Unbundling Spring (maven) bundled SPA (AngularJS)!

Time to move away from legacy code structure and use SPA’s the right way.

I recently joined a team and a project which has been running for a long time (~5 years). The simple overview of the project is Java Spring with AngularJS, I will leave out the rest of the technical details to shorten my story.

My example will be regarding AngularJS (which is very old already), but it can be used for any SPA.

The way the project was set up in regards to the UI part was that the AngularJS application was bundled into a maven module and “deployed” as jetty resource. So the folder structure looked like this:

folder structure

“OK, so what is the problem with that?”

The issue with it was that some type of container was needed to run the UI (jetty, tomcat…), additional Spring security configuration needed to expose the resources, project setup for new team-members was longer and in some parts unnecessary etc. But most of all we weren’t using the benefit of SPA and SPA development in terms of having standalone SPA which can be developed and deployed separately from the back-end world.

Obstacles when splitting them apart

Theoretically the task was pretty simple and straight forward. Just copy out the resources from the maven module and run it by either just opening index.html or in some kind of server (node, nginx, apache2…).

And as mentioned above most of the job was done just by doing that, but one obstacle needed to be tackled in order to run it smoothly. The application contained many relative paths to different resources, e.g. dynamic resources or the basic rest api resources. What this means is that wherever the application is deployed it will use this host in order to construct the urls for the resources.

My solution

In the showcase I will use localhost as host and my config files will be based on this, but they can be replaced easily by any host-names.

I decided to do a prototype using node-express as a server which ran the AngularJS application. I left the backend intact.

First I had to install node-express:

npm install express --save-dev

In order to make the resource calls successfully I needed a proxy, for which I used http-proxy-middleware, so I had to install that as well:

npm install http-proxy-middleware --save-dev

I had to adjust a little bit my package.json file to add a script to run the application:

...
"scripts": {
"start": "node server.js"
},
"main": "server.js",
...

And finally added the server.js file which configures the server with the proxy for the back-end resources. I added server.js on the same level in the directory structure with package.json.

The server.js is as follows:

var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/', express.static(__dirname + '/'));app.use('/<path-to-proxy>', proxy({target: process.env.PROXY_HOST, changeOrigin: true}));
app.use('/<another-path-to-proxy>', proxy({target: process.env.PROXY_HOST, changeOrigin: true}));
app.listen(8080, 'localhost');console.log("MyProject Server is Listening on port 8080");

I have highlighted the configuration for proxying the resources. Different and unlimited paths can be proxied. Anything under the specified path will also be proxied, meaning if the path is /api, /api/resource will also be proxied.

Finally the application can be run with the following command:

PROXY_HOST=<host-name> npm start

In my case <host-name> was http://localhost:8081. I hope this saves somebody’s time and nerves and we can nicely host the SPA’s as they are meant to be .

Conclusion

In a world where SPA’s are taking more and more place we still have some older applications which are misusing the SPA architecture. Therefore I hope you find this useful if you decide to do this split.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store