To help deal with this issue, AEM provides Client-side Library Folders, which allow you to store your client-side code in the repository, organize it into categories, and define when and how each category of code is to be served to the client. The client-side library system then takes care of producing the correct links in your final webpage to load the correct code.
How Client-Side Libraries Work in AEM
The standard way to include a client-side library (that is, a JS or CSS file) in the HTML of a page is simply to include a <script> or <link> tag in the JSP for that page, containing the path to the file in question. For example,
<head>
...
<script type="text/javascript" src="/etc/clientlibs/granite/jquery/source/1.8.1/jquery-1.8.1.js"></script>
...
</head>
While this approach works in AEM, it can lead to problems when pages and their constituent components become complex. In such cases there is the danger that multiple copies of the same JS library may be included in the final HTML output. To avoid this and to allow logical organization of client-side libraries AEM uses client-side library folders.
A client-side library folder is a repository node of type cq:ClientLibraryFolder. It’s definition in CND notation is
[cq:ClientLibraryFolder] > sling:Folder
- dependencies (string) multiple
- categories (string) multiple
- embed (string) multiple
- channels (string) multiple
By default, cq:ClientLibraryFolder nodes can be placed anywhere within the /apps, /libs and /etc subtrees of the repository (these defaults, and other settings can be controlled through the Adobe Granite HTML Library Manager panel of the System Console).
[cq:ClientLibraryFolder] > sling:Folder
- dependencies (string) multiple
- categories (string) multiple
- embed (string) multiple
- channels (string) multiple
By default, cq:ClientLibraryFolder nodes can be placed anywhere within the /apps, /libs and /etc subtrees of the repository (these defaults, and other settings can be controlled through the Adobe Granite HTML Library Manager panel of the System Console).
Each cq:ClientLibraryFolder is populated with a set of JS and/or CSS files, along with a few supporting files (see below). The properties of the cq:ClientLibraryFolder are configured as follows:
- categories: Identifies the categories into which the set of JS and/or CSS files within this cq:ClientLibraryFolder fall. The categories property, being multi-valued, allows a library folder to be part of more than one category (see below for how this may be useful).
- dependencies: This is a list of other client library categories on which this library folder depends. For example, given two cq:ClientLibraryFolder nodes F and G, if a file in F requires another file in G in order to function properly, then at least one of the categories of G should be among the dependencies of F.
- embed: Used to embed code from other libraries. If node F embeds nodes G and H, the resulting HTML will be a concetration of content from nodes G and H.
- allowProxy: If a client library is located under /apps, this property allows acces to it via proxy servlet.
Because HTL is the preferred technology for developing AEM sites, HTL should be used to include client-side libraries in AEM. However it is also possible to do so using JSP.
Using HTL
In HTL, client libraries are loaded through a helper template provided by AEM, which can be accessed through data-sly-use. Three templates are available in this file, which can be called through data-sly-call:
css – Loads only the CSS files of the referenced client libraries.
js – Loads only the JavaScript files of the referenced client libraries.
all – Loads all the files of the referenced client libraries (both CSS and JavaScript).
Each helper template expects a categories option for referencing the desired client libraries. That option can be either an array of string values, or a string containing a comma separated values list.
Using JSP
Add a ui:includeClientLib tag to your JSP code to add a link to client libraries in the generated HTML page. To reference the libraries, you use the value of the categories property of the ui:includeClientLib node.
<%@taglib prefix="ui" uri="http://www.adobe.com/taglibs/granite/ui/1.0" %>
<ui:includeClientLib categories="<%= categories %>" />
For example, the /etc/clientlibs/foundation/jquery node is of type cq:ClientLibraryFolder with a categories property of value cq.jquery. The following code in a JSP file references the libraries:
<ui:includeClientLib categories="cq.jquery"/>
The generated HTML page contains the following code:
<script type="text/javascript" src="/etc/clientlibs/foundation/jquery.js"></script>
Caution:
<cq:includeClientLib>, which in the past was commonly used to include client libraries, has been deprecated since AEM 5.6. <ui:includeClientLib> should be used instead as detailed above.
Creating Client Library Folders
Create a cq:ClientLibraryFolder node to define JavaScript and Cascading Style Sheet libraries and make them available to HTML pages. Use the categories property of the node to identify the library categories to which it belongs.
The node contains one or more source files that, at runtime, are merged into a single JS and/or CSS file. The name of the generated file is the node name with either the .js or .css file name extension. For example, the library node named cq.jquery results in the generated file named cq.jquery.js or cq.jquery.css.
Client library folders contain the following items:
The JS and/or CSS source files to merge.
Resources that support CSS styles, such as image files.Note: You can use subfolders to organize source files.
One js.txt file and/or one css.txt file that identifies the source files to merge in the generated JS and/or CSS files.
The web client must have permissions to access the cq:ClientLibraryFolder node. You can also expose libraries from secured areas of the repository .
Overriding Libraries in /lib
Client library folders located below /apps take precedence over same-named folders that are similarly located in /libs. For example, /apps/cq/ui/widgets takes precedence over /libs/cq/ui/widgets. When these libraries belong to the same category, the library below /apps is used.
Locating a Client Library Folder and Using the Proxy Client Libraries Servlet
In previous versions, client library folders were located below /etc/clientlibs in the repository. This is still supported, however it is recommended that client libraries now be located under /apps. This is to locate the client libraries near the other scripts, which are generally found below /apps and /libs.
Note:
In order to better isolate code from content and configuration, it is recommended to locate client libraries under /apps and expose them via /etc.clientlibs by leveraging the allowProxy property.
The JS and/or CSS source files to merge.
Resources that support CSS styles, such as image files.Note: You can use subfolders to organize source files.
One js.txt file and/or one css.txt file that identifies the source files to merge in the generated JS and/or CSS files.
The web client must have permissions to access the cq:ClientLibraryFolder node. You can also expose libraries from secured areas of the repository .
Overriding Libraries in /lib
Client library folders located below /apps take precedence over same-named folders that are similarly located in /libs. For example, /apps/cq/ui/widgets takes precedence over /libs/cq/ui/widgets. When these libraries belong to the same category, the library below /apps is used.
Locating a Client Library Folder and Using the Proxy Client Libraries Servlet
In previous versions, client library folders were located below /etc/clientlibs in the repository. This is still supported, however it is recommended that client libraries now be located under /apps. This is to locate the client libraries near the other scripts, which are generally found below /apps and /libs.
Note:
In order to better isolate code from content and configuration, it is recommended to locate client libraries under /apps and expose them via /etc.clientlibs by leveraging the allowProxy property.
In order for the client libraries under /apps to be accessible, a proxy servelt is used. The ACLs are still enforced on the client library folder, but the servlet allows for the content to be read via /etc.clientlibs/ if the allowProxy property is set to true.
A static resource can only be accessed via the proxy, if it resides below a resource below the client library folder.
As an example:
You have a clientlib in /apps/myproject/clientlibs/foo
You have a static image in /apps/myprojects/clientlibs/foo/resources/icon.png
Then you set the allowProxy property on foo to true.
You can then request /etc.clientlibs/myprojects/clientlibs/foo.js
You can then reference the image via /etc.clientlibs/myprojects/clientlibs/foo/resources/icon.png
Caution:
When using proxied client libraries, the AEM Dispatcher configuration may require an update to ensure the URIs with the extension clientlibs are allowed.
Caution:
Adobe recommends locating client libraries under /apps and making them available using the proxy servlet. However keep in mind that best practice still requires that public sites never include anything that is served directly over an /apps or /libs path.
Linking to Dependencies
When the code in your client library folder references other libraries, identify the other libraries as dependencies. In the JSP, the ui:includeClientLib tag that references your client library folder causes the HTML code to include a link to your generated library file as well as the dependencies.
The dependencies must be another cq:ClientLibraryFolder. To identify dependencies, add a property to your cq:ClientLibraryFolder node with the following attributes:
Name: dependencies
Type: String[]
Values: The value of the categories property of the cq:ClientLibraryFolder node that the current library folder depends on.
For example, the /etc/clientlibs/myclientlibs/publicmain has a dependency on the cq.jquery library. The JSP that references the main client library generates HTML that includes the following code:
<script src="/etc/clientlibs/foundation/cq.jquery.js" type="text/javascript">
<script src="/etc/clientlibs/mylibs/publicmain.js" type="text/javascript">
Embedding Code From Other Libraries
You can embed code from a client library into another client library. At runtime, the generated JS and CSS files of the embedding library includes the code of the embedded library.
Embedding code is useful for providing access to libraries that are stored in secured areas of the repository.
App-Specific Client Library Folders
It is a best practice to keep all application-related files in their application folder below /app. It is also a best practice to deny access for web site visitors to the /app folder. To satisfy both best practices, create a client library folder below the /etc folder that embeds the client library that is below /app.
<script src="/etc/clientlibs/foundation/cq.jquery.js" type="text/javascript">
<script src="/etc/clientlibs/mylibs/publicmain.js" type="text/javascript">
Embedding Code From Other Libraries
You can embed code from a client library into another client library. At runtime, the generated JS and CSS files of the embedding library includes the code of the embedded library.
Embedding code is useful for providing access to libraries that are stored in secured areas of the repository.
App-Specific Client Library Folders
It is a best practice to keep all application-related files in their application folder below /app. It is also a best practice to deny access for web site visitors to the /app folder. To satisfy both best practices, create a client library folder below the /etc folder that embeds the client library that is below /app.
Use the categories property to identify the client library folder to embed. To embed the library, add a property to the embedding cq:ClientLibraryFolder node, using the following property attributes:
Name: embed
Type: String[]
Value: The value of the categories property of the cq:ClientLibraryFolder node to embed.
Using Embedding to Minimize Requests
In some cases you may find that the final HTML generated for typical page by your publish instance includes a relatively large number of <script> elements, particularly if your site is using client context information for analaytics or targeting. For example, in a non-optimized project you might find the following series of <script> elements in the HTML for a page:
<script type="text/javascript" src="/etc/clientlibs/granite/jquery.js"></script>
<script type="text/javascript" src="/etc/clientlibs/granite/utils.js"></script>
<script type="text/javascript" src="/etc/clientlibs/granite/jquery/granite.js"></script>
<script type="text/javascript" src="/etc/clientlibs/foundation/jquery.js"></script>
<script type="text/javascript" src="/etc/clientlibs/foundation/shared.js"></script>
<script type="text/javascript" src="/etc/clientlibs/granite/underscore.js"></script>
<script type="text/javascript" src="/etc/clientlibs/foundation/personalization/kernel.js"></script>
In such cases, it can be useful to combine all the required client library code in to a single file so that the number of back and forth requests on page load is reduced. To do this you can embed the required libraries into you app-specific client library using the embed property of the cq:ClientLibraryFolder node.
The following client library categories are incuded with AEM. You should embed only those that are required for he functioning of your particular site. However, you should maintain the order listed here:
When you embed CSS files, the generated CSS code uses paths to resources that are relative to the embedding library. For example, the publicly-accessible library /etc/client/libraries/myclientlibs/publicmain embeds the/apps/myapp/clientlib client library:
The main.css file contains the following style:
body {
padding: 0;
margin: 0;
background: url(images/bg-full.jpg) no-repeat center top;
width: 100%;
}
The CSS file that the publicmain node generates contains the following style, using the URL of the original image:
body {
padding: 0;
margin: 0;
background: url(../../../apps/myapp/clientlib/styles/images/bg-full.jpg) no-repeat center top;
width: 100%;
}
Using a Library for Specific Mobile Groups
Use the channels property of a client library folder to identify the mobile group that uses the library. The channels property is useful when libraries of the same category are designed for different device capabilities.
To associate a client library folder with a device group, add a property to your cq:ClientLibraryFolder node with the following attributes:
Name: channels
Type: String[]
Values: The name of the mobile group. To exclude the library folder from a group, prefix the name with an exclamation mark (“!”).
Name: embed
Type: String[]
Value: The value of the categories property of the cq:ClientLibraryFolder node to embed.
Using Embedding to Minimize Requests
In some cases you may find that the final HTML generated for typical page by your publish instance includes a relatively large number of <script> elements, particularly if your site is using client context information for analaytics or targeting. For example, in a non-optimized project you might find the following series of <script> elements in the HTML for a page:
<script type="text/javascript" src="/etc/clientlibs/granite/jquery.js"></script>
<script type="text/javascript" src="/etc/clientlibs/granite/utils.js"></script>
<script type="text/javascript" src="/etc/clientlibs/granite/jquery/granite.js"></script>
<script type="text/javascript" src="/etc/clientlibs/foundation/jquery.js"></script>
<script type="text/javascript" src="/etc/clientlibs/foundation/shared.js"></script>
<script type="text/javascript" src="/etc/clientlibs/granite/underscore.js"></script>
<script type="text/javascript" src="/etc/clientlibs/foundation/personalization/kernel.js"></script>
In such cases, it can be useful to combine all the required client library code in to a single file so that the number of back and forth requests on page load is reduced. To do this you can embed the required libraries into you app-specific client library using the embed property of the cq:ClientLibraryFolder node.
The following client library categories are incuded with AEM. You should embed only those that are required for he functioning of your particular site. However, you should maintain the order listed here:
- browsermap.standard
- browsermap
- jquery-ui
- cq.jquery.ui
- personalization
- personalization.core
- personalization.core.kernel
- personalization.clientcontext.kernel
- personalization.stores.kernel
- personalization.kernel
- personalization.clientcontext
- personalization.stores
- cq.collab.comments
- cq.collab.feedlink
- cq.collab.ratings
- cq.collab.toggle
- cq.collab.forum
- cq.cleditor
When you embed CSS files, the generated CSS code uses paths to resources that are relative to the embedding library. For example, the publicly-accessible library /etc/client/libraries/myclientlibs/publicmain embeds the/apps/myapp/clientlib client library:
The main.css file contains the following style:
body {
padding: 0;
margin: 0;
background: url(images/bg-full.jpg) no-repeat center top;
width: 100%;
}
The CSS file that the publicmain node generates contains the following style, using the URL of the original image:
body {
padding: 0;
margin: 0;
background: url(../../../apps/myapp/clientlib/styles/images/bg-full.jpg) no-repeat center top;
width: 100%;
}
Using a Library for Specific Mobile Groups
Use the channels property of a client library folder to identify the mobile group that uses the library. The channels property is useful when libraries of the same category are designed for different device capabilities.
To associate a client library folder with a device group, add a property to your cq:ClientLibraryFolder node with the following attributes:
Name: channels
Type: String[]
Values: The name of the mobile group. To exclude the library folder from a group, prefix the name with an exclamation mark (“!”).
For example, the following table lists the value of the channels property for each client library folder of the cq.widgetscategory:
Client library folder. Value of channels property
/libs/cq/analytics/widgets !touch
/libs/cq/analytics/widgets/themes/default !touch
/libs/cq/cloudserviceconfigs/widgets !touch
/libs/cq/searchpromote/widgets !touch
/libs/cq/searchpromote/widgets/themes/default [no value]
/libs/cq/touch/widgets touch
/libs/cq/touch/widgets/themes/default touch
/libs/cq/ui/widgets !touch
/libs/cq/ui/widgets/themes/default !touch
Using Preprocessors
AEM allows for pluggable preprocessors and ships with support for YUI Compressor for CSS and JavaScript and Google Closure Compiler (GCC) for JavaScript with YUI set as AEM’s default preprocessor.
The pluggable preprocessors allow for flexible usage including:
Defining ScriptProcessors that can process script sources
Processors are configurable with options
Processors can be used for minification, but also for non-minified cases
The clientlib can define which processor to use
Note:
By default, AEM uses the YUI Compressor. Switching to GCC compressor for particular clientlibs may solve some issues observed when using YUI.
Caution:
Do not place a minified library in a client library. Instead provide the raw library and if minification is required, use the options of the preprocessors.
Usage
You can choose to configure the preprocessors configuration per clientlibrary or system-wide.
Add the multivalue properties cssProcessor and jsProcessor on the clientlibrary node
Or define the system default configuration via the HTML Library Manager OSGi configuration
A preprocessor configuration on the clientlib node takes precedence over the OSGI configuration.
Format and Examples
Format
config:= mode ":" processorName options*;
mode:= "default" | "min";
processorName := "none" | <name>;
options := ";" option;
option := name "=" value;
YUI Compressor for CSS Minification and GCC for JS
cssProcessor: ["default:none", "min:yui"]
jsProcessor: ["default:none", "min:gcc;compilationLevel=advanced"]
Typescript to Preprocess and Then GCC to Minify and Obfuscate
jsProcessor: [
"default:typescript",
"min:typescript",
"min:gcc;obfuscate=true"
]
Additional GCC Options
failOnWarning (defaults to "false")
languageIn (defaults to "ECMASCRIPT5")
languageOut (defaults to "ECMASCRIPT5")
compilationLevel (defaults to "simple") (can be "whitespace", "simple", "advanced")
Set System Default Minifier
YUI is set as the default minifier in AEM. To change this to GCC, follow these steps.
Go to Apache Felix Config Manager at http://localhost:4502/system/console/configMgr
Find and edit the Adobe Granite HTML Library Manager.
Enable the Minify option (if not already enabled).
Set the value JS Processor Default Configs to min:gcc.
Options can be passed if separated with a semicolon e.g. min:gcc;obfuscate=true.
Click Save to save the changes.
Debugging Tools
AEM provides several tools for debugging and testing client library folders.
See Embedded Files
To trace the origin of embedded code, or to ensure that embedded client libraries are producing the expected results, you can see the names of the files that are being embedded at runtime. To see the file names, append the debugClientLibs=trueparameter to the URL of your web page. The library that is generated contains @import statements instead of the embedded code.
Client library folder. Value of channels property
/libs/cq/analytics/widgets !touch
/libs/cq/analytics/widgets/themes/default !touch
/libs/cq/cloudserviceconfigs/widgets !touch
/libs/cq/searchpromote/widgets !touch
/libs/cq/searchpromote/widgets/themes/default [no value]
/libs/cq/touch/widgets touch
/libs/cq/touch/widgets/themes/default touch
/libs/cq/ui/widgets !touch
/libs/cq/ui/widgets/themes/default !touch
Using Preprocessors
AEM allows for pluggable preprocessors and ships with support for YUI Compressor for CSS and JavaScript and Google Closure Compiler (GCC) for JavaScript with YUI set as AEM’s default preprocessor.
The pluggable preprocessors allow for flexible usage including:
Defining ScriptProcessors that can process script sources
Processors are configurable with options
Processors can be used for minification, but also for non-minified cases
The clientlib can define which processor to use
Note:
By default, AEM uses the YUI Compressor. Switching to GCC compressor for particular clientlibs may solve some issues observed when using YUI.
Caution:
Do not place a minified library in a client library. Instead provide the raw library and if minification is required, use the options of the preprocessors.
Usage
You can choose to configure the preprocessors configuration per clientlibrary or system-wide.
Add the multivalue properties cssProcessor and jsProcessor on the clientlibrary node
Or define the system default configuration via the HTML Library Manager OSGi configuration
A preprocessor configuration on the clientlib node takes precedence over the OSGI configuration.
Format and Examples
Format
config:= mode ":" processorName options*;
mode:= "default" | "min";
processorName := "none" | <name>;
options := ";" option;
option := name "=" value;
YUI Compressor for CSS Minification and GCC for JS
cssProcessor: ["default:none", "min:yui"]
jsProcessor: ["default:none", "min:gcc;compilationLevel=advanced"]
Typescript to Preprocess and Then GCC to Minify and Obfuscate
jsProcessor: [
"default:typescript",
"min:typescript",
"min:gcc;obfuscate=true"
]
Additional GCC Options
failOnWarning (defaults to "false")
languageIn (defaults to "ECMASCRIPT5")
languageOut (defaults to "ECMASCRIPT5")
compilationLevel (defaults to "simple") (can be "whitespace", "simple", "advanced")
Set System Default Minifier
YUI is set as the default minifier in AEM. To change this to GCC, follow these steps.
Go to Apache Felix Config Manager at http://localhost:4502/system/console/configMgr
Find and edit the Adobe Granite HTML Library Manager.
Enable the Minify option (if not already enabled).
Set the value JS Processor Default Configs to min:gcc.
Options can be passed if separated with a semicolon e.g. min:gcc;obfuscate=true.
Click Save to save the changes.
Debugging Tools
AEM provides several tools for debugging and testing client library folders.
See Embedded Files
To trace the origin of embedded code, or to ensure that embedded client libraries are producing the expected results, you can see the names of the files that are being embedded at runtime. To see the file names, append the debugClientLibs=trueparameter to the URL of your web page. The library that is generated contains @import statements instead of the embedded code.
In the example in the previous Embedding Code From Other Libraries section, the /etc/client/libraries/myclientlibs/publicmain client library folder embeds the /apps/myapp/clientlib client library folder. Appending the parameter to the web page produces the following link in the web page’s source code:
<link rel="stylesheet" href="/etc/clientlibs/mycientlibs/publicmain.css">
Opening the publicmain.css file reveals the following code:
@import url("/apps/myapp/clientlib/styles/main.css");
<p”>Use the following procedure to see the names of embedded files:</p”>
In the address box of your web browser, append the following text to the URL of your HTML:?debugClientLibs=true
When the page loads, view the page source.
Click the link that is provided as the href for the link element to open the file and view the source code.
Discover Client Libraries
The /libs/cq/ui/components/dumplibs/dumplibs component generates a page of information about all client library folders on the system. The /libs/cq/ui/content/dumplibs node has the component as a resource type. To open the page, use the following URL (use a different host and port as required):
http://localhost:4502/libs/cq/ui/content/dumplibs.test.html
<link rel="stylesheet" href="/etc/clientlibs/mycientlibs/publicmain.css">
Opening the publicmain.css file reveals the following code:
@import url("/apps/myapp/clientlib/styles/main.css");
<p”>Use the following procedure to see the names of embedded files:</p”>
In the address box of your web browser, append the following text to the URL of your HTML:?debugClientLibs=true
When the page loads, view the page source.
Click the link that is provided as the href for the link element to open the file and view the source code.
Discover Client Libraries
The /libs/cq/ui/components/dumplibs/dumplibs component generates a page of information about all client library folders on the system. The /libs/cq/ui/content/dumplibs node has the component as a resource type. To open the page, use the following URL (use a different host and port as required):
http://localhost:4502/libs/cq/ui/content/dumplibs.test.html
The information includes the library path and type (CSS or JS), and the values of the library attributes, such as categories and dependencies. Subsequent tables on the page show the libraries in each category and channel.
See Generated Output
The dumplibs component includes a test selector that displays the source code that is generated for ui:includeClientLib tags. The page includes code for different combinations of js, css, and themed attributes.
Use one of the following methods to open the Test Output page:
See Generated Output
The dumplibs component includes a test selector that displays the source code that is generated for ui:includeClientLib tags. The page includes code for different combinations of js, css, and themed attributes.
Use one of the following methods to open the Test Output page:
From the dumplibs.html page, click the link in the Click here for output testing text.
Open the following URL in your web browser (use a different host and port as required):http://localhost:4502/libs/cq/ui/content/dumplibs.html
The default page shows output for tags with no value for the categories attribute.
To see the output for a category, type the value of the client library’s categories property and click Submit Query.
Configuring Library Handling for Development and Production
The HTML Library Manager service processes cq:ClientLibraryFolder tags and generates the libraries at runtime. The type of environment, development or production, determines how you should configure the service:
Increase security: Disable debugging
Improve performance: Remove whitespace and compress libraries.
Improve readability: Include whitespace and do not compress.
Open the following URL in your web browser (use a different host and port as required):http://localhost:4502/libs/cq/ui/content/dumplibs.html
The default page shows output for tags with no value for the categories attribute.
To see the output for a category, type the value of the client library’s categories property and click Submit Query.
Configuring Library Handling for Development and Production
The HTML Library Manager service processes cq:ClientLibraryFolder tags and generates the libraries at runtime. The type of environment, development or production, determines how you should configure the service:
Increase security: Disable debugging
Improve performance: Remove whitespace and compress libraries.
Improve readability: Include whitespace and do not compress.
No comments:
Post a Comment
If you have any doubts or questions, please let us know.