Tuesday, January 17, 2012

How to use and debug CQ Client Library CQ5.4 / WEM

Use case:
1) You want to create your own client library (Only basic).
2) You want to debug performance of javascript
3) You want to list all client library
4) You want to have all your js and css in same location {No need to have it under /etc/design}

Solution:

To create your own client library

You can use structure like,

+ /apps/yourapp/ui [cq:Folder]
+ clientlib [cq:ClientLibrary]
- categories ["cq.widgets", "cq.wcm.edit", "cq.admin",<Or any category>]
- dependencies []
- type "js"
- js.txt [nt:file]
- channels []
- embed []
+ include.list [nt:file]
+ exclude.list [nt:file]
+ files [cq:Folder]
+ MyCustomeJs1.js [nt:file]
+ MyCustomeJs2.js [nt:file]
...
+ themes [cq:Folder]
+ default [cq:ClientLibrary]
- categories ["cq.widgets", "cq.wcm.edit", "cq.admin",<Or any category>]
- dependencies []
- type "css"
- css.txt
- channels []
- embed []
+ include.list [nt:file]
+ exclude.list [nt:file]
+ files [cq:Folder]
+ MyCustomeCSS1.css [nt:file]
+ MyCustomeCSS2.css [nt:file]

Additional descriptions of the cq:ClientLibrary properties (Information can not be 100% correct):

categories: List of tags or dynamic dependencies. If a category is used in the ClientLibraryManager.include() method, all cq:ClientLibrarys tagged with this category will be included in the html. See example below.
dependencies: A list of either categories or paths to cq:ClientLibrarys that have to be included in html before (and will be included automatically).
type: "css" or "js", hence <link rel='stylesheet'> or <script> in the html
includes.txt list file defines the concatenation order
exclude.txt That should not be included for concatenation
channels
- if no channels are specified, it's only assigned to all channels
- if multiple channels are specified, it's assigned to all those channels
- special keyword default can be used to specify the default channel
- if the channel name is prefixed with !, it is not used on that channel.
Example:
// all channels
channels: []
// only default channel
channels: ["default"]
// only on touch devices (/libs/cq/touch/redirect/notimplemented, /etc/designs/geometrixx/clientlibs/ie6/themes/default)
channels: ["touch"]
// not on touch devices (/etc/clientlibs/foundation/swfobject)
channels: ["!touch"]


Use Case:
touch devices
create a channel specific lib: cq.myWidget, channels=["touch"]
exclude that channel in the normal lib: cq.myWidget, channels=["!touch"]
create a channel detection script based on user agent
use it: <cq:inclideClientLibrary categories="cq.myWidget"/>

See one more example

/etc/designs/geometrixx/clientlibs/ie6/themes/default which is included /apps/geometrixx/components/asseteditor/headlibs.jsp


embed
A library can embed other libraries. This is useful to reduce the amount of includes or to bypass some access restrictions of libraries that reside in a read-protected area. For example the clientlibs of the foundation components are located in /libs/foundation/* but are needed on publish (which has /libs read protected for anonymous).
When a library defines categories to be embedded, if only embeds the direct dependencies that match the same type (obviously) and theme.
Example, /etc/designs/geometrixx/clientlibs has,
embed="[personalization,cq.collab.comments,cq.collab.feedlink,cq.collab.ratings,cq.collab.toggle,cq.collab.forum]"

allowProxy: (CQ5.6 Onward) true or false
The purpose is to serve client libs hosted under /libs and /apps
  • add the property: allowProxy = 'true' to a clientlib
  • the clientlib will then be proxied via /etc.clientlibs/..., bypassing access control set on the clientlib.
example: 
Assume you have clientlib in /apps/myproject/clientlibs/foo. then you set the property /apps/myprojects/clientlibs/foo/allowProxy to true and then you can request: /etc.clientlibs/myprojects/clientlibs/foo.js.


How to use custom client library

the libraries can either be included directly in the html,
eg:
<link rel="stylesheet" href="/libs/cq/ui/themes/default.css" type="text/css">
<script type="text/javascript" src="/libs/cq/ui/widgets.js"></script>

or via manager. eg:
ClientLibraryManager.include(out, "/libs/cq/ui/widgets");

or
ClientLibraryManager.include(out, "wcm.edit");

or using the tag library:
<cq:includeClientLib categories="cq.packaging"/>

using the manager or tag is of course favorable since if the ClientLibraryManager runs in debug mode, the concatenation is disabled.
To avoid duplicated inclusions when multiple libraries with dependencies are requested, the include method supports multiple paths or categories. Multiple requested libraries (through the API or through dependencies) will be only included once:

ClientLibraryManager.include(out, "wcm.edit", "wcm.admin", "wcm.edit");

How to Debug custom client library

By Using ?debugClientLibs=true (on a html page). This will load individual javascript and then you can use request analyzer to analyze each js.
By using ?debugConsole=true (on a html page) if you are using firebug

Since 5.4, there is a overview page available that lists all libraries and allows to test resolution.
see
http://<host>:4502/libs/cq/ui/content/dumplibs.html

See a good example here http://blogs.adobe.com/mtg/2011/11/building-components-in-adobe-cq-5-part-1-a-tutorial-on-clientlibs-using-jquery-ui.html

One more very good blog Post http://blogs.adobe.com/ADEP/2012/02/cq5-clientlib-explained-by-example.html

If you want to further minify js/css you can use "Day CQ HTML Library Manager" from felix configuration




Note This information is not a official documented information. Please test it before use.

Special thanks to Adobe and Alex from Adobe for providing this information.

13 comments:

  1. There is another cq:ClientLibrary property - "embed". Though can't find any info about it :(

    ReplyDelete
  2. Thanks for feedback .. I have added some information about this. Soon these information will be available on docs as well

    ReplyDelete
  3. Great thanks for "embed" section!
    Concatenates JS or CSS like a charm. This is exactly what we've been looking for for "individual styles and JS for each component" approach.

    ReplyDelete
  4. Awesome post! Lots of good information in there.

    Anyway to only include a client library in a particular WCMMode? For example, only include some JS when in preview or disabled mode?

    ReplyDelete
    Replies
    1. Just an Idea:
      Define multiple categories on the client library for each mode.
      For example: categories: [PREVIEW, DISABLED] and use

      in your html file.

      Delete
  5. Jordan,

    are you referring to if (editContext != null && WCMMode.fromRequest(request) == WCMMode.EDIT) . I don't think there is any tag lib for this.

    ReplyDelete
  6. Great post.

    Trying to find some information on

    currentDesign.writeCssIncludes(pageContext);

    Is used by the CQ base head.js template. Seems to pull all of the client libraries in the path of the current page node (both above and below the node) and add them into the page. I don't really understand the sense in that, so wondered how it's meant to be used?

    ReplyDelete
  7. Yogesh, I think it'd be very useful if there is a documentation bug raised for the how the ClientLib fully works on the day.com site. Is it possible to raise one? I don't have an active daycare account now.

    ReplyDelete
    Replies
    1. @Sarwar
      Yes there is already a documentation bug and it will get documented soon.

      Delete
  8. Nice Post. Thanks.
    How does the exclude.txt work. Currently there are lots of widget.js being included by clientlibrarymanager.js , how do we avoid some of these js files from being included.

    ReplyDelete
    Replies
    1. Hello,

      Easy way to remove them from js.txt file if they are not required. I need to update this document, I don't think include/exlude list and property is supported or implemented.

      Yogesh

      Delete
  9. Hi Yogesh,

    Is it possible to add custom attribute to cq:includeClientLib.

    Basically I want to add print media for the CSS file.

    Thanks,
    Bala

    ReplyDelete
    Replies
    1. Bala,

      Not out of box. However you can extend includeClientLib tag and process your custom attribute. for example something like and then you have to create custom tag lib extending inclideClientLibraryTag http://dev.day.com/content/docs/en/cq/current/javadoc/com/adobe/granite/ui/tags/IncludeClientLibraryTag.html

      Yogesh

      Delete