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 will also cover how the ui.frontend module, a de-coupled webpack project, can be integrated into the end-to-end build process.
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.
If you successfully completed the previous chapter you can re-use the project and skip the steps for checking out the starter project.
Check out the base-line code the tutorial builds on:
Check out the tutorial/client-side-libraries-start
branch from GitHub
$ cd aem-guides-wknd
$ git checkout tutorial/client-side-libraries-start
Deploy code base to a local AEM instance using your Maven skills:
$ mvn clean install -PautoInstallSinglePackage
If using AEM 6.5 or 6.4, append the classic
profile to any Maven commands.
$ mvn clean install -PautoInstallSinglePackage -Pclassic
You can always view the finished code on GitHub or check the code out locally by switching to the branch tutorial/client-side-libraries-solution
.
In this chapter you will add some baseline styles for the WKND site and the Article Page Template in an effort to bring the implementation closer to the UI design mockups. You will use an advanced front-end workflow to integrate a webpack project into an AEM client library.
Article Page with baseline styles applied
Client-Side Libraries provides 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:
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 we will 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 currently un-styled. We will next implement Client-side libraries for the WKND brand to add CSS and Javascript to the page.
Next we will explore the organization of clientlibs generated by the AEM Project Archetype.
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, skillsets and requirements.
Using VSCode or other IDE open up the ui.apps module.
Expand the path /apps/wknd/clientlibs
to view the clientlibs generated by the archetype.
We will inspect these clientlibs in greater detail below.
The following table summarizes the client libraries. More details about including Client Libraries can be found here.
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 3rd party dependencies | Generated by the ui.frontend module |
Observe that clientlib-site
and clientlib-dependencies
are ignored from source control. This is by design, since these will be generated at build time by the ui.frontend
module.
Next, update the base styles defined in the ui.frontend module. The files in the ui.frontend
module will generate the clientlib-site
and clientlib-dependecies
libraries that contain the Site theme and any 3rd party dependencies.
Client-side libraries have some limitations when it comes to support of languages like Sass or TypeScript. There are a number of 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 a majority of front-end source files.
Open up the ui.frontend module and navigate to src/main/webpack/site
.
Open the file main.scss
client-side-libraries/main-scss
main.scss
is the entry point to all of the Sass files in the ui.frontend
module. It will include 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 all of the styles for individual components styles under src/main/webpack/components
. Another regular expression includes all of the files under src/main/webpack/site/styles
.
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 will be used by the webpack configuration files as the entry point for the entire ui.frontend
module.
Inspect the files beneath src/main/webpack/site/styles
:
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.
Expand the components
folder under src/main/webpack
and inspect the 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.
Download the WKND Base Styles wknd-base-styles-src-v3.zip and unzip the file.
To accelerate the tutorial, we have provided the several Sass files that implement the WKND brand based on Core Components and the structure of the Article Page Template.
Overwrite the contents of ui.frontend/src
with files from the previous step. The contents of the zip should overwrite the following folders:
/src/main/webpack
/components
/resources
/site
/static
Inspect the changed files to see details of the WKND style implementation.
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.
The AEM Project Archetype automatically sets up this integration. Next, explore how it works.
Open a command line terminal and install the ui.frontend module using the npm install
command:
$ cd ~/code/aem-guides-wknd/ui.frontend
$ npm install
npm install
only needs to be run once, following a new clone or generation of the project.
Start the webpack dev server in watch mode by running the following command:
$ npm run watch
This will compile the src
files in the ui.frontend
module and sync the changes with AEM at http://localhost:4502
+ 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
The command npm run watch
ultimately populates the clientlib-site and clientlib-dependencies in the ui.apps module wich is then synced automatically with AEM.
There is also a npm run prod
profile which will minify 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.
Inspect the file site.css
beneath ui.frontend/dist/clientlib-site/site.css
. This is the compiled CSS based on the Sass source files.
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.
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.
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.
Open the LA Skatepark article in AEM at: http://localhost:4502/editor.html/content/wknd/us/en/magazine/guide-la-skateparks.html.
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!
The steps performed above to build and deploy the ui.frontend code to AEM will be executed automatically when a Maven build is triggered from the root of the project mvn clean install -PautoInstallSinglePackage
.
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.
In the ui.frontend
module open the file: ui.frontend/src/main/webpack/site/_variables.scss
.
Update the $brand-primary
color variable:
//== variables.css
//== Brand Colors
$brand-primary: $pink;
Save the changes.
Return to the browser and refresh the AEM page to see the updates:
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.
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.
Browse to the Article Page template at http://localhost:4502/editor.html/conf/wknd/settings/wcm/templates/article-page/structure.html
Click the Page Information icon and in the menu select Page Policy to open the Page Policy dialog.
Page Information > Page Policy
Notice that the categories for wknd.dependencies
and wknd.site
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. If desired you can explicitly list that the clientlib JavaScript be loaded in the Page head. This is the case for wknd.dependencies
.
It is also possible to reference the wknd.site
or wknd.dependencies
from the page component directly, using the customheaderlibs.html
or customfooterlibs.html
script, as we saw eaerlier for the wknd.base
clientlib. Using the Template gives some flexibility in that you can pick and choose which clientlibs are used per template. For example if you have a very heavy JavaScript library that is only going to be used on a select template.
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.
Click the Page Information icon and in the menu select View As Published to open the article page outside of the AEM editor.
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>
:
<head>
...
<script src="/etc.clientlibs/wknd/clientlibs/clientlib-dependencies.lc-d41d8cd98f00b204e9800998ecf8427e-lc.min.js"></script>
<link rel="stylesheet" href="/etc.clientlibs/wknd/clientlibs/clientlib-dependencies.lc-d41d8cd98f00b204e9800998ecf8427e-lc.min.css" type="text/css">
<link rel="stylesheet" href="/etc.clientlibs/wknd/clientlibs/clientlib-site.lc-78fb9cea4c3a2cc17edce2c2b32631e2-lc.min.css" type="text/css">
...
</head>
Notice that the clientlibs are using the proxy /etc.clientlibs
endpoint. You should also see the following clientlib includes at the bottom of the page:
...
<script src="/etc.clientlibs/wknd/clientlibs/clientlib-site.lc-7157cf8cb32ed66d50e4e49cdc50780a-lc.min.js"></script>
<script src="/etc.clientlibs/wknd/clientlibs/clientlib-base.lc-53e6f96eb92561a1bdcc1cb196e9d9ca-lc.min.js"></script>
...
</body>
If following on 6.5/6.4 the client side libraries will not be automatically minified. See the documentation on the HTML Library Manager to enable minfication (recommended).
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.
Learn how to implement individual styles and re-use 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 brach tutorial/client-side-libraries-solution
.
tutorial/client-side-libraries-solution
branch.In the previous couple of exercises we were able to update several Sass files in the ui.frontend module and through a build process, ultimately see these changes reflected in AEM. Next we will look at a techniques that leverage a webpack-dev-server to rapidly develop our front-end styles against static HTML.
This technique is handy if the majority of the styles and front-end code will be 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.
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.
Re-open your IDE. Paste the copied markup from AEM into the index.html
in the ui.frontend module beneath src/main/webpack/static
.
Edit the copied markup and remove any references to clientlib-site and clientlib-dependencies:
<!-- 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>
We can remove those references because the webpack dev server will generate these artifacts automatically.
Start the webpack dev server from a new terminal by running the following command from within the ui.frontend module:
$ 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 ./webpack.dev.js
This should open a new browser window at http://localhost:8080/ with static markup.
Edit the file src/main/webpack/site/_variables.scss
file. Replace the $text-color
rule with the following:
- $text-color: $black;
+ $text-color: $pink;
Save the changes.
You should automatically see the changes automatically reflected in the browser on http://localhost:8080.
Review the /aem-guides-wknd.ui.frontend/webpack.dev.js
file. This contains the webpack configuration used to start the webpack-dev-server. Note that 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.
The image src of the static markup points to a live image component on a local AEM instance. Images will 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.
You can stop the webpack server from the command line by typing CTRL+C
.
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 aemfed is designed to listen to file changes within the ui.apps module and automatically syncs them directly to a running AEM instance. Based on the changes, a local browser will automatically refresh, thereby speeding up front-end development. It also is built to work with Sling Log tracer to automatically display any server-side errors directly in the terminal.
If you are doing a lot of work within the ui.apps module, modifying HTL scripts and creating custom components, aemfed can be a very powerful tool to use. Full documentation can be found here..
With 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 will force AEM to re-compile any LESS files and generate the CSS.
Dump Libs - Lists all of 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 all of the client libraries or invalidate the cache of client libraries. This tool is particularly effective when developing with LESS as this can force AEM to re-compile the generated CSS. In general it is more effective to Invalidate Caches and then perform a page refresh versus rebuilding all of the libraries. <host>/libs/granite/ui/content/dumplibs.rebuild.html