Dynamic Imports

Vite uses rollup under the hood which supports dynamic imports just like webpack and other bundlers but it has a small flaw. Well, not so much a flaw but rather a consideration that was never put to thought simply because of how AEM ClientLibs work.

The import rewriter takes the ES module import paths and converts them into AEM friendly paths automatically.

Vite Plugin

AEM Vite provides a plugin that will rewrite dynamic import paths to your /etc.clientlibs proxy path.

npm install --save-dev @aem-vite/import-rewriter
# or; yarn
yarn add -D @aem-vite/import-rewriter

Configuration

Getting this plugin configured is really simple, all it requires is your ClientLib public path.

 




 
 
 
 



import { bundlesImportRewriter } from '@aem-vite/import-rewriter';

export default defineConfig(() => ({
  plugins: [
    // ... all other plugins
    bundlesImportRewriter({
      publicPath: '/etc.clientlibs/<project>/clientlibs/clientlib-site',
      resourcesPath: 'resources/js',
    }),
  ],
}));

Plugin options

Property NameTypeRequired
caching
Instruct import rewriter how to handle AEM caching.
objectNo
publicPath
The AEM proxy path to your ClientLib directory.
stringYes
resourcesPath
The folder where Vite generated JavaScript resources.
stringYes

Caching options

Property NameTypeRequiredDefault
enabled
Should caching support be utilised during builds?
booleanYes-
keyFormat
Long term cache key format.
stringNolc-%s-lc
minification
Should .min be added to the import path?
booleanNofalse

How This Works?

Under the hood es-module-lexer is used to parse the rollup chunk source and identifies all of the import statements. Once identified, they are parsed and all instances that use path patterns such as ./ or ../ will get replaced with publicPath configured in your plugin configuration.

By rewriting the imports we solve another issue and that is we prevent Vite adding duplicate imports via its dynamic import polyfill transformer.

Circular imports

In addition to handling import paths, the main entry path is also rewritten to the correct AEM ClientLib path to ensure ES module imports behave correctly in AEM.

Caching and Minification

So your code doesn't use the wrong path when in a testing, staging or production environment, it is good practice to dynamically switch on minification for AEM Vite using an environment variable via your Maven pom.xml file.

The below showcases this using Adobe Cloud Manager as an example by looking for a CM_BUILD environment variable and setting a Maven property called aem.caching. This Maven property can then be passed onto frontend-maven-plugin which can subsequently be passed onto your Vite configuration.

A note about the <arguments> property

This property assumes you already have an npm script called build in your package.json file.

<properties>
  <aem.caching>false</aem.caching>
</properties>

<build>
  <plugins>
    <plugin>
      <groupId>com.github.eirslett</groupId>
      <artifactId>frontend-maven-plugin</artifactId>

      <executions>
        <execution>
          <id>build-fed</id>
          <phase>initialize</phase>
          <goals>
            <goal>yarn</goal>
          </goals>
          <configuration>
            <arguments>build --config ./path/to/vite.config.js</arguments>
            <environmentVariables>
              <AEM_CACHING>${aem.caching}</AEM_CACHING>
            </environmentVariables>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

<profiles>
  <profile>
    <id>cmBuild</id>
    <activation>
      <property>
        <name>env.CM_BUILD</name>
      </property>
    </activation>
    <properties>
      <aem.caching>true</aem.caching>
    </properties>
  </profile>
</profiles>

Setting the Vite configuration

From there, you can update your Vite configuration to look for AEM_CACHING and then enable caching and minification. An assumption is made that caching and minification are both enabled, if you need separation, add another Maven profile to set another property/environment variable.



 








 
 
 
 




import { bundlesImportRewriter } from '@aem-vite/import-rewriter';

const needsCaching = process.env.AEM_CACHING === 'true';

export default defineConfig(({ command, mode }) => ({
  plugins: [
    // ... all other plugins before, 'bundlesImportRewriter' must be last
    bundlesImportRewriter({
      publicPath: '/etc.clientlibs/<project>/clientlibs/clientlib-site',
      resourcesPath: 'resources/js',

      caching: {
        enabled: command === 'build' && mode === 'production' && needsCaching,
        minification: needsCaching,
      },
    }),
  ],
}));