Skip to content

Nodejs tool which helps to build/inject critical/component CSS for AEM components (Adobe Experience Manager)

License

Notifications You must be signed in to change notification settings

dmantsevich/aem-critical-css

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

39 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

AEM Critical CSS 🐝

Nodejs tool which helps to build/inject critical/component CSS for AEM templates/components (Adobe Experience Manager).

It can be used as components CSS dependency resolver/injector (not as automatically code splitter/extractor).

dmantsevich/aem-critical-css

Table of contents πŸ‘ˆπŸ»

Features 🐿

  • Fast, flexible, powerful
  • Configurable
  • Inline injection via style tag
  • Standalone injection via link tag
  • Single injection (on the page)
  • Auto-resolving injection type by file size
  • Hashes for files injected via link tag
  • Supports .css, .scss, .sass, .less files
  • Partial injection (css depends on component configuration)
  • Tested on several AEM projects
  • etc.

Install 🐠

  1. Install NodeJs (This will also install npm)
  2. Install @dmantsevich/aem-critical-css as dependency for your project (πŸ‘):
npm i @dmantsevich/aem-critical-css --save

How to use 🐟

That section shows basic usage for beginners.

  1. Open AEM component template and add next code (where "path/to/component-css.less" is path to critical css file, which should be injected. Path is related to ${config.css.sourceRoot} (see config). Supports: less, scss, sass, css types):
<sly data-sly-use.aemCriticalCSS="${'./_aem-critical-css.js'}"
	@aem-critical-css="path/to/component-css.less">${aemCriticalCSS.inject @ context="unsafe"}</sly>
  1. Go to folder where frontend team are working (cd ui.frontend or cd ui.clientlibs or other)
  2. Install AEM Critical CSS module/package as dependency (see Install section):
npm i @dmantsevich/aem-critical-css --save
  1. Create aem-critical-css.js file (in the future webpack, gulp & grunt wrappers will be added) with code:
const { process } = require('@dmantsevich/aem-critical-css');
const config = {}; // it is configuration for the project
process(config);
  1. Process templates (see Regular Workflow section) (it should be a part of frontend build):
node aem-critical-css.js
  1. If processing was successful, then you can find generated css file (aem-critical-css.js) near AEM component template.
  2. You can deploy code to AEM

Regular Workflow πŸ‰

  1. Tool is searching all "*.html" files (HTL) under ${config.AEM.components} (by default: ui.apps/src/main/content/jcr_root/apps/ folder | see config) folder
  2. Analyzing all found files, which contains ${criticalCSS.file}.${criticalCSS.type} (by default: _aem-critical-css.js string | see config) string.
  3. Parsing ${config.criticalCSS.sourceAttr}, ${config.criticalCSS.injectionTypeAttr}, ${config.criticalCSS.serviceAttr} attributes. (by default: @aem-critical-css, @aem-critical-css-injectiontype, @aem-critical-css-service attributes | see config)
  4. If parsing was successful, then starts generating CSS code linked in ${config.criticalCSS.sourceAttr} (by default: @aem-critical-css attribute | see config) attribute.
    • Reading source ${config.css.sourceRoot}/${@aem-critical-css-attribute-value} file (by default: ./${aem-critical-css-attribute-value} | see config)
    • Compile source file with less, node-sass compiler (you can create your custom compiler)
    • Process CSS with postcss plugins (by default: autoprefixer, cssnano | see config)
  5. Resolve injection type
    • If ${config.criticalCSS.injectionTypeAttr} attribute (by default: @aem-critical-css-injectiontype | see config) is defined, then it will be used
    • Otherwise ${config.criticalCSS.injectionType} value (by default: auto | see config) will be used
    • Resolving for injection type auto:
      • Calculating filesize for generated CSS file (after gzip)
      • If filesize is lower ${config.criticalCSS.gzipSize} (by default: 10kb | see config) then file will be injected via <style> tag.
      • Otherwise file will be injected via <link> tag.
  6. If injection type is link, then css file(file name will contains hash) will be saved under ${config.web.localClientlib}/resources/ folder (by default: ui.apps/src/main/content/jcr_root/apps/aem-critical-css/resources/ | see config)
  7. Generating ${criticalCSS.file}.${criticalCSS.type} (by default: _aem-critical-css.js | see config) file in the same folder with HTL template (where it used).

API πŸ¦”

Next properties & method exports @dmantsevich/aem-critical-css module:

  • process(config) {function} - process AEM templates & generate css files for injection.
  • CRITICAL_CSS_TYPES {constants} - contains possible types for critical css files. Uses in configuration ${config.criticalCSS.type}. See config section
    • CRITICAL_CSS_TYPES.TEMPLATE - generate HTL files.
    • CRITICAL_CSS_TYPES.USEAPI - generate JS files.
  • INJECTION_TYPES {constants} - contains possible values for configuration ${config.criticalCSS.injectionType}. Also that values can be used in "@aem-critical-css-inectiontype" attribute.
    • INJECTION_TYPES.INLINE - inject css with <style> tag. (see Injection type - Inline)
    • INJECTION_TYPES.LINK - inject css with <link href="...."> tag. (see Injection type - Link)
    • INJECTION_TYPES.AUTO - resolve injection type automatically. By default, if filesize(after gzip) is lower 10kb, then INLINE type will be used, otherwise LINK. See config section

Config πŸ¦–

Default config file here: /main/lib/config.js

Property Description
AEM.projectRoot {String} Path to AEM Project root folder. Default value: ./../(parent folder)
AEM.components {String} Path to HTL templates which should be processed. Path should be relative to ${config.AEM.projectRoot}. Default value: ui.apps/src/main/content/jcr_root/apps/
criticalCSS.file {String} Name for output(generated) files. Result filename: ${config.criticalCSS.file}.${config.criticalCSS.type}. See Regular Workflow section. Default value: _aem-critical-css
criticalCSS.type {CRITICAL_CSS_TYPES.USEAPI / CRITICAL_CSS_TYPES.TEMPLATE} Output file type. Default value: CRITICAL_CSS_TYPES.USEAPI
criticalCSS.injectionType {INJECTION_TYPES.AUTO / INJECTION_TYPES.INLINE / INJECTION_TYPES.LINK} Default injection type (if @aem-critical-css-injectiontype attribute isn't defined). Default value: INJECTION_TYPES.AUTO
criticalCSS.injectionTypeAutoResolver {Function(criticalCSSDefObj)} Function-Resolver for INJECTION_TYPES.AUTO. Calling for each AEM Critical CSS definition. Should return INJECTION_TYPES.INLINE or INJECTION_TYPES.LINK. By default: based on CSS GZip size(getGzip(css) < config.criticalCSS.gzipSize ? INJECTION_TYPES.INLINE : INJECTION_TYPES.LINK). See criticalCSS.gzipSize option.
criticalCSS.gzipSize {Integer} Default value: 10kb. If CSS GZip size lower than is value, then css will be injected - INJECTION_TYPES.INLINE. Otherwise: INJECTION_TYPES.LINK. Working only with default criticalCSS.injectionTypeAutoResolver
criticalCSS.sourceAttr {String} Attribute with path to css source file. Default value: @aem-critical-css
criticalCSS.injectionTypeAttr {String} Attribute with injection type configuration. If attribute isn't present, then criticalCSS.injectionType value will be used. Default value: @aem-critical-css-injectiontype
criticalCSS.serviceAttr {String} Attribute with path (should be relative to jcr_root) to custom injector service. Default value: @aem-critical-css-service. Level: Expert.
criticalCSS.useAPIService {String} Path (should be relative to jcr_root) to default JS/Java css injector service. By default: built-in service (AEMCriticalCSSService.js). Level: Expert.
criticalCSS.AEMCriticalCSSServiceDestination {String} Path, where build-in (AEMCriticalCSSService.js) file will be saved. Default value: ui.apps/src/main/content/jcr_root/apps/aem-critical-css/utils/. Level: Expert.
criticalCSS.minifyOutput {Boolean} Minify output(for generated _aem-critical-css.html, _aem-critical-css.js files). Default value: true

Injection type - Inline (as a part of HTML)

For small or important(critical) css files, that type is more - preferable. Because request to small files can be bigger (+ non-blocking rendition), than css content.

HTML output for component/critical css file will be (just example):

<!-- @aem-critical-css: path/to/component-css.less -->
<style>/*2021-2-21 0:49:06*/.my-component{border:1px solid red}.my-component a{border:1px solid green}</style>

Injection type - Link (as a css file)

That type is better for rarely used components on site pages. That files can be cached in user browser.

HTML output for component/critical css file will be (just example):

<!-- @aem-critical-css: path/to/component-css.less -->
<link href="/etc.clientlibs/aem-critical-css/resources/path/to/component-css.1ha51609gjk2.css" rel="stylesheet"/>

Partial CSS injection πŸ‡

Should helps to split & inject only necessary CSS for your component (depends on component configuration)

TBD

Custom Services

Will describe how to create own service

TBD

Best practice πŸ¦—

  • Add _aem-critical-css.js, _aem-critical-css.html files (see config) to your .gitignore file
  • Add ui.apps/src/main/content/jcr_root/apps/aem-critical-css/ folder (see config) to your .gitignore file

TBD

FAQ πŸ¦†

If you have any questions or you need help, feel free to ask via github: Issues

Most popular questions/answers will be here

TBD

Roadmap πŸ¦™

TBD

Links πŸ™

@dmantsevich/aem-critical-css

dmantsevich/aem-critical-css

Adobe Experience Manager

🧰


2021

Releases

No releases published

Packages

No packages published