Client libraries and front-end workflow client-side-libraries

Learn how Client-Side Libraries or clientlibs are used to deploy and manage CSS and JavaScript for an Adobe Experience Manager (AEM) Sites implementation. This tutorial also covers how the ui.frontend module, a de-coupled webpack project, can be integrated into the end-to-end build process.

Prerequisites prerequisites

Review the required tooling and instructions for setting up a local development environment.

It is also recommended to review the Component Basics tutorial to understand the fundamentals of client-side libraries and AEM.

Starter Project

If you successfully completed the previous chapter, you can reuse the project and skip the steps for checking out the starter project.

Check out the base-line code that the tutorial builds on:

  1. Check out the tutorial/client-side-libraries-start branch from GitHub

    code language-shell
    $ cd aem-guides-wknd
    $ git checkout tutorial/client-side-libraries-start
  2. Deploy code base to a local AEM instance using your Maven skills:

    code language-shell
    $ mvn clean install -PautoInstallSinglePackage
    note note
    If using AEM 6.5 or 6.4, append the classic profile to any Maven commands.
    code language-shell
    $ mvn clean install -PautoInstallSinglePackage -Pclassic

You can always view the finished code on GitHub or check out the code locally by switching to the branch tutorial/client-side-libraries-solution.


  1. Understand how client-side libraries are included onto a page via an editable template.
  2. Learn how to use the ui.frontend module and a webpack development server for dedicated front-end development.
  3. Understand the end-to-end workflow of delivering compiled CSS and JavaScript to a Sites implementation.

What you are going to build what-build

In this chapter, you add some baseline styles for the WKND site and the Article Page Template to bring the implementation closer to the UI design mockups. You use an advanced front-end workflow to integrate a webpack project into an AEM client library.

Finished Styles

Article Page with baseline styles applied

Background background

Client-Side Libraries provide a mechanism to organize and manage CSS and JavaScript files necessary for an AEM Sites implementation. The basic goals for client-side libraries or clientlibs are:

  1. Store CSS/JS in small discrete files for easier development and maintenance
  2. Manage dependencies on third-party frameworks in an organized fashion
  3. Minimize the number of client-side requests by concatenating CSS/JS into one or two requests.

More information about using Client-Side Libraries can be found here.

Client-side libraries do have some limitations. Most notably is a limited support for popular front-end languages like Sass, LESS, and TypeScript. In the tutorial, let’s look at how the ui.frontend module can help solve this.

Deploy the starter code base to a local AEM instance and navigate to http://localhost:4502/editor.html/content/wknd/us/en/magazine/guide-la-skateparks.html. This page is unstyled. Let’s implement Client-side libraries for the WKND brand to add CSS and JavaScript to the page.

Client-Side Libraries Organization organization

Next let’s explore the organization of clientlibs generated by the AEM Project Archetype.

High level clientlibrary organization

High-level diagram Client-side Library organization and page inclusion

The following client-side library organization is generated by AEM Project Archetype but represents merely a starting point. How a project ultimately manages and delivers CSS and JavaScript to a Sites implementation can vary dramatically based on resources, skill sets and requirements.
  1. Using VSCode or other IDE open up the ui.apps module.

  2. Expand the path /apps/wknd/clientlibs to view the clientlibs generated by the archetype.

    Clientlibs in ui.apps

    In the below section, these clientlibs are reviewed in greater details.

  3. The following table summarizes the client libraries. More details about including Client Libraries can be found here.

    table 0-row-3 1-row-3 2-row-3 3-row-3 4-row-3
    Name Description Notes
    clientlib-base Base level of CSS and JavaScript needed for WKND Site to function embeds Core Component client libs
    clientlib-grid Generates the CSS necessary for Layout Mode to work. Mobile/Tablet breakpoints can be configured here
    clientlib-site Contains site-specific theme for the WKND Site Generated by the ui.frontend module
    clientlib-dependencies Embeds any third-party dependencies Generated by the ui.frontend module
  4. Observe that clientlib-site and clientlib-dependencies are ignored from source control. This is by design, since these are generated at build time by the ui.frontend module.

Update base styles base-styles

Next, update the base styles defined in the ui.frontend module. The files in the ui.frontend module generate the clientlib-site and clientlib-dependecies libraries that contain the Site theme and any third-party dependencies.

Client-side libraries do not support more advanced languages like Sass or TypeScript. There are several open-source tools like NPM and webpack that accelerate and optimize front-end development. The goal of the ui.frontend module is to be able to use these tools to manage most front-end source files.

  1. Open up the ui.frontend module and navigate to src/main/webpack/site.

  2. Open the file main.scss

    main.scss - entrypoint

    main.scss is the entry point to the Sass files in the ui.frontend module. It includes the _variables.scss file, which contains a series of brand variables to be used throughout different Sass files in the project. The _base.scss file is also included and defines some basic styles for HTML elements. A regular expression includes the styles for individual components styles under src/main/webpack/components. Another regular expression includes the files under src/main/webpack/site/styles.

  3. Inspect the file main.ts. It includes main.scss and a regular expression to collect any .js or .ts files in the project. This entry point is used by the webpack configuration files as the entry point for the entire ui.frontend module.

  4. Inspect the files beneath src/main/webpack/site/styles:

    Style Files

    These files styles for global elements in the template, like the Header, Footer and main content container. The CSS rules in these files target different HTML elements header, main, and footer. These HTML elements were defined by policies in the previous chapter Pages and Templates.

  5. Expand the components folder under src/main/webpack and inspect the files.

    Component Sass files

    Each file maps to a Core Component like the Accordion Component. Each Core Component is built with Block Element Modifier or BEM notation to make it easier to target specific CSS classes with style rules. The files beneath /components have been stubbed out by the AEM Project Archetype with the different BEM rules for each component.

  6. Download the WKND Base Styles and unzip the file.

    WKND Base Styles

    To accelerate the tutorial, several Sass files that implement the WKND brand based on Core Components and the structure of the Article Page Template is provided.

  7. Overwrite the contents of ui.frontend/src with files from the previous step. The contents of the zip should overwrite the following folders:

    code language-plain

    Changed files

    Inspect the changed files to see details of the WKND style implementation.

Inspect the ui.frontend integration ui-frontend-integration

A key integration piece built into the ui.frontend module, aem-clientlib-generator takes the compiled CSS and JS artifacts from a webpack/npm project and transforms them into AEM client-side libraries.

ui.frontend architecture integration

The AEM Project Archetype automatically sets up this integration. Next, explore how it works.

  1. Open a command-line terminal and install the ui.frontend module using the npm install command:

    code language-shell
    $ cd ~/code/aem-guides-wknd/ui.frontend
    $ npm install
    note note
    npm install run is needed only once, like after a new clone or generation of the project.
  2. Open ui.frontend/package.json and in the scripts start command add --env writeToDisk=true.

    code language-json
      "scripts": {
        "start": "webpack-dev-server --open --config ./ --env writeToDisk=true",
  3. Start the webpack dev server in watch mode by running the following command:

    code language-shell
    $ npm run watch
  4. This compiles the source files from the ui.frontend module and syncs the changes with AEM at http://localhost:4502

    code language-shell
    + jcr_root/apps/wknd/clientlibs/clientlib-site/js/site.js
    + jcr_root/apps/wknd/clientlibs/clientlib-site/js
    + jcr_root/apps/wknd/clientlibs/clientlib-site
    + jcr_root/apps/wknd/clientlibs/clientlib-dependencies/css.txt
    + jcr_root/apps/wknd/clientlibs/clientlib-dependencies/js.txt
    + jcr_root/apps/wknd/clientlibs/clientlib-dependencies
    http://admin:admin@localhost:4502 > OK
    + jcr_root/apps/wknd/clientlibs/clientlib-site/css
    + jcr_root/apps/wknd/clientlibs/clientlib-site/js/site.js
    http://admin:admin@localhost:4502 > OK
  5. The command npm run watch ultimately populates the clientlib-site and clientlib-dependencies in the ui.apps module which is then synced automatically with AEM.

    note note
    There is also a npm run prod profile which minifies the JS and CSS. This is the standard compilation whenever the webpack build is triggered via Maven. More details about the ui.frontend module can be found here.
  6. Inspect the file site.css beneath ui.frontend/dist/clientlib-site/site.css. This is the compiled CSS based on the Sass source files.

    Distributed Site css

  7. Inspect the file ui.frontend/clientlib.config.js. This is the configuration file for an npm plugin, aem-clientlib-generator that transforms the contents of /dist into a client library and moves it to the ui.apps module.

  8. Inspect the file site.css in the ui.apps module at ui.apps/src/main/content/jcr_root/apps/wknd/clientlibs/clientlib-site/css/site.css. This should be an identical copy of the site.css file from the ui.frontend module. Now that it is in ui.apps module it can be deployed to AEM.

    ui.apps clientlib-site

    note note
    Since clientlib-site is compiled during build time, using either npm, or maven, it can be safely ignored from source control in the ui.apps module. Inspect the .gitignore file beneath ui.apps.
  9. Open the LA Skatepark article in AEM at: http://localhost:4502/editor.html/content/wknd/us/en/magazine/guide-la-skateparks.html.

    Updated Base Styles for the Article

    You should now see the updated styles for the article. You may need to do a hard refresh to clear any CSS files cached by the browser.

    It’s starting to look a lot closer to the mockups!

    note note
    The steps performed above to build and deploy the ui.frontend code to AEM is executed automatically when a Maven build is triggered from the root of the project mvn clean install -PautoInstallSinglePackage.

Make a style change

Next, make a small change in the ui.frontend module to see the npm run watch automatically deploy the styles to the local AEM instance.

  1. From, the ui.frontend module open the file: ui.frontend/src/main/webpack/site/_variables.scss.

  2. Update the $brand-primary color variable:

    code language-scsss
    //== variables.css
    //== Brand Colors
    $brand-primary:          $pink;

    Save the changes.

  3. Return to the browser and refresh the AEM page to see the updates:

    Client Side Libraries

  4. Revert the change to the $brand-primary color and stop the webpack build using the command CTRL+C.

The use of the ui.frontend module may not be necessary for all projects. The ui.frontend module adds additional complexity and if there is not a need/desire to use some of these advanced front-end tools (Sass, webpack, npm…) it may not be needed.

Page and Template Inclusion page-inclusion

Next, let’s review how the clientlibs are referenced in the AEM Page. A common best practice in web development is to include CSS in the HTML Header <head> and JavaScript right before closing </body> tag.

  1. Browse to the Article Page template at http://localhost:4502/editor.html/conf/wknd/settings/wcm/templates/article-page/structure.html

  2. Click the Page Information icon and in the menu select Page Policy to open the Page Policy dialog.

    Article Page Template Menu Page Policy

    Page Information > Page Policy

  3. Notice that the categories for wknd.dependencies and are listed here. By default clientlibs configured via the Page Policy are split to include the CSS in the page head and the JavaScript at the body end. You can explicitly list the clientlib JavaScript be loaded in the Page head. This is the case for wknd.dependencies.

    Article Page Template Menu Page Policy

    note note
    It is also possible to reference the or wknd.dependencies from the page component directly, using the customheaderlibs.html or customfooterlibs.html script. Using the Template gives flexibility in that you can pick and choose which clientlibs are used per template. For example, if you have a heavy JavaScript library that is only going to be used on a select template.
  4. Navigate to the LA Skateparks page created using the Article Page Template: http://localhost:4502/editor.html/content/wknd/us/en/magazine/guide-la-skateparks.html.

  5. Click the Page Information icon and in the menu select View As Published to open the article page outside of the AEM Editor.

    View as Published

  6. View the Page source of http://localhost:4502/content/wknd/us/en/magazine/guide-la-skateparks.html?wcmmode=disabled and you should be able to see the following clientlib references in the <head>:

    code language-html
    <script src="/etc.clientlibs/wknd/clientlibs/"></script>
    <link rel="stylesheet" href="/etc.clientlibs/wknd/clientlibs/" type="text/css">
    <link rel="stylesheet" href="/etc.clientlibs/wknd/clientlibs/" type="text/css">

    Notice that the clientlibs are using the proxy /etc.clientlibs endpoint. You should also see that the following clientlib includes at the bottom of the page:

    code language-html
    <script src="/etc.clientlibs/wknd/clientlibs/"></script>
    <script src="/etc.clientlibs/wknd/clientlibs/"></script>
    note note
    For AEM 6.5/6.4 the client-side libraries are not automatically minified. See the documentation on the HTML Library Manager to enable minification (recommended).
    note warning
    It is critical on the publish side that the client libraries are not served from /apps as this path should be restricted for security reasons using the Dispatcher filter section. The allowProxy property of the client library ensures the CSS and JS are served from /etc.clientlibs.

Next Steps next-steps

Learn how to implement individual styles and reuse Core Components using Experience Manager’s Style System. Developing with the Style System covers using the Style System to extend Core Components with brand-specific CSS and advanced policy configurations of the Template Editor.

View the finished code on GitHub or review and deploy the code locally at on the Git branch tutorial/client-side-libraries-solution.

  1. Clone the repository.
  2. Check out the tutorial/client-side-libraries-solution branch.

Additional Tools and Resources additional-resources

Webpack DevServer - Static Markup webpack-dev-static

In the previous couple of exercises several Sass files in the ui.frontend module were updated and through a build process, ultimately see that these changes reflected in AEM. Next let’s look at a technique that uses a webpack-dev-server to rapidly develop the front-end styles against static HTML.

This technique is handy if most the styles and front-end code is performed by a dedicated Front-End developer who may not have easy access to an AEM environment. This technique also allows the FED to make modifications directly to the HTML, which can then be handed off to an AEM developer to implement as components.

  1. Copy the page source of the LA skatepark article page at http://localhost:4502/content/wknd/us/en/magazine/guide-la-skateparks.html?wcmmode=disabled.

  2. Reopen your IDE. Paste the copied markup from AEM into the index.html in the ui.frontend module beneath src/main/webpack/static.

  3. Edit the copied markup and remove any references to clientlib-site and clientlib-dependencies:

    code language-html
    <!-- remove -->
    <script type="text/javascript" src="/etc.clientlibs/wknd/clientlibs/clientlib-dependencies.js"></script>
    <link rel="stylesheet" href="/etc.clientlibs/wknd/clientlibs/clientlib-dependencies.css" type="text/css">
    <link rel="stylesheet" href="/etc.clientlibs/wknd/clientlibs/clientlib-site.css" type="text/css">
    <script type="text/javascript" src="/etc.clientlibs/wknd/clientlibs/clientlib-site.js"></script>

    Remove these references because the webpack dev server generates these artifacts automatically.

  4. Start the webpack dev server from a new terminal by running the following command from within the ui.frontend module:

    code language-shell
    $ cd ~/code/aem-guides-wknd/ui.frontend/
    $ npm start
    > aem-maven-archetype@1.0.0 start code/aem-guides-wknd/ui.frontend
    > webpack-dev-server --open --config ./
  5. This should open a new browser window at http://localhost:8080/ with static markup.

  6. Edit the file src/main/webpack/site/_variables.scss file. Replace the $text-color rule with the following:

    code language-diff
    - $text-color:              $black;
    + $text-color:              $pink;

    Save the changes.

  7. You should automatically see the changes automatically reflected in the browser on http://localhost:8080.

    Local webpack dev server changes

  8. Review the /aem-guides-wknd.ui.frontend/ file. This contains the webpack configuration used to start the webpack-dev-server. It proxies the paths /content and /etc.clientlibs from a locally running instance of AEM. This is how the images, and other clientlibs (not managed by the ui.frontend code) are made available.

    note caution
    The image src of the static markup points to a live image component on a local AEM instance. Images appear broken if the path to the image changes, if AEM is not started, or if the browser has not logged into the local AEM instance. If handing off to an external resource, it’s also possible to replace the images with static references.
  9. You can stop the webpack server from the command line by typing CTRL+C.

aemfed develop-aemfed

aemfed is an open-source, command-line tool that can be used to speed up front-end development. It is powered by aemsync, Browsersync, and Sling Log Tracer.

At a high level, the aemfedis designed to listen to file changes within the ui.apps module and automatically sync them directly to a running AEM instance. Based on the changes, a local browser automatically refreshes, thus speeding up front-end development. It is also built to work with Sling Log tracer to automatically display any server-side errors directly in the terminal.

If you are doing much work within the ui.apps module, modifying HTL scripts, and creating custom components, aemfed can be a powerful tool to use. Full documentation can be found here.

Debugging Client-side Libraries debugging-clientlibs

Using different methods of categories and embeds to include multiple client libraries it can be cumbersome to troubleshoot. AEM exposes several tools to help with this. One of the most important tools is Rebuild Client Libraries which forces AEM to recompile any LESS files and generate the CSS.

  • Dump Libs - Lists the client libraries registered in the AEM instance. <host>/libs/granite/ui/content/dumplibs.html

  • Test Output - allows a user to see the expected HTML output of clientlib includes based on category. <host>/libs/granite/ui/content/dumplibs.test.html

  • Libraries Dependencies validation - highlights any dependencies or embedded categories that cannot be found. <host>/libs/granite/ui/content/dumplibs.validate.html

  • Rebuild Client Libraries - allows a user to force AEM to rebuild the client libraries or invalidate the cache of client libraries. This tool is effective when developing with LESS as this can force AEM to recompile the generated CSS. In general, it is more effective to Invalidate Caches and then perform a page refresh versus rebuilding the libraries. <host>/libs/granite/ui/content/dumplibs.rebuild.html

rebuild client library