Photo by Tim Gouw: https://www.pexels.com/photo/four-paintings-on-wall-139764/

The Re-evolution of Web Development: From Client-Side Components to Server-Side Templating with EJS and HTMX

Paul Allies

--

Web development is a constantly evolving field, and as technology advances, so do our approaches to building web applications. In recent years, the trend has shifted towards building more components on the client side, leveraging frameworks like React, Angular, or Vue.js. However, as we look to develop more server-side components and explore the use of technologies like HTMX, there’s a resurgence of interest in server-side templating languages like EJS, Handlebars, Nunjucks. In this blog, we’ll discuss how this shift is happening and how EJS, HTMX, and server-side templating can complement each other.

The Client-Side Component Trend

Before the era of React, web applications predominantly relied on server-side templating languages like EJS, where the server was responsible for generating HTML pages containing integrated dynamic content. This methodology was well-suited for conventional websites.

However, with the rise of single-page applications (SPAs) and client-side frameworks, the focus shifted towards building complex UI components on the client side. This approach offered benefits like faster user interactions and a more responsive user experience. Developers embraced tools like React, Angular, and Vue.js to build these dynamic client-side components.

The Role of HTMX

HTMX is a relatively new library that aims to bridge the gap between server-side and client-side development. It allows you to make partial page updates by requesting HTML content from the server and injecting it into the DOM, all while maintaining the benefits of client-side interactivity.

This approach is particularly useful when you want to enhance a traditional server-rendered application with dynamic features without fully transitioning to a client-side SPA architecture. HTMX enables you to fetch and replace parts of the page, achieving smoother user experiences while retaining server-side rendering.

The Return of Server-Side Templating with EJS

As we explore the capabilities of HTMX and look to develop more server-side components, the use of server-side templating languages like EJS is making a comeback. Here’s how EJS fits into this evolving landscape:

1. Server-Side Templating: EJS excels at server-side templating, making it easy to generate dynamic HTML on the server. You can use EJS to create reusable templates for your server-rendered components.

2. Combining with HTMX: HTMX can be seamlessly integrated with EJS. You can use EJS to render the initial page on the server and HTMX to fetch and inject dynamic components when needed, creating a hybrid approach that combines the best of both server and client-side rendering.

<! — Example: Using EJS with HTMX →
<div id=”dynamic-content” hx-get=”/load-dynamic-content”>
<! — HTMX will replace this content with server-rendered HTML →
<%- include(‘server-rendered-component’) %>
</div>

3. Performance and SEO: Server-side rendering with EJS ensures that your content is visible to search engines and provides a fast initial page load, enhancing SEO and user experience.

Utilising EJS for Clean and Structured HTML Integration

When using EJS for server-side rendering, it’s essential to follow best practices for clean and structured HTML integration. Here are some key guidelines:

1. Use Delimiters Effectively

EJS provides delimiters like `<% … %>`, `<%= … %>`, and `<%- … %>` to embed JavaScript code. Utilise them effectively to separate logic from presentation. For example, use `<% … %>` for control flow and loops and `<%= … %>` for outputting dynamic content. This separation makes your templates more readable and maintainable.


<ul>
<% for (let item of items) { %>
<li><%= item.name %></li>
<% } %>
</ul>

You can use the `<% … %>` delimiter to include conditional logic using `if` statements within your EJS templates. For example, conditionally displaying content based on a variable:


<% if (loggedIn) { %>
<p>Welcome, <%= username %>!</p>
<% } else { %>
<p>Please log in to access your account.</p>
<% } %>

Similarly, you can use the `<% … %>` delimiter to include `switch` statements for more complex conditional logic. Here’s an example of displaying different messages based on a variable:


<% switch (userRole) {
case 'admin': %>
<p>You have admin privileges.</p>
<% break
case 'user': %>
<p>Welcome, regular user!</p>
<% break
default: %>
<p>Your role is not recognized.</p>
<% } %>

These examples demonstrate how to effectively use the `<% … %>` delimiter to incorporate `if` and `switch` statements within your EJS templates, allowing you to create dynamic and conditionally-rendered content based on your application’s logic.

2. Create Reusable Partial Templates

To avoid code duplication and improve maintainability, create reusable partial templates for common HTML elements or components. EJS allows you to include these partials in your main templates using the

<%- include(‘partial-name’) %> 

syntax.

For example, if you have a header and footer that appear on multiple pages, create partials for them:


<! — header.ejs →
<header>
<h1>My Website</h1>
</header>

<! — footer.ejs →
<footer>
<p>&copy; 2024 My Website</p>
</footer>

Then, include these partials in your main templates:


<%- include(‘header’) %>
<main>
<! — Your page content here →
</main>
<%- include(‘footer’) %>

Sometimes, you may need to pass data or parameters to your partials. This can be achieved by including the parameters when you render the partial.

<!-- main-template.ejs -->
<main>
<%- include('partials/product-list', { products: productList }) %>
</main>

By passing parameters to your partials, you can make them more dynamic and versatile, allowing you to reuse them in various contexts with different data.

3. Maintain a Logical Folder Structure

Organise your EJS templates in a logical folder structure. Group related templates in directories and use meaningful names for your template files. This makes it easier to find and manage your templates as your project grows.

For example, you can have a structure like this:


views/
├── pages/
│ ├── home.ejs
│ ├── about.ejs
│ └── contact.ejs
├── partials/
│ ├── header.ejs
│ └── footer.ejs
└── layout.ejs
```

4. Use Helper Functions

EJS allows you to define and use helper functions to encapsulate complex logic and make your templates cleaner.

// app.js

app.locals.formatDate = function (date) {
return new Intl.DateTimeFormat("en-US").format(date);
};
<p>Today's date: <%= formatDate(new Date()) %></p>

By using helper functions, you keep your EJS templates focused on presentation while encapsulating complex logic in separate JavaScript files, promoting cleaner and more maintainable code.

5. Utilise EJS Comments

EJS also supports comments using `<%# … %>` syntax. Use comments to provide explanations for complex or non-obvious parts of your templates. This documentation can be invaluable for you and other developers working on the project.


<%# This section generates the product list %>
<ul>
<% for (let product of products) { %>
<li>
<%= product.name %>
</li>
<% } %>
</ul>

Writing EJS templates in a clean and structured way without interfering with HTML is crucial for the maintainability of your web applications. By using delimiters effectively, creating reusable partials, maintaining a logical folder structure, incorporating helper functions, passing parameters to partials, and utilising comments, you can ensure that your EJS templates remain organised and easy to work with, even as your projects become more complex.

Conclusion

The web development landscape continues to evolve, and the pendulum often swings between client-side and server-side approaches. While client-side components have dominated recent trends, technologies like HTMX are bringing back the importance of server-side rendering and server-side templating languages like EJS.

By leveraging EJS for server-side rendering and combining it with HTMX for client-side interactivity, you can create web applications that offer the best of both worlds: the performance and SEO benefits of server-side rendering and the dynamic, interactive user experiences

--

--