When I started investigating (googling) web frontends, I found tutorials for various frameworks and I found tutorials using node.js to deliver frontends to web browsers on localhost.
What I did not find, was something telling me how I should pack up and deliver the webapp frontend from my production system, so that comes here:
- The initial HTML file references bundle.js
The above code example tries to find the element with id root in the DOM of the surrounding HTML file, and replacing it with the DOM of the <App/> react component (i.e. running the render() method of the component).
This means that for anything to appear in the HTML page there must be an element in the HTML page with id “root”. If not, react won’t find a place to start rewriting the DOM and won’t do anything.
|<title>Frontend Karaf Test</title>|
|<meta name="viewport" content="width=device-width, initial-scale=1.0"></meta>|
This page will load the bundle.js and contains the element <div id=”root” /> where react can start rewriting the DOM.
It is possible to serve this two part web application as static files, i.e. dropping the index.html and bundle.js files into a directory served by nginx or apache will be sufficient to make the webapp load and start rendering in a web browser.
The frontend people and most frontend tutorials use node.js to build the bundle.js and serve the index.html and the bundle.js. That’s fine for developing the actual frontend application, but not for delivering the application to the production enviroment.
Working in java my first thought was “how do I package up the frontend in a jar file that can be deployed to a maven repository?”. The rest of this article attempts to answer this question.
- The frontend-maven-plugin is used to build a bundle.js from the src/main/frontend/ directory of a project
<plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>1.6</version> <configuration> <nodeVersion>v10.4.0</nodeVersion> <workingDirectory>src/main/frontend</workingDirectory> <installDirectory>target</installDirectory> </configuration> <executions> <execution> <id>install node and npm</id> <goals> <goal>install-node-and-npm</goal> </goals> </execution> <execution> <id>npm install</id> <goals> <goal>npm</goal> </goals> </execution> <execution> <id>webpack build</id> <goals> <goal>webpack</goal> </goals> </execution> </executions> </plugin>
- The bundle.js created by frontend-maven-plugin is included as a resource in the jar (handled by having frontend-maven-plugin drop the bundle.js in the target/classes/ directory)
- The index.html file is put into src/main/resources/ and end up as a resource in the jar
- A servlet is added to the code. The servlet will return “index.html” for the request path “/” and otherwise look through the classpath for a match
And that’s it, basically.
Edit: I got tired of copy-pasting the above code, so I packed it up in a base class and deployed it to maven central. It’s available under the Apache v2 license (see also Simplified delivery of react.js from apache karaf)
You will need stuff to wire up your servlet to a path in the servlet container. This could e.g. be a web-inf/web.xml deployment descriptor of a war file, or it could be annotations of servlet 3.0. Personally I use the OSGi web whiteboard: the servlet becomes a declarative services (DS) component that is started and plugs into a path (web context) in the servlet container.
Another thing to consider, is if you use the react-router or similar to rewrite the URL when moving to a different page, then you would like to enter the frontend application at all of the paths matching a page.
Some frontend examples (all using OSGi web whiteboard):
- The frontend-karaf-demo (a single maven module creating a declarative services component plugging into the web whiteboard on the webcontext “frontend-karaf-demo” and would become available at http://localhost:8181/frontend-karaf-demo/ when being loaded into apache karaf)
- The authservice user administration GUI
- The ukelonn weekly allowance web application