Monday, November 14, 2016

Basic integration of Angular 2 project generated via Angular-CLI with NodeJS

Angular 2 is an amazing platform, and Angular-CLI is a fantastic way to start an Angular 2 project. Generating a project via Angular-CLI gives you a client-side code. This code needs to be served up from the server and a lot of people seem to question how exactly this should be done. I see this question pops up often so I decided to write a quick post about wiring the output that angular-CLI generates with NodeJS. In particular, this example shows how to wire things up with the ExpressJS server.

Below is a basic folder structure that we'll end up with:
/pathTo/MyAwesomeProject
  /client
  /server

The two folders - /client, and /server will have completely independent projects inside with their own package.json files.

Generate client-side code


let's start by generating the client side project:
> cd /pathTo/MyAwesomeProject
> ng new client
> cd client
> ng build
Notice that we didn't create the directory /client manually. We just navigated in the /MyAwesomeProject directory and Angular-CLI generated directory /client for us. Then we navigated into the /client directory and executed the Angular-CLI build command. At this point, we have the dist directory that contains client-side code ready to be served from the web server.

Generate server-side code


Now let's create the server. Do manually create /server directory. Then execute commands below:
> cd /pathTo/MyAwesomeProject/server
> npm init -f
> npm i --save express
Command npm init -f will generate package.json file for us. Then we'll install ExpressJS dependency.

package.json specifies index.js file as an entry point for nodejs. So let's create index.js file and write basic ExpressJS server code in it:
var express = require('express');

var app = express();

var server = app.listen(3000, function() {
  var port = server.address().port;
  console.log('App is listening on port:' + port);
});
The code above creates the server, but it does not do anything yet. Now comes the interesting part. Let's wire it up to serve client-side resources.

Wire up server with client


Add one more require statement to the top of our server-side code:
var path = require('path');
Then add the code below after declaring the app variable:
var app = express();

var clientRoot = path.resolve(__dirname, '..', 'client', 'dist');
var indexPath = path.join(clientRoot, 'dist', 'index.html');
app.use(express.static(clientRoot));

app.get('/', function (req, res, next) {
  res.sendFile(indexPath);
});
We are done! The code above tells ExpressJS that all files in the /client/dist/ directory should be allowed to be served if requested for. Further, we tell ExpressJs to serve the index.html page from the dist directory if the root URL is hit. Now see if the code works:
> node index.js

Navigate in your browser to localhost:3000 and you should see "app works!".

Bonus: utilize Angular-CLI's serve command for browser auto-refresh


Angular-CLI's serve command is very convenient with its browser synchronization feature. We'd like to utilize it during the development. However, running this command as-is will start Angular-CLI's own server, when we'd like to use server we created. This can easily be achieved by using --proxy-config option.

In the /client directory create file proxy.conf.json with the following contents:
{
  "/api": {
    "target": "http://localhost:3000",
    "secure": false
  }
}
Now, if you run the command below while in the /client directory, all requests starting with /api will be routed to our real server, and the browser will automatically refresh on any client-side changes.
> ng serve --proxy-config proxy.conf.json
Of course, before executing the command above you should make sure that your server is running.
Also remember to observe changes in your browser on port 4200 (localhost:4200), not 3000. This is the default port on which Angular-CLI serves client side code.

This command is a bit lengthy and it's easy to forget to append the proxy option every time you want to run it. This is a perfect use case for npm scripts. In the /client/package.json file modify the start script to include the proxy option. Now, you can simply type npm start and your client side code will be served with the correct configuration.

Final comments


The code above is a simple proof of concept. There is a lot of room for improvement left. I usually write my server-side code in TypeScript, thus have a separate build process for it. Add hot module reloading to server-side code, and many more shenanigans that make development a pleasant process.

Hope you found this post useful.