Requirejs and AEM 6. Kiss.

Requirejs and AEM 6. Kiss.

Following the KISS principle, let's get requirejs working inside AEM.

Table of Contents

  1. Getting Started with Requirejs and AEM

Getting Started with Requirejs and AEM

Setup

Create project using maven archetype

Instructions for doing this can be found at the docs.adobe.com

Simplified approach

    Using Eclipse (Luna)

  1. Click New -> Maven Project
  2. Ensure Create a simple project (skip archetype selection) is not checked then click Next
  3. Click Configure -> Add Remote Catalog. Enter http://repo.adobe.com/nexus/content/groups/public/ in the Catalog File Textbox. Put any name for Description (i.e. Adobe). Click OK
  4. Select the newly created Catalog Item in the dropdown. In the main box you should now see a few options. If you do not see aem-project-archetype under Artifact Id, then an error has occurred.
  5. Select aem-project-archetype (I'm using version 10) -> Click Next
  6. Here we need to specify some properties, remember kiss...

    Group Idmygroup
    Artifact Idmyartifact
    artifactNameartifact
    packageGrouppackage
    appsFolderNameapps
    contentFolderNamecontent
    cssIdcssId
    componentGroupNamecomponentGroup
    siteNamesite
  7. Click Finish

Okay, so now we have made it through creating the maven archetype

Getting Requirejs

Download Requirejs here

Setup Requirejs

  1. Copy folder clientlib-all (located at: /ui.apps/target/classes/etc/designs/apps/clientlib-all)
  2. Paste to /ui.apps/target/classes/etc/designs/apps and Rename to clientlib-vendor
  3. Create folder "js" under clientlib-vendor
  4. Create folder "vendor" under js
  5. Modify .content.xml file
    categories="[cssId.vendor]" dependencies="[jquery]"
  6. Put the requirejs file into clientlib-vendor/js/vendor (mine is named require.js) I am using version 2.1.17

Setup jQuery

  1. Create a file named require-configuration.js under clientlib-vendor/js
    In AEM, jQuery ($) is defined globally, but requirejs tries to minimize things in the global namespace. We will need to make jQuery a module to be used inside of requirejs modules.
    (function (){
                'use strict';
                define(
                    'jquery',
                    [],
                    function() {
                        return jQuery;
                });
            }());
    For more information about this go here

Wire Up Clientlibs

  1. Create a js.txt file under clientlib-vendor
    Add
                #base=js
                vendor/require.js
                require-configuration.js
            
    At this point your vendor client lib structure should look like this:

    Ignore the ember.js files, they are not needed for this tutorial

Setup AEM

  1. In headlibs.html under /apps/apps/components/structure/page/partials
    Add
    <sly data-sly-use.clientLib="/libs/granite/sightly/templates/clientlib.html" 
        data-sly-call="${clientLib.js @ categories='cssId.vendor'}" data-sly-unwrap/>

Simple Test

  1. Create a component under /apps/components/content (I named it testcomponent)
  2. Create a clientlib folder and a js.txt file inside the newly created component
    Inside js.txt Add
                #base=js
                test.js
            
  3. Create a test.js file under the clientlib folder
  4. Create/Modify .context.xml file under the clientlib folder
    Add
    categories="[cssId.test]"
  5. Create/Modify testcomponent.html
    Add
    <h3 id="test-me">test component</h3>
    This is what your file structure should look like:
  6. Modify .content.xml under /ui.content/src/main/content/jcr_root/content/content/en (This is under the ui.content project)
    Add
    <testcomponent
        jcr:primaryType="nt:unstructured"
        sling:resourceType="apps/components/content/testcomponent"/>
    I put this in between servicecomponent and title_1 but it doesn't really matter where you put it.
  7. Modify .content.xml file under /ui.apps/src/main/content/jcr_root/etc/designs/ (This is in the ui.apps project)
    Add cssId.test like this:
    embed="[cssId.site,cssId.page,cssId.topnav,cssId.colctrl,cssId.textimage,cssId.test]"
  8. Modify the test.js file under /apps/components/content/testcomponent/clientlib/js
    Add
    //test to make sure require and jquery are working together
    require(['jquery'], function( $ ) {
        console.log( $('#test-me').html() ); // prints test component
    });
    This will ensure we have jquery working with requirejs.
  9. Again, modify the test.js file under /apps/components/content/testcomponent/clientlib/js
    
        define('Spaceship',['jquery','module'], function( $, module ) {
            var Spaceship = function(){
                //constructor
                var me = this;
                var equipment = {};
                equipment.weapon = (require.config.Spaceship != undefined)?require.config.Spaceship.defaults.weapon:'none';
                this.getEquipment = function(){
                    return equipment;
                };
            };
            Spaceship.prototype.shoot = function(){
                var me = this;
                var equipment = this.getEquipment();
                if(equipment.weapon === 'none'){
                    console.log('Retreat!');
                }else{
                    console.log(equipment.weapon + ' fires');
                }
            };
            return Spaceship;
        });
    
        require(['Spaceship'],function(Spaceship){
            require.config = {
                'Spaceship' :{
                    defaults: {
                        weapon : 'Laser Cannon'
                    }
                }
            };
            var warship = new Spaceship();
            warship.shoot();
            require.config = {
                'Spaceship' :{
                    defaults: {
                        weapon : 'none'
                    }
                }
            };
            var cargoship = new Spaceship();
            cargoship.shoot();
        });
  10. Now wrap everything inside test.js with
    (function() {
            //8. & 9. goes here
        })();
  11. Fire up your AEM 6 instance (I am using AEM 6 sp2)
  12. Build the project using mvn clean intall -PautoInstallPackage
  13. Open http://localhost:4502/editor.html/content/content/en.html and view console. Should see something like this:

Putting it all together

We created a project using a maven archetype. This created a sightly ready aem project.

When setting up Require js, we created a client lib to hold the require js files inside /etc... We defined jQuery as a Require js module in the require-configuration.js file which gets loaded immediately after the initial Require js file. This does not eliminate jQuery or $ from the global namespace, as would cause problems within AEM. We then "sightly included" theses files into the headlibs.html. Typically, js is loaded at the bottom but this is a simplified approach. It is possible to put the Require js files at the bottom but then any Require js modules would need deferred until the page is completely rendered or until Require js is loaded.

For the Simple Test, we created a test component and added client lib folder and test.js file. Inside this file, we added the testing criteria. In this test, all of the Require modules are in the same file. Usually each Require module has its own file. This is where AEM client libs shows its usefulness: by adding all the Require js module files into the js.txt and by using embed we can add all the client libraries, that are inside the component, to the main clientlib (cssId.all in this case which is loaded at the bottom of the page). So if we have many components, and they all have the category of cssId.test, they all will be appended to the main client file. No build tool required.

Taking a closer look at the Simple Test, there are a few things visible: a module name Spaceship is defined; the Spaceship module is required; require.config is used to set attributes for the Spaceship. Require.config can be useful if dealing with only one javascript object. In this case, using it for multiple objects may not be a best practice, but it can be seen how it acts as a global namespace for modules.

If you don't want to go through this whole process. I put my working copy on github at https://github.com/kuckmc01/aem-6-base. There is no guarantee that this working project will work by the time you see it.

Share this post

0 Comments

comments powered by Disqus