Running an existing Angular app on Liferay DXP makes the app available as a widget for using on site pages. You can adapt your existing Angular app, but this doesn’t give you access to the bundler and its various loaders to develop your project further in Liferay DXP. To have access to all of Liferay DXP’s features, you must use the Liferay JS Generator and Liferay npm Bundler to merge your files into a portlet bundle, adapt your routes and CSS, and deploy your bundle.
Figure 1: Apps like this Guestbook app are easy to migrate to Liferay DXP.
Follow these steps:
-
Using npm, install the Liferay JS Generator:
npm install -g yo generator-liferay-js
-
Generate an Angular-based portlet bundle project for deploying your app to your Liferay DXP installation.
yo liferay-js
Select
Angular based portlet
and opt for generating sample code. Here’s the bundle’s structure:[my-angular-portlet-bundle]
assets/
→ CSS, HTML templates, and resourcescss/
→ CSS filesstyles.css
→ Default CSS file
app/
→ HTML templatesapp.component.html
→ Root component template
features/
→ Liferay DXP bundle featureslocalization/
→ Resource bundlesLanguage.properties
→ Default language keys
src/
→ JavaScript an TypeScript filesapp/
→ Application modules and Componentsapp.component.ts
→ Main componentapp.module.ts
→ Root moduledynamic.loader.ts
→ Loads an Angular component dynamically for the portlet to attach to
types/
LiferayParams.ts
→ Parameters passed by Liferay DXP to the JavaScript module
index.ts
→ Main module invoked by the “bootstrap” module to initialize the portletpolyfills.ts
→ Fills in browser JavaScript implementation gaps
package.json
→ npm bundle configurationREADME.md
.npmbuildrc
→ Build configuration.npmbundlerrc
→ Bundler configurationtsconfig.json
→ TypeScript configuration
-
Copy your app files, matching the types listed below, into your new project.
File type Destination Comments HTML assets/app/
Merge your main component with the existing app.component.html
.CSS assets/css/
Overwrite styles.css
.TypeScript and JavaScript src/app/
Merge with all files except app.module.ts
—the root module merge is explained in a later step. -
Update your component class
templateUrl
s to use theweb-context
value declared in your project’s.npmbundlerrc
file. Here’s the format:templateUrl: `/o/[web-context]/app/[template]`
Here’s an example:
templateUrl: '/o/my-angular-guestbook/app/add-entry/add-entry.component.html'
-
Update your bundle to use portlet-level styling.
-
Import all component CSS files through the CSS file (default is
styles.css
) your bundle’spackage.json
file sets for your portlet. Here’s the default setting:"portlet": { "com.liferay.portlet.header-portlet-css": "/css/styles.css", ... }
-
Remove
selector
andstyleUrls
properties from your component classes.
-
-
In your routing module’s
@NgModule
decorator, configure the router optionuseHash: true
. This tells Angular to use client-side routing in the form of.../#/[route]
, which prevents client-side parameters (i.e., anything after#
) from being sent back to Liferay DXP.For example, your routing module class
@NgModule
decorator might look like this:@NgModule({ imports: [RouterModule.forRoot(routes, {useHash: true})], exports: [RouterModule] }) export class AppRoutingModule { }
-
Also in your routing module, export your view components for your root module (discussed next) to use. For example,
export const routingComponents = [ViewComponent1, ViewComponent2]
-
Merge your root module with
src/app/app.module.ts
, configuring it to dynamically load components.-
Import the
routingComponents
constant and the app routing module class from your app routing module. For example,import { AppRoutingModule, routingComponents } from './app-routing.module';
-
Specify the base href for the router to use in the navigation URLs.
import { APP_BASE_HREF } from '@angular/common'; ... @NgModule({ ... providers: [{provide: APP_BASE_HREF, useValue: '/'}] })
-
Declare the
routingComponents
constant in your@NgModule
decorator.@NgModule({ declarations: [ routingComponents, ... ], ... })
-
Make sure your
@NgModule
bootstrap
property has no components. All components are loaded dynamically using theentryComponents
array property. The emptyngDoBootstrap()
method nullifies the default bootstrap implementation.@NgModule({ ... entryComponents: [AppComponent], bootstrap: [], ... }) export class AppModule { ngDoBootstrap() {} ... }
Your root module
app.module.ts
should look like this:import { APP_BASE_HREF } from '@angular/common'; import { AppRoutingModule, routingComponents } from './app-routing.module'; // more imports ... @NgModule({ declarations: [ AppComponent, routingComponents, // more declarations ... ], imports: [ AppRoutingModule, // more imports ... ], entryComponents: [AppComponent], providers: [{provide: APP_BASE_HREF, useValue: '/'}], bootstrap: [], // more properties ... }) export class AppModule { ngDoBootstrap() {} // ... }
-
-
Merge your app
package.json
file’sdependencies
anddevDependencies
into the bundle’spackage.json
. -
Finally, deploy your bundle:
npm run deploy
Congratulations! Your Angular app is deployed and now available as a widget that you can add to site pages.
The Liferay npm Bundler confirms the deployment:
Report written to liferay-npm-bundler-report.html
Deployed my-angular-guestbook-1.0.0.jar to c:\git\bundles
The Liferay DXP console confirms your bundle started:
2019-03-22 20:17:53.181 INFO [fileinstall-C:/git/bundles/osgi/modules][BundleStartStopLogger:39] STARTED my-angular-guestbook_1.0.0 [1695]
To find your widget, select the Add icon
(),
navigate to Widgets and then the category you specified to the Liferay Bundle
Generator (Sample is the default category).