AEM & Vite integration - Part 1

2021-11-07

Vite?

The amount of JavaScript we are dealing with increased exponentially. It is not uncommon for large scale projects to contain thousands of modules. We are starting to hit a performance bottleneck for JavaScript based tooling: it can often take an unreasonably long wait (sometimes up to minutes!) to spin up a dev server, and even with HMR, file edits can take a couple seconds to be reflected in the browser. The slow feedback loop can greatly affect developers' productivity and happiness.

Vite aims to address these issues by leveraging new advancements in the ecosystem: the availability of native ES modules in the browser, and the rise of JavaScript tools written in compile-to-native languages.

- https://vitejs.dev/guide/why.html#the-problems

If you want more information on how Vite works, don't hesitate to look into the docs, everything is well explained over there.

AEM & Vite development integration

Part 1 of the this series will focus on the development flow and part 2 will focus on the production flow and will follow shortly.

The Vite documentation has a section specifically for backend integrations, it's that information that I used as a starting point. Inside your FE module of your AEM project you should add the following scripts to the package.json, for now we will only focus on the dev command.

1
2
3
4
5
6
7
{
  "scripts": {
    "dev": "vite", // start dev server
    "build": "vite build", // build for production
    "preview": "vite preview" // locally preview production build
  }
}

When running Vite from the command line, Vite will automatically try to resolve a config file named vite.config.js inside project root.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  server: {
    port: 3000,
    strictPort: true,
  },
  build: {
      input: {
        app: 'src/main.ts',
      },
    },
  },
  plugins: [vue()],
});

The important part here are the port and the entry file as both will be referenced in the script tags outputted to your HTML:

1
2
<script type="module" src="http://localhost:3000/@vite/client"></script>
<script type="module" src="http://localhost:3000/main.js"></script>

Introducing ES Module Client Libraries

In order to output the tags shown above I had to come up with a mechanism to link AEM with Vite, I found a solution using AEM clientlibs. I've added an option in the page policy of my template to list ES Module enabled clientlibs.

1
2
3
<sly data-sly-use.clientlibs="${'be.jeroendruwe.core.models.ModuleClientLibraries' @ categories=page.ESModuleClientlibCategories}">
    ${clientlibs.getIncludes @ context="unsafe"}
</sly>

The clientlibs are passed to a custom Sling model that does the following (slimmed down version)

  1. Fetches all clientlibs based on the categories that were passed to the Sling model.
  2. Check if the viteDevServerEnabled property inside the be.jeroendruwe.core.internal.services.ViteClientLibServiceImpl.cfg.json config file is enabled. This allows me to only enable the Vite development mode on my local machine using AEM run modes.
  3. Resolves a dev server configuration file based on the categories of the clientlib
  4. Build script tags using the protocol, hostname, port and Vite entry provided by the dev server config.

A config (be.jeroendruwe.core.internal.services.ViteDevServerConfigImpl-esmodule.cfg.json) looks like this:

1
2
3
4
5
6
7
{
  "protocol": "http",
  "hostname": "localhost",
  "port": "3000",
  "entry": "src/main.ts",
  "category": "aem-vite-demo.esmodule"
}

Demo project

I've created a demo project based on the AEM archetype, you can look into the repository to see the full code and try it out yourself. Here is a small demonstration on how a multi clientlib setup using Vite looks like:

The output to the document looks like this:

1
2
3
4
<script type="module" src="http://localhost:3000/@vite/client"></script>
<script type="module" src="http://localhost:3000/src/main.ts"></script>
<script type="module" src="http://localhost:3001/@vite/client"></script>
<script type="module" src="http://localhost:3001/src/another.ts"></script>

As you can see Vite enables tremendous development speed gains in AEM projects were frontend changes used to take a lot more time! Keep a look at my blog as I'll try to write up part 2 as soon as possible. Do not hesitate to contact me or leave a comment below.

Created by Jeroen Druwé