Building Angular WebBundle for Apache Karaf

Apache Karaf is a complete applications container, supporting several programming models: OSGi, DS, Blueprint, Spring, …

It’s also a complete web application container like Apache Tomcat, but providing some unique feature. If Apache Karaf supports WAR, it also supports Web Bundle. A Web Bundle is basically a bundle with a specific header.

For web application frontend, Angular is popular framework (used in combination with Bootstrap). It’s possible to write Angular directly by hand, but, most of the time, web developers prefer to use IDE like WebStorm.
In any case, Angular CLI (https://github.com/angular/angular-cli) is a “classic” tool to test and build your Angular application.

Project with Angular CLI

Angular CLI allows you to quickly start your Angular project.

You can bootstrap using the following command:

$ ng new test-frontend

Then, Angular CLI (ng) creates all required resources:

  create test-frontend/README.md (1028 bytes)  create test-frontend/.angular-cli.json (1248 bytes)  create test-frontend/.editorconfig (245 bytes)  create test-frontend/.gitignore (544 bytes)  create test-frontend/src/assets/.gitkeep (0 bytes)  create test-frontend/src/environments/environment.prod.ts (51 bytes)  create test-frontend/src/environments/environment.ts (387 bytes)  create test-frontend/src/favicon.ico (5430 bytes)  create test-frontend/src/index.html (299 bytes)  create test-frontend/src/main.ts (370 bytes)  create test-frontend/src/polyfills.ts (3114 bytes)  create test-frontend/src/styles.css (80 bytes)  create test-frontend/src/test.ts (642 bytes)  create test-frontend/src/tsconfig.app.json (211 bytes)  create test-frontend/src/tsconfig.spec.json (283 bytes)  create test-frontend/src/typings.d.ts (104 bytes)  create test-frontend/e2e/app.e2e-spec.ts (295 bytes)  create test-frontend/e2e/app.po.ts (208 bytes)  create test-frontend/e2e/tsconfig.e2e.json (235 bytes)  create test-frontend/karma.conf.js (923 bytes)  create test-frontend/package.json (1298 bytes)  create test-frontend/protractor.conf.js (722 bytes)  create test-frontend/tsconfig.json (363 bytes)  create test-frontend/tslint.json (3012 bytes)  create test-frontend/src/app/app.module.ts (316 bytes)  create test-frontend/src/app/app.component.css (0 bytes)  create test-frontend/src/app/app.component.html (1141 bytes)  create test-frontend/src/app/app.component.spec.ts (986 bytes)  create test-frontend/src/app/app.component.ts (207 bytes)> uws@9.14.0 install /home/jbonofre/Workspace/test-frontend/node_modules/uws> node-gyp rebuild > build_log.txt 2>&1 || exit 0> node-sass@4.7.2 install /home/jbonofre/Workspace/test-frontend/node_modules/node-sass> node scripts/install.jsCached binary found at /home/jbonofre/.npm/node-sass/4.7.2/linux-x64-59_binding.node> uglifyjs-webpack-plugin@0.4.6 postinstall /home/jbonofre/Workspace/test-frontend/node_modules/webpack/node_modules/uglifyjs-webpack-plugin> node lib/post_install.js> node-sass@4.7.2 postinstall /home/jbonofre/Workspace/test-frontend/node_modules/node-sass> node scripts/build.jsBinary found at /home/jbonofre/Workspace/test-frontend/node_modules/node-sass/vendor/linux-x64-59/binding.nodeTesting binaryBinary is fineadded 1272 packages in 65.41sProject 'test-frontend' successfully created.

You can test your project using:

$ ng serve** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **Date: 2018-03-02T10:01:07.769Z                                                          Hash: a130567e5011eb653504Time: 8240mschunk {inline} inline.bundle.js (inline) 3.85 kB [entry] [rendered]chunk {main} main.bundle.js (main) 17.9 kB [initial] [rendered]chunk {polyfills} polyfills.bundle.js (polyfills) 549 kB [initial] [rendered]chunk {styles} styles.bundle.js (styles) 41.5 kB [initial] [rendered]chunk {vendor} vendor.bundle.js (vendor) 7.42 MB [initial] [rendered]webpack: Compiled successfully.

You can access your web application directly in your browser and all change is taken on the fly.

If you want to generate “static” web application (converting your Angular project as a set of html and js files), you can use:

$ ng buildDate: 2018-03-02T10:03:36.703Z                                                          Hash: 9de4cb2f98111fe59f9eTime: 9459mschunk {inline} inline.bundle.js, inline.bundle.js.map (inline) 3.89 kB [entry] [rendered]chunk {main} main.bundle.js, main.bundle.js.map (main) 7.39 kB [initial] [rendered]chunk {polyfills} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 202 kB [initial] [rendered]chunk {styles} styles.bundle.js, styles.bundle.js.map (styles) 14.5 kB [initial] [rendered]chunk {vendor} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.44 MB [initial] [rendered]

ng build generates all static content in a dist folder. You will find here a index.html file with all other resources (js files, …).

Building Angular application ready to be deployed in Apache Karaf

Now, we want to “automatize” this build using Apache Maven. The purpose is to:

  1. perform ng build to create the resources in the dist folder
  2. package this resource as a Web Bundle

Our Maven pom.xml will contain basically three plugin executions:

  1. maven-antrun-plugin to perform the ng build
  2. maven-bundle-plugin to package as a WebBundle
  3. maven-clean-plugin to clean all created folder

Here’s the pom.xml doing so:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>net.nanthrax</groupId>    <artifactId>test-frontend</artifactId>    <version>1.0-SNAPSHOT</version>    <packaging>bundle</packaging>    <build>        <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-antrun-plugin</artifactId>                <version>1.8</version>                <executions>                    <execution>                        <id>ng-build</id>                        <phase>generate-resources</phase>                        <goals>                            <goal>run</goal>                        </goals>                        <configuration>                            <target>                                <mkdir dir="target"/>                                <echo message="Generating frontend resource"/>                                <exec executable="ng">                                    <arg value="build"/>                                </exec>                            </target>                        </configuration>                    </execution>                </executions>            </plugin>            <plugin>                <groupId>org.apache.felix</groupId>                <artifactId>maven-bundle-plugin</artifactId>                <version>3.3.0</version>                <inherited>true</inherited>                <extensions>true</extensions>                <configuration>                    <instructions>                        <Web-ContextPath>/angular-test</Web-ContextPath>                        <Private-Package>*</Private-Package>                        <Include-Resource>dist</Include-Resource>                    </instructions>                </configuration>            </plugin>        </plugins>        <pluginManagement>            <plugins>                <plugin>                    <groupId>org.apache.maven.plugins</groupId>                    <artifactId>maven-clean-plugin</artifactId>                    <configuration>                        <directory>dist</directory>                        <directory>target</directory>                    </configuration>                </plugin>            </plugins>        </pluginManagement>    </build></project>

The most important parts are:

  • Web-ContextPath is the context path of our web application.
  • Include-Resource uses the resources content generated by ng build.

We can now build our bundle, simply using:

$ mvn clean install

Deployment in Apache Karaf

Now, the deployment is pretty simple in Apache Karaf.

On a running Karaf instance, you just have to install the war feature:

karaf@root()> feature:install war

Now, we directly install our WebBundle:

karaf@root()> bundle:install -s mvn:net.nanthrax/test-frontend/1.0-SNAPSHOTBundle ID: 87

We can see the web application available:

karaf@root()> web:listID │ State       │ Web-State   │ Level │ Web-ContextPath │ Name───┼─────────────┼─────────────┼───────┼─────────────────┼───────────────────────────────87 │ Active      │ Deployed    │ 80    │ /angular-test   │ test-frontend (1.0.0.SNAPSHOT)

And we can access the application directly using a browser on the Karaf HTTP service (listening on 8181 by default): http://localhost:8181/angular-test

Conclusion

Thanks to the Maven build, we can now setup continuous integration (using Jenkins for instance).

A good improvement could be to wrap this Angular web application in a Karaf feature, automatically installing the war feature and our webbundle.

Comments

Popular posts from this blog

Quarkus and "meta" extension

Getting started with Apache Karaf Minho

Apache Karaf Minho and OpenTelemetry