April 11, 2020
Estimated Post Reading Time ~

Part 2 - AEM with Angular 2 – Building project using Gulp and Maven

Angular 2 is modular in nature, what that means is there are a 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 the same way as regular AEM component. 

So this means 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 compile 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 to build script will compile typescript files, place them in a different folders 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 the 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 the “ui.apps” project which contains a major chunk of our code. Here is an expanded view of ui.apps project:


1. Page template - this is a folder (/structure/page) which contains page AppModule (https://angular.io/guide/bootstrapping) and renderer component (app or root component) for a template that we’ll be using for creating pages where we’ll drop Angular 2 components. This is a simple page template that has few columns and parsys where we can drop components. The only important thing to note here is the “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)
2. Components - this folder (/apps/ngaem/components/content) contains all AEM components including Angular 2 (e.g. ng-app, text-area) and non Angular components.
3. ng-app component - this is the main Angular 2 root component that will be bootstrapped by Angular 2 library when the application is loading. You can read more about what is root component in Angular 2 here: https://angular.io/guide/bootstrapping
4. text-area component - this an Angular 2 + AEM component that leverages the 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 learning how to develop AEM component using Angular 2
5. 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 the link: http://suryakand-shinde.blogspot.com/2017/06/dynamically-loading-of-angular-2.html
6. 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
7. lib folder (/etc/designs/ngaem/lib) - contains Angular 2 dependencies (javascript libraries)
8. build folder - Our gulp build script has 2 tasks “gulp build” and “gulp build:aem”. “gulp build” task will build a project so that we can run the Angular 2 project without deploying it to AEM (i.e. run like any regular Angular 2 application). This task (gulp build) will compile .ts file to JavaScript files, copy html templates for Angular 2 components, copy a different version of the “systemjs.config.js” file (that loads dependencies from /build/lib folder) and index.html into the build folder. You can run the generated application in build folder using the following command:
npm run start
9. 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 the application without deploying to AEM. “gulp build:aem” task will also do the 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:

@Component({
selector: 'text-area',
templateUrl: '/apps/ngaem/components/content/text-area/text.html'
})

Will be changed to following after “gulp build:aem” finishes:

core_1.Component({
selector: 'text-area',
templateUrl: '/bin/ngtemplate?path=/apps/ngaem/components/content/text-area/text.html'
})

10. 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 the project that can be deployed in AEM
11. tsconfig.json and typings.json - Configuration file for Typescript compiler. You can read more about various configuration options that you can use for customizing typescript compiler and instruct to load type definitions, refer this link https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html
12. 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 a dependency for Java projects in pom.xml)
13. 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”.


AngularTemplateServlet - Angular 2 components can have views either as part of the same Javascript file or it can be loaded from the external html file. To make it simpler and align with how we develop components in AEM we’ll load views from external files. Here is the Angular 2 component code snippet that shows how we load views in Angular 2 component from external html file:

@Component({
selector: 'text-area',
templateUrl: '/apps/ngaem/components/content/text-area/text.html'
})


As you can see, “templateUrl” property is trying to load the 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 the 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 the Angular 2 component. To this we need to update “templateUrl” property as follows:

core_1.Component({
selector: 'text-area',
templateUrl: '/bin/ngtemplate?path=/apps/ngaem/components/content/text-area/text.html'
})

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 a 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:

gulp build
This command will create a “build” directory under the 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:

<properties>
    <aem.host>localhost</aem.host>
    <aem.port>4502</aem.port>
    <aem.publish.host>localhost</aem.publish.host>
    <aem.publish.port>4503</aem.publish.port>
    <sling.user>admin</sling.user>
    <sling.password>admin</sling.password>
    <vault.user>admin</vault.user>
    <vault.password>admin</vault.password>
</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 an iframe and lead 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 projects like this. In the next part I’ll focus on component development, please stay tuned.



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.