Client-Side Libraries and Front-end Workflow

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.

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

NOTE

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:

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

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

    $ mvn clean install -PautoInstallSinglePackage
    
    NOTE

    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.

Objective

  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 will build

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.

Finished Styles

Article Page with baseline styles applied

Background

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:

  1. Store CSS/JS in small discrete files for easier development and maintenance
  2. Manage dependencies on 3rd 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 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.

Client-Side Libraries Organization

Next we will 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

NOTE

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.

  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

    We will inspect these clientlibs in greater detail below.

  3. 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
  4. 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.

Update base styles

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.

  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 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.

  3. Inspect the file main.ts. main.ts includes main.scss and includes 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.

  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 wknd-base-styles-src.zip and unzip the file.

    WKND Base Styles

    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.

  7. 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
             /base
             /components
             /resources
    

    Changed files

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

Inspect the 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:

    $ cd ~/code/aem-guides-wknd/ui.frontend
    $ npm install
    
    NOTE

    npm install only needs to be run once, following a new clone or generation of the project.

  2. In the same terminal, build and deploy the ui.frontend module by using the npm run dev command:

    $ npm run dev
    
    CAUTION

    You may recieve an error like “ERROR in ./src/main/webpack/site/main.scss”.
    This usually happens because your environment has changed since running npm install.
    Run npm rebuild node-sass to fix the issue. This will happen if the version of npm installed on your local dev machine differs from the version used by the Maven frontend-maven-plugin in the aem-guides-wknd/pom.xml file. You can permanently fix this by modifying the version in the pom file to match your local version or vice-versa.

  3. The command npm run dev should build and compile the source code for the Webpack project and ultimately populate the clientlib-site and clientlib-dependencies in the ui.apps module.

    NOTE

    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.

  4. Inspect the file site.css beneath ui.frontend/dist/clientlib-site/css/site.css. This is the compiled CSS based on the Sass source files.

    Distributed Site css

  5. 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.

  6. 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

    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.

  7. Sync the clientlib-site library with a local instance of AEM using the developer tools or Maven skills.

    Sync Clientlib Site

  8. 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

    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.

CAUTION

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

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. In the ui.apps module navigate to ui.apps/src/main/content/jcr_root/apps/wknd/components/page.

    Structure Page Component

    This is the page component that is used to render all pages in the WKND implementation.

  2. Open the file customheaderlibs.html. Notice the lines ${clientlib.css @ categories='wknd.base'}. This indicates that the CSS for the clientlib with a category of wknd.base will be included via this file, effectively including clientlib-base in the header of all our pages.

  3. Update customheaderlibs.html to include a reference to Google font styles that we specified earlier in the ui.frontend module.

    <link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600|Asar&display=swap" rel="stylesheet">
    <sly data-sly-use.clientLib="/libs/granite/sightly/templates/clientlib.html"
     data-sly-call="${clientlib.css @ categories='wknd.base'}"/>
    
    <!--/* Include Context Hub */-->
    <sly data-sly-resource="${'contexthub' @ resourceType='granite/contexthub/components/contexthub'}"/>
    
  4. Inspect the file customfooterlibs.html. This file, like customheaderlibs.html is meant to be overwritten by implementing projects. Here the line ${clientlib.js @ categories='wknd.base'} means that the JavaScript from clientlib-base will be included at the bottom of all our pages.

  5. Export the page component to the AEM server using the developer tools or using your Maven skills.

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

  7. 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

  8. 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.

    Article Page Template Menu Page Policy

    NOTE

    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.

  9. 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. You should see a difference in fonts.

  10. 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

  11. 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>
    ...
    <link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600|Asar&display=swap" rel="stylesheet"/>
    <link rel="stylesheet" href="/etc.clientlibs/wknd/clientlibs/clientlib-base.min.css" type="text/css">
    <script type="text/javascript" src="/etc.clientlibs/wknd/clientlibs/clientlib-dependencies.min.js"></script>
    <link rel="stylesheet" href="/etc.clientlibs/wknd/clientlibs/clientlib-dependencies.min.css" type="text/css">
    <link rel="stylesheet" href="/etc.clientlibs/wknd/clientlibs/clientlib-site.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 type="text/javascript" src="/etc.clientlibs/wknd/clientlibs/clientlib-site.min.js"></script>
    <script type="text/javascript" src="/etc.clientlibs/wknd/clientlibs/clientlib-base.min.js"></script>
    ...
    </body>
    
    NOTE

    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).

    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.

Webpack DevServer - Static Markup

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.

  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. Re-open 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:

    <!-- 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.

  4. 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
    
  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:

    - $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/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.

    CAUTION

    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.

  9. You can stop the webpack server from the command line by typing CTRL+C.

Webpack DevServer - Watch and aemsync

Another technique is to have Node.js watch for any file changes to the src files in the ui.frontend module. Whenever a file changes it will quickly compile the client library and use the aemsync npm module to sync the changes to a running AEM server.

  1. Start the webpack dev server in watch mode from a new terminal by running the following command from within the ui.frontend module:

    $ cd ~/code/aem-guides-wknd/ui.frontend/
    $ npm run watch
    
  2. This will compile the src files 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
    
  3. Navigate to AEM and the LA Skateparks article: http://localhost:4502/content/wknd/us/en/magazine/guide-la-skateparks.html?wcmmode=disabled

    Changes deployed to AEM

    The changes should be deployed to AEM. There is a slight delay and you will have to refresh the browser manually to see the updates. However viewing the changes directly in AEM is beneficial if you are working with new components and dialog authoring.

  4. Revert the change to _variables.scss and save the changes. The changes should again be synced with the local instance of AEM after a slight delay.

  5. Stop the webpack dev server and perform a full Maven build from the root of the project:

    $ cd aem-guides-wknd
    $ mvn clean install -PautoInstallSinglePackage
    

    Again the ui.frontend module is compiled, transformed to clientlibraries and deployed to AEM via the ui.apps module. However this time Maven performs everything for us.

Congratulations!

Congratulations, the Article Page now has some consistent styles that match the WKND brand and you have become familiar with the ui.frontend module!

Next Steps

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.

  1. Clone the github.com/adobe/aem-wknd-guides repository.
  2. Check out the tutorial/client-side-libraries-solution branch.

Additional Tools and Resources

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 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..

Debugging Client-side Libraries

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

rebuild client library

On this page