Part 2 - AEM with Angular 2 – Building project using Gulp and Maven
Angular 2 is modular in nature, what that means is there are number of smaller modules that you can choose to mix and match based on what is required in your project. When you are developing Angular 2 application outside of AEM this is not a big challenge in terms of building and shipping an Angular 2 application out of the door because there are many build tools (e.g. Angular 2 CLI) are available to take care of bundling and packaging these angular modules and dependencies. But, when we are in AEM, components are just building blocks and content authors can drag-drop these components anywhere and as many times as they need so, reusability is key i.e. authors should be able to use Angular 2 components in same way as regular AEM component. So this mean build tools that are available today for Angular 2 application can’t help because those tools need to know upfront where components have been used and then these tools compiles applications but, in AEM this is different because authors can drag and drop Angular 2 components anywhere on a page so after components have been developed by developers (as we discussed above).
To address this problem we need to write custom build script using gulp (we can use grunt as well) and Maven (gulp task will be invoked from Maven build using “exec-maven-plugin”). Before having a look at actual build scripts let’s look at project structure and then we’ll see how build script will compile typescript files, place them in different folder and package it for deployment in AEM.
Let’s get started!!!
I am using AEM Maven archetype for creating a multi-module maven project which contains following projects:
Out of these projects we’ll be focusing on 3 projects:
- “core” - contains servlet to render Angular 2 template, that we’ll see later in this series of tutorial
- “ui.apps” - contains template, pages, component, Angular 2 dependencies (in etc folder)
Project Structure - ui.apps
First we’ll look at “ui.apps” project which contains major chunk of our code. Here is expanded view of ui.apps project:
- Page template - this is folder (/structure/page) which contains page AppModule (https://angular.io/guide/bootstrapping) and renderer component (app or root component) for template that we’ll be using for creating pages where we’ll drop Angular 2 components. This is a simple page template which has few columns and parsys where we can drop components. The only important thing to note here is “systemjs.config.js” file (which is included in page’s head section) and this file is responsible for loading Angular 2 dependencies on page. We’ll talk more about “systemjs.config.js” file later in this article (point # 13)
- Components - this folder (/apps/ngaem/components/content) contains all AEM components including Angular 2 (e.g. ng-app, text-area) and non Angular components.
- ng-app component - this is the main Angular 2 root component that will be bootstrapped by Angular 2 library when application is loading. You can read more about what is root component in Angular 2 here: https://angular.io/guide/bootstrapping
- text-area component - this an Angular 2 + AEM component that leverages power of Angular 2 but, it is an AEM component that authors can drag and drop in parsys like any other AEM component. We’ll be discussing more and more about this component to learn how to develop AEM component using Angular 2
- Angular 2 dynamic component loader - this is an important file which allows us to render/load Angular 2 components dynamically in HTML DOM. If you want to read more about what is Dynamic Component loading and why we need it, please refer link: http://suryakand-shinde.blogspot.com/2017/06/dynamically-loading-of-angular-2.html
- main.ts - this is the first file that is loaded by “systemjs.config.js” while initializing Angular 2 application. It loads AppModule (will discuss it more on it later) which eventually loads root component and with the help of Dynamic Loader (that we discussed above) it loads other Angular 2 components
npm run start
- gulpfile.ts (frontend build script) - this file contains gulp build tasks (e.g. command: gulp build and build:aem). “gulp build” task will generate files and copy it into “build” folder so that we can run application without deploying to AEM. “gulp build:aem” task will also do same thing as “gulp build” task but, it’ll update “templateUrl” of Angular 2 components so that it leverages Sling Servlet (that we’ll talk later) to load Angular 2 component’s views. E.g before running this task if .ts file has:
Will be changes to following after “gulp build:aem” finishes:
- pom.xml (Maven file) - this file contains all Java dependencies for AEM project and maven plugin “exec-maven-plugin” to execute gulp task (gulp build:aem) during packaging (creating CRX package) of project that can be deployed in AEM
- package.json - this is a standard file for node project or projects that want to leverage node modules (like gulp, node typescript compiler etc.) for a project during build time. Since we are using Gulp and Typescript therefore we need this file. In this file we have defined node module dependencies (they way we define dependency for Java projects in pom.xml)
- systemjs.config.js - SystemJS config file that will load Angular 2 dependencies on AEM page template (from /etc/designs/ngaem/lib folder) and bootstrap Angular 2’s main module (AppModule) into HTML DOM
Project Structure - core
“Core” is another maven module/project which mainly contains Java code (OSGi Services, Sling Models, Filters, Servlet). For this tutorial the only important piece of code that we’ll be focusing on is “AngularTemplateServlet”.
As you can see, “templateUrl” property is trying to load template from /apps folder (which is possible but, not recommended). If we have to load views from /apps folder this means we have to expose our /apps folder for outside world and this might lead to serious problems. To overcome this, what I have done is, I have created a very simple Sling Servlet that reads content on html files in /apps/
and feeds it to Angular 2 component. To this we need to update “templateUrl” property as follows:
This path update is done by the gulp task “gulp build:aem” (which gets executed as part of maven build) so that you don’t have to do it manually.
So, now you know the project structure. Let’s look at some build commands that you’ll use to build project and test it either locally or in AEM.
Building & Testing Angular 2 components locally:
From your ui.apps project’s main directory (where package.json file is), you’ll need to run following command:
This command will create a “build” directory under ui.apps project. Once build is completed run following command to start lite-server (this is small nodejs server to serve html/js/css files locally) so that you can access index.html page via http://localhost:8000
npm run start
Building & Testing Angular 2 components in AEM:
From your ui.apps project’s main directory (where pom.xml file is), you’ll need to run following command:
mvn clean install -PautoInstallPackage
This command will create a CRX package in “target” directory and it’ll automatically install it in AEM. For automatic installation you need to make sure that pom.xml of parent project (not ui.apps) has correct values in properties section. For point to your local AEM installation running on 4502 you can use following properties:
Once build is complete successfully you can go to your AEM instance and navigate to http://localhost:4502/editor.html/content/ngaem/en.html?wcmmode=disabled to see the page.
NOTE: You need to add “wcmmode=disabled” in URL otherwise AEM will not bootstrap your application, this is because in EDIT/PREVIEW mode AEM pages are rendered inside iframe and leads to a situation where Angular application loaded via system.js is not able to bootstrap properly.
With this now you are aware of project structure, various files, build tasks and why we have organized project like this. In next part I’ll focus on component development, please stay tuned.
Github Project/Source Code: https://github.com/suryakand/aem-angular2
Thanks for reading!!!