For my current tinkering project I'm using EJS with hapi. Up until now I've been writing front-end code with Vue (or occasionally Svelte) with an Express back-end, so this is a change for me. There are downsides but definite upsides - I'll try and write about those another time.

In the meantime, one difference I found is how they handle optional values. In the case of (for example) Vue a v-if handles both undefined and "falsy" values.

<router-link v-if="!loggedIn" to="/register">Register | </router-link>

But that doesn't work for EJS - the equivalent template throws an error:

<% if (message) { %>
  <h3><%= message %></h3>
<% } %>
ReferenceError: ejs:1
 >> 1| <% if (message) { %>
    2| <h3>Message: <%= message %></h3>
    3| <% } %>

message is not defined

Instead, what you need to do is check for locals.message:

<% if (locals.message) { %>
  <h3><%= locals.message %></h3>
<% } %>

and all is well, both with no value and with a value:

$ npx ejs ./test.ejs

$ npx ejs ./test.ejs message="Hello world"
<h3>Message: Hello world</h3>