May 12, 2020
Estimated Post Reading Time ~

Style Guides and AEM: Fitting a Square Peg in a Round Hole


There is a push in the industry to code against an external style guide to maintain consistent styling, have a reusable set of components to build applications with and provide a shared vocabulary for teams to communicate. The goal is that any web application built in an organisation can make use of this style guide to re-use existing CSS rules and/or Javascript functions. For example, one of the more well-known and recently-published style guides is the U.S. Web Design Standards, which will enable U.S. government agencies to create a unified user experience throughout their web applications. 

When dealing with modern web applications, integrating a style guide is a relatively straightforward process. It often involves leveraging the existing Javascript build tooling to pull assets down via npm, and then having those assets processed as part of the build pipeline along with your application’s styles/scripts. Alternately, you can simply copy-paste a version of your style guide’s artifacts into your application – the quick and dirty way. 

However, things are not always this easy. In my experience working with AEM/CQ, integrating a style guide into a project has consistently been a challenge.
To be fair, style guides are not to be blamed for this. AEM’s strict file structure, meta-data (.content.xml files and the like) and reliance on Java technologies can make it challenging to integrate with Javascript-based tooling. Each project generally ends up with a set of custom scripts to achieve this integration, resulting in a solution that is simply not maintainable. If you’ll indulge me for a moment, I’d like to take this opportunity to run through a few solutions I’ve come across to integrate style guides with AEM.

1. GruntJS-to-Zip-to-Nexus-to-Maven-to-Groovy-to-AEM
In this scenario, a heavily scripted Gruntfile is used to organise the CSS and JS files into folders and create the necessary js.txt and css.txt files at the root of each folder. The resulting artifact files is then zipped and deployed to Nexus.
The responsibility for integrating those artifacts with an AEM project is then hand-balled to the Maven build for the project. The build has the style guide dependencies listed in its POM, which are pulled down from Nexus. 

However, because the files inside do not conform to AEM’s requirement for a client library, a custom Groovy script needs to be used to process the unpacked zip and generate the .content.xml file for the ClientLibrary folder. At this point, the Groovy script also transfers the client library folder to a location that can be picked up by filter.xml, which can then package it along with the other assets using content-package-maven-plugin.

I think it’s safe to say this is not an ideal way of going about things. Having a Gruntfile of around 1000 lines to orchestrate only a portion of the process rings alarm bells in itself. Moreover, having the responsibility for the proper formatting of the client library spread between two independent applications makes it difficult to debug

  

I think this person may be attempting to integrate AEM with a style guide… 

2. AEM-only
I’ve also come across projects that have abandoned the idea of having an external style guide re-usable by non-AEM applications altogether and have implemented their style guide as an AEM project. As a result, no integration issues need to tackled, however, it sort of defeats the purpose of a style guide as it is not re-usable by other types of web applications. It’s arguable whether decisions like these are made due to fear of having to tackle integration issues or simply a push from the organisation to adopt AEM as a solution for web applications throughout the organisation.  

3. Git-Subtree-to-Maven-to-GulpJS-to-AEM
This method of integration works in an interesting way as it uses a hybrid Gulp/Maven style guide. The style guide uses its Maven nature to be added as a sub-module in the AEM Maven build via a git subtree. Once changes are made to the style guide, a git subtree pull is executed to pull down the latest changes from the style guide repository.
In order to integrate the style guide with AEM, Maven profiles are added to execute GulpJS tasks (using the frontend-maven-plugin) that process the style guide assets (linting, pre-processing, etc) and move them to another Maven sub-module which is responsible for packaging everything along with the other assets using the content-package-maven-plugin.

This approach has merit in that it’s more maintainable, given there is no complex processing of files required to generate a client library. However, the drawback is that only a predetermined set of files can be transferred across to AEM if the developers have opted to leverage an existing client library’s js.txt and css.txt. Including additional assets would need a modification of the js.txt and css.txt as well as modifications to the Gulpfile.  

4. GruntJS-to-AEM
Shine’s preferred method is to think pragmatically and come up with a solution that uses the right tool for the job, instead of relying on questionable workarounds. This last approach uses a Grunt plugin I developed called grunt-clientlibify, which is an attempt at standardising the way style guides are integrated with AEM.
This plugin aims to take the guess work out of integrating AEM with an external style guide by leveraging mature Javascript tooling to build (and optionally deploy) a CRX package containing front-end assets.
  

For the purpose of demonstrating the plugin, let’s integrate the U.S Web Design Standards (a.k.a “uswds”) we talked about earlier into AEM. To the untrained eye, this would seem like a daunting task, potentially taking weeks of development time. Let’s see if we can do this in 5 minutes, shall we?
Please note that you must have a local instance of AEM running on port 4502 for the deployment to be successful.
Let’s start off by creating a project directory and set up our dependencies:
[code]
mkdir uswds-blog
cd uswds-blog
npm init
npm install grunt –save-dev
npm install grunt-run –save-dev
npm install grunt-clientlibify –save-dev
[/code]
Then we need to add the uswds github repository as a dependency in the “dependencies” section inside package.json:
[code language=”js”]
"uswds": “https://github.com/18F/web-design-standards.git#18f-pages-staging"
[/code]
At the very minimum our package.json file should look something like this:
[code language=”js”]
{
"name": "uswds-aem",
"version": "1.0.0",
"description": "Sample project to demonstrate integrating the U.S. Web Design Standards with AEM using the grunt-clientlibify plugin",
"author": {
"name": Michael Leroy,
"email": "michael.leroy@shinetech.com"
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-clientlibify": "^0.2.0",
"grunt-run": "^0.5.2"
},
"dependencies": {
"uswds": "https://github.com/18F/web-design-standards.git#18f-pages-staging"
}
}
[/code]
Then we create the following Gruntfile.js:
[code language=”js”]
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON(‘package.json’),
run: {
commands: {
exec: ‘cd node_modules/uswds & npm run build-sass’
}
}
});
grunt.loadNpmTasks(‘grunt-run’);
grunt.registerTask(‘default’, [‘run’]);
};
[/code]  

All this file will do is run the `build-sass` npm task supplied by the uswds project in order to compile the project’s SASS files.
We can check if our setup works by running the `npm install` followed by the `grunt` command:

Let’s now go ahead and configure the `clientlibify` task to deploy this style guide to AEM.
In the Gruntfile, we load the `clientlibify` grunt task:
[code language=”js”]
grunt.loadNpmTasks(‘grunt-clientlibify’);
[/code]
Also, we make sure to add the task to the default build:
[code language=”js”]
grunt.registerTask(‘default’, [‘run’, ‘clientlibify’]);
[/code]
In the Gruntfile, add the following task config after the `run` task:
[code language=”js”]
clientlibify: {
options: {
// where to dump the generated .zip package
dest: ‘dist’,
// these tell the plugin where to find the css and js files
cssDir: ‘node_modules/uswds/assets/css’,
jsDir: ‘node_modules/uswds/assets/js’,
// set `installPackage` to `true` to deploy to an AEM instance
installPackage: true,
categories: [‘uswds’],
embed: [],
dependencies: [],
// package options
packageName: ‘uswds-styleguide’,
packageDescription: ‘Package containing USWDS styles/scripts and installed using the grunt-clientlibify plugin’,
// deploy options
// Note: these options would likely come from environment vars
deployScheme: ‘http’,
deployHost: ‘localhost’,
deployPort: ‘4502’,
deployUsername: ‘admin’,
deployPassword: ‘admin’
},
build: {
// target options go here
}
}
[/code]
 

In order to demonstrate the features of this plugin, I’ve included all the available options. However, the only mandatory ones are `cssDir` and `jsDir`.
We can now run the `grunt` command and watch the magic happen:

As you can see, the task generates a CRX package containing our style guide’s assets and uploaded it successfully to our local AEM instance. Let’s login to AEM and check things out. Navigate to http://localhost:4502/crx/packmgr/index.jsp and we should be able to see our newly installed package:

Navigate to http://localhost:4502/crxde and we should be able to see our style guide files under `/etc/designs/uswds`:
 

Hooray! Now it’s business as usual and the U.S. Web Design Standards can be injected on a JSP page by using the standard cq tag lib:
[code language=”html”]
<cq:includeClientLib categories=“uswds”>
[/code]
Any issues or feature requests, head on over to the Github page for the project (contributions are welcomed). Now go forth and fit that square peg in that round hole!



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.