UNPKG

aem-clientlib-generator

Version:

Creates configuration files for AEM ClientLibs and synchronizes assets.

343 lines (290 loc) 14.2 kB
aem-clientlib-generator ====== [![Build](https://github.com/wcm-io-frontend/aem-clientlib-generator/workflows/Build/badge.svg)](https://github.com/wcm-io-frontend/aem-clientlib-generator/actions?query=workflow%3ABuild) [![GitHub issues](https://img.shields.io/github/issues/wcm-io-frontend/aem-clientlib-generator)](https://github.com/wcm-io-frontend/aem-clientlib-generator/issues) A node plugin that creates ClientLib configuration files (repository nodes) for [AEM Client Libraries](https://helpx.adobe.com/experience-manager/6-3/sites/developing/using/clientlibs.html), creates _Client Library Folders_ and synchronizes all assets. It supports both JSON file format (default) and FileVault XML file format (see `serializationFormat` parameter). ## Installation ```bash npm install aem-clientlib-generator ``` ## Usage ### Command Line Interface The CLI `clientlib` is located in `./bin/clientlib-cli.js`. The command can be used without parameters, it loads the default configuration file `clientlib.config.js`. More options are described in help menu: ```text Options: --help, -h Show help [boolean] --version, -v Show version number [boolean] --dry 'Dry run' without write operations. [boolean] --verbose Prints more details [boolean] ``` #### clientlib.config.js A clientlib configuration file is a simple exported module: ```js module.exports = { // default working directory (can be changed per 'cwd' in every asset option) context: __dirname, // path to the clientlib root folder (output) clientLibRoot: "path/to/clientlib-root", // define all clientlib options here as array... (multiple clientlibs) libs: [ { name: "test.base.apps.mainapp", // optional override path to write clientlib files to, by default files // are written to lib.name/ outputPath: "explicit/path/to/lib/or/existing/lib/structure", assets: { js: [ "src/frontend/js/app.js" ], css: [ "src/frontend/css/styling.css" ] } }, ...// next clientlibs ], // or as object (single clientlib) libs: { name: "test.base.apps.mainapp", assets: { js: [ "src/frontend/js/app.js" ], css: [ "src/frontend/css/styling.css" ] } } } ``` #### npm scripts The CLI can be used in a project as local module via npm scripts (defined in `package.json`). ```js // package.json file: "scripts": { "test": "mocha", "build": "clientlib --verbose" } ``` In this case `npm run build` tries to load the default clientlib configuration file `clientlib.config.js` (same directory like package.json) and generates all clientslib as defined. ### Module: clientlib(arrProps | props, [options], callback) Import the module into a JavaScript file and run the module as a function: ```js var clientlib = require("aem-clientlib-generator"); clientlib(arrProps, { verbose: true }, function () { console.log("generator has finished"); }); ``` **Important:** Due to many write operations, the `clientlib` function is **asynchronous**! - `arrProps` `{Array<Object>}` Array of Clientlib configuration properties (see below) - `props` `{Object}` Clientlib configuration properties - `path` `{String}` Clientlib root path (optional if `options.clientLibRoot` is set) - `outputPath` `{String}` Clientlib destination path (optional, overrides default behavior of writing to the above path or options.clientLibRoot, useful to supply your own directory naming convention or if you are clientlib-ifying an existing directory) - `name` `{String}` Clientlib name (required) - `serializationFormat` `{String}` Type of the target archive for which the resources must be generated [json|xml] (optional, default=json) - `embed` `{Array<String>}` other Clientlib names that should be embedded (optional) - `dependencies` `{Array<String>}` other Clientlib names that should be included (optional) - `categories` `{Array<String>}` to set a category for the clientLib (optional), ovrrides the default that uses the name as category - `customProperties` `{Array<String>}` by default only a set of known properties will be copied over the clientlib, using this field custom properties can be added - `cssProcessor` `{Array<String>}` configuration for the clientlib CSS processor, requires AEM 6.2 (optional) - `jsProcessor` `{Array<String>}` configuration for the clientlib JS processor, requires AEM 6.2 (optional) - `replaces` `{String}` Path to the library that is replaced by 'this' one - `disableIfReplacing` `{boolean}` Disable this library if it would replace the old one - `assets` `{Object}` content that should be copied to the clientlib folder, more details below (required) - `allowProxy` `{Boolean}` allow for Clientlib creation under `/apps/myapp/clientLibs` but enable proxy to `/etc.clientlibs/myapp/clientlibs/mylib` See [AEM 6.3 Documentation](https://docs.adobe.com/docs/en/aem/6-3/develop/the-basics/clientlibs.html#Locating%20a%20Client%20Library%20Folder%20and%20Using%20the%20Proxy%20Client%20Libraries%20Servlet) - `longCacheKey` `{String}` optional string with placeholders to use with URL Fingerprinting, eq. `"${project.version}-${buildNumber}"`. This requires the [build-helper-maven-plugin](http://www.mojohaus.org/build-helper-maven-plugin/usage.html) to be configured, see [wcm-io-samples - Clientlibs](https://github.com/wcm-io/wcm-io-samples/blob/develop/bundles/clientlibs/pom.xml#L56). - `options` `{Object}` global options to be used for all clientlib definitions (optional) - `clientLibRoot` {String} Clientlib root path - `context` {String} changes the current working directory (via `process.chdir()`) - `cwd` {String} alias for `context` - `verbose` {Boolean} prints detailed information during generation - `dry` {Boolean} dry run without file write operations (sets automatically verbose to true) * `callback` `{Function}` to be called if clientlib() has finished ### The `assets` Object The `assets` object determine the content that should be pushed into the clientlib folder. The key stands for the content type, `js` for JavaScript files, `css` for styles and `resources` for other content such as fonts or images. ```javascript { js: { // JavaScript files to be copied and used for `js.txt` - a clientlib JS configuration file }, css: { // CSS files to be copied and used for `css.txt` - a clientlib CSS configuration file }, resources: { // other resources that should be copied } } ``` Each property can be an object of deeper configuration options (`assetConfig`) or an array of files (simple way, see example below). The following can be configured: - `assetConfig` `{Object}` Configuration object for an asset type - `base` `{String}` path within the clientlib folder where the data should be copied to (optional), default: asset key, e.g. for "js" is the base "js" - Hint: Using "." copies the files into the clientlib folder instead of the subfolder - `files` `{Array<String|Object>}` array of file paths (sources) or a src-dest key value map (required) - Important: The order of JS or CSS files in this property defines the merging/bundling order in AEM clientlib. - file object contains: - `src` {String} - source file relative to the current working directory or the global `cwd` option, if set - `dest` {String} - destination relative to the clientlib folder including base - `cwd` {String} - change working directory (relative to the context / global `cwd` option); only available with glob pattern - `flatten` {Boolean} - using file's basename instead of folder hierarchy; default true; only available with glob pattern - `ignore` `{String|Array<String>}` - glob pattern or array of glob patterns for matches to exclude For an glob example see example section below. ```javascript // simple version js: ["pth/to/file.js", { src: "pth/to/lib/file.js", dest: "lib/file.js" }]; // will be transformed to: js: { base: "js"; files: [ { src: "pth/to/file.js", dest: "file.js" }, { src: "pth/to/lib/file.js", dest: "lib/file.js" }, ]; } ``` ### Example ```javascript var clientlib = require("aem-clientlib-generator"); clientlib( [ { name: "test.base.apps.mainapp", // the name will be used as subfolder in clientlibs root and for the AEM repository node // in this example it creates: // the subfoler: path/to/clientlibs-root/test.base.apps.mainapp/ // repository node: path/to/clientlibs-root/test.base.apps.mainapp.json // new in AEM 6.2: configure the clientlib processor by yourself: // An example to disable minification for CSS: cssProcessor: ["default:none", "min:none"], // using google closure compiler for minification instead of YUI jsProcessor: ["default:none", "min:gcc;compilationLevel=whitespace"], // new in AEM 6.3: create clientLibs in /apps/myapp/clientlibs and proxy to /etc.clientlibs/myapp allowProxy: true, // will copy over the allowed properties and their values to the clientlib customProperties: [ "customProperty" ], customProperty: "customValue", // allow URL Fingerprinting via placeholder longCacheKey: "${project.version}-${buildNumber}", assets: { // creates the JS configuration file: // path/to/clientlibs-root/test.base.apps.mainapp/js.txt // which lists all JavaScript files from the ClientLib. // and copies all files into a js subfolder (default base): // path/to/clientlibs-root/test.base.apps.mainapp/js/ js: [ // file will be copied to: // path/to/clientlibs-root/test.base.apps.mainapp/js/app.js { src: "src/frontend/js/app.js", dest: "app.js" }, // file will be copied to: // path/to/clientlibs-root/test.base.apps.mainapp/js/libs/mylib.min.js { src: "src/frontend/js/libs/mylib.min.js", dest: "libs/mylib.min.js", }, // copy source map files as well { src: "src/frontend/js/libs/mylib.min.js.map", dest: "libs/mylib.min.js.map", }, ], // creates the CSS configuration file: // path/to/clientlibs-root/test.base.apps.mainapp/css.txt css: ["src/frontend/css/styling.css", "src/frontend/css/lib.css"], }, }, { name: "test.base.apps.secondapp", embed: [ "test.base.apps.thirdapp", // this clientlib will be auto embedded in AEM (kind of `merging`) ], dependencies: [ "test.base.apps.mainapp", // define clientlib dependency ], assets: { js: { base: "js", // by default the `base` is the asset key property files: [ { src: "src/frontend/secondapp/js/lib.js", dest: "secondapp-lib.js", }, ], }, // creates the CSS configuration file: // path/to/clientlibs-root/test.base.apps.secondapp/css.txt // that lists all CSS files from the ClientLib. // All files defined below will be copied into the defined base: // path/to/clientlibs-root/test.base.apps.secondapp/style/ css: { base: "style", // changes the `base` from `css` (default) to `style` files: ["src/frontend/secondapp/main.css"], }, resources: ["src/frontend/resources/template.html"], }, }, { name: "test.base.apps.thirdapp", assets: { // copy all files into the clientlib subfolder, because `base` is changed: // path/to/clientlibs-root/test.base.apps.thirdapp/ resources: { base: ".", // copy the file into `test.base.apps.thirdapp` (root) instead of `test.base.apps.thirdapp/resources` files: ["src/frontend/resources/notice.txt"], }, }, }, { name: "test.base.apps.fourth", assets: { js: { // "flatten" is true by default and using file's basename instead of path for destination // set to false to keep the folder hierarchy below "cwd" flatten: false, // remove this option if you like a flat list of files in your clientlib cwd: "src/frontend/js/", // change working directory (will be stripped from destination) files: [ "**/*.js", // match all js files recursively "**/*.js.map", ], }, css: [ // all css will copied to destination folder "style" (in base folder css) { src: "src/frontend/css/*.css", dest: "style/" }, // all css will copied to destination folder "vendor" (in base folder css) { src: "src/frontend/secondapp/*.css", dest: "vendor/" }, ], }, }, { name: "test.base.apps.myExistingAssetOrganization", outputPath: path.join(__dirname, "libs", "collectionOne"), assets: { // uses existing files at ./libs/collectionOne, since base is set to '.' js: { base: ".", // copy the file into `./libs/collectionOne` (outputPath) instead of `{path}/test.base.apps.myExistingAssetOrganization/js` files: ["libs/collectionOne/index.js"], }, }, }, ], { cwd: __dirname, // using folder of the file as current working directory clientLibRoot: path.join(__dirname, "path/to/clientlibs-root"), }, function () { console.log("clientlibs created"); } ); ``` ### Deploying to AEM: The generated client library can be deployed to AEM via [Sling Content Loading](https://sling.apache.org/documentation/bundles/content-loading-jcr-contentloader.html). Take a look at the [wcm.io Sample Application](https://github.com/wcm-io/wcm-io-samples/tree/develop/bundles/clientlibs). If you've switched the `serializationFormat` to "xml" you can deploy the client library as part of an AEM content package.