43

I found a great tutorial that explains how to setup express.js with Angular CLI, but in this tutorial the angular app is compiled into a production dist folder: https://scotch.io/tutorials/mean-app-with-angular-2-and-the-angular-cli

How do I integrate express.js with Angular CLI, but I want the express.js to work with the development version of the Angular app and I want the nodemon to restart if I make changes to either the express OR angular app.

Have been spending over eight hours trying to get this working. Thanks!

I don't want to run 'ng build' every time I make a change to the Angular app (this takes too long) - I want instant reloading whenever I save a change to my angular app (as if I was running 'ng serve') or express app.

I found a tutorial where you hook up Angular 2 QuickStart with Express, it works but I'm looking to use Angular CLI.

I understand that the Angular CLI uses WebPack whereas the QuickStart uses System.js

Graham
  • 7,431
  • 18
  • 59
  • 84
etayluz
  • 15,920
  • 23
  • 106
  • 151

7 Answers7

96

NEW ANSWER

My experience of 15 hours has taught me that trying to serve an Angular app with Express during development is NOT a good idea. The proper way is to run Angular and Express as two different apps on two different ports. Angular will be served on port 4200 and Express on port 3000 as usual. Then configure a proxy for API calls to Express app.

Add proxy.config.json to root of Angular project:

{
  "/api/*":{
    "target":"http://localhost:3000",
    "secure":false,
    "logLevel":"debug"
  }
}

Open up a new terminal tab and run this command to start Express app:

nodemon [YOUR_EXPRESS_APP.js] --watch server

(YOUR_EXPRESS_APP.js is usually named server.js or app.js. server is a directory where you keep all your Express app files)

Open up a second terminal tab and run this command to start Angular app:

ng serve --proxy-config proxy.config.json

This will ensure that Angular app is rebuilt and browser reloaded when a change is made to any Angular app file. Similarly, Express server will restart when a change is made to any Express app files.

Your Angular app is here: http://localhost:4200/

Watch this video to see how to configure a proxy for your API calls with Angular CLI

NOTE: this setup only applies for development environment. In production, you will want to run ng build and place the Angular app inside a dist directory to be served up by Express. In production, there is only ONE app running - an Express app serving up your Angular app.

PREVIOUS ANSWER

Using input from @echonax I came up with this solution which is quite fast:

  • Add Express to Angular 2 app (built with Angular CLI) as in this tutorial
  • Run this in terminal:

ng build -w & nodemon server.js --watch dist --watch server

This will rebuild the Angular app into the dist folder, and the node server will restart each time that happens. However, there is NOT automatic browser refresh with this setup :(

More on that here:

https://github.com/jprichardson/reload

etayluz
  • 15,920
  • 23
  • 106
  • 151
  • This helped me understand what ngCli was doing a ton. I don't want to pile on more answers onto here, but I ended up having a `backend` and `fronend` folder, copying over the index.html generated by `ng build`, and then running my server with just `node app.js` and my build assets server with `ng serve --live-reload=false`, so it wouldn't try to keep reconnecting to WDS. Looking into how I can redirect that request, but for now this seems to work and is similar to this answer, but with the back-end and front-end a little more separated – Jay Mar 23 '18 at 15:32
  • The Angular documentation now has good coverage of the proxy method described here. See [Proxying to a backend server](https://angular.io/guide/build#proxying-to-a-backend-server). – Daniel Jan 04 '19 at 04:43
  • I was working on the exact same issue. Can you elaborate on why you do not recommend serving Angular on express? My first idea was exactly your answer coupled with Yusuf's concurrent solution (5 hours spent reinventing a wheel..) But it occurred to me that serving Angular from express would be a more elegant solution since it would be just one service(?) and no proxies. Is it because of the ease of implementation, or it mirrors the production environment more correctly? Would love to hear your take on the issue. Thanks. – Namgyu Ho Apr 19 '19 at 18:39
16

"etayluz" solution is very good. But I want to add an additional option for NEW ANSWER to not opening two times terminal.

Firstly you have to install concurrently package (https://www.npmjs.com/package/concurrently);

npm install concurrently --save 

Then you could add below codes into your package.json file.

"start": "concurrently \"npm run serve-api\" \"npm run serve\"",
"serve": "ng serve --port 3333 --proxy-config proxy.config.json", // You could add --port for changing port
"serve-api": "nodemon [YOUR_EXPRESS_APP.js] --watch server",

npm start is enough for running your project.

yusuf
  • 1,233
  • 1
  • 15
  • 29
5

Using angular-cli, the ng build or ng build --prod command will give you bundled up files along with an index.html. Make your app.js(node/express) target this file.

Example:

app.use( express.static(__dirname + '/src' ) ); //<- it will automatically search for index.html under src folder.
eko
  • 39,722
  • 10
  • 72
  • 98
  • 'ng build' builds my Angular app into a dist folder. That takes time. I don't want to wait around so long and manually build the angular app every time I need to make a change. That's why I want something where express points to the development version of the Angular 2 app generated with Angular CLI. Is it possible? – etayluz Mar 20 '17 at 04:55
  • 1
    @etayluz If you add -w like `ng build -w` cli will watch for the changes happening on the client side and re-build again(according to the delta). Would that solve the issue? – eko Mar 20 '17 at 05:00
  • 'ng build -w' takes too long to run (like 10 seconds) I want instant reloading – etayluz Mar 20 '17 at 05:02
  • When I run 'ng serve' - every time I make a change the TS trans-pilation happens rather instantly; looking for that effect – etayluz Mar 20 '17 at 05:05
  • any ideas? I don't see anything online about this – etayluz Mar 20 '17 at 05:27
  • 2
    @etayluz nope :/ I'll leave my answer as is so that people will have an idea about the situation. Maybe you can file an issue for angular-cli about this topic? – eko Mar 20 '17 at 05:27
  • 3
    ng build --watch will take time on the first run, but it compiles in 1 or 2 seconds each time you make a change. – gyc Mar 20 '17 at 12:58
  • 1
    @gyc that was my experience as well, that's why I said "re-build again(according to the delta)" but I guess OP is having a different experience. – eko Mar 20 '17 at 13:05
  • Last question, how do I automatically reload the browser? – etayluz Mar 20 '17 at 15:14
  • Exactly what I did. Run ng-build into a static file set up in Express, then run nodemon from that dir, and it serves both server and Angular app perfectly. https://github.com/chriskavanagh/angularauth – Chris Kavanagh Jun 29 '18 at 05:09
2

Longer Explanation

I've spent a decent amount of time figuring out how to do this in my own development environments. The best I've come up with is a two fold implementation that combines a lot of echonax's, squirrelsareduck's, and Max's solution, but taking advantage of built in Angular CLI strategies to watch frontend/Angular changes, and using nodemon to watch the backend/Express changes. The short of it is you end up running two processes (ng build and nodemon) to get your development environment up and running, but it automatically rebuilds and runs everything under one Express web server.

The first process you will need to run will be to build the Angular dist folder, and watch any changes made to the Angular frontend. Luckily for us, Angular CLI can do this natively (Tested on Angular CLI >= 1.5) with the following command:

ng build --watch

You'll need to leave this running in the background, but this will watch for any changes made in the Angular code, and rebuild the bundles on the fly.

The second process involves using nodemon to run your Express server, and may take a little bit more setup and planning depending on how extensive your backend/Express setup is. Just make sure Express is pointing to your index file in the dist folder. The big advantage here is that you can add all of this into a Gulpfile with gulp-nodemon to do even more sequential tasks after running nodemon to watch the backend/Express such as linting your backend, running tests parallel to your builds, minifying your backend, or whatever else you can think of to use Gulp for. Use npm or Yarn to add and install nodemon to your project's dependencies, and then run the following to start your Express server:

nodemon app.js

Replace app.js with whatever file you're using to build your Express backend, and it should now rebuild anytime there are changes made to your backend.

tldr;

Run two separate processes in the background to start your development environment. First run:

ng build --watch

Second, add nodemon to your project dependencies, and run the following command in the background where app.js is replaced with whatever your Express file is called:

nodemon app.js

Bonus

Since you asked how to automatically reload the browser, your best bet will be to take advantage of a browser plugin called LiveReload. Since we're already going to be using nodemon to watch our backend, you might seriously consider using Gulp if you're not already to run both nodemon and LiveReload as two tasks. Your best bet for implementing LiveReload into Gulp is to use the gulp-refresh plugin as this is an updated version of the gulp-livereload plugin. You'll end up with a Gulpfile resembling this:

const defaultAssets = require('./config/assets/default'),
  gulp = require('gulp'),
  gulpLoadPlugins = require('gulp-load-plugins'),
  runSequence = require('run-sequence'),
  plugins = gulpLoadPlugins(),
  semver = require('semver');
  
// I store the locations of my backend js files in a config file, so 
// that I can call them later on. ie; defaultAssets
gulp.task('nodemon', function () {
  // Node.js v7 and newer use different debug argument
  const debugArgument = semver.satisfies(process.versions.node, '>=7.0.0') ? '--inspect' : '--debug';

  return plugins.nodemon({
    script: 'app.js',
    nodeArgs: [debugArgument],
    ext: 'js,html',
    verbose: true,
    watch: defaultAssets.server.allJS
  });
});

// Watch Files For Changes
gulp.task('watch', function () {
  // Start LiveReload
  plugins.refresh.listen();

  // Watch backend for changes
  gulp.watch(defaultAssets.server.allJS).on('change', plugins.refresh.changed);
  // Watch frontend dist folder for changes
  gulp.watch('./dist').on('change', plugins.refresh.changed);
});
  
  
gulp.task('default', function (done) {
  runSequence(['nodemon', 'watch'], done);
});

Now you just run the gulp command in place of nodemon app.js to start your Express server.

Clark Brent
  • 189
  • 1
  • 10
1

I was wondering this also. The Udemy course on the MEAN stack by Max Schwarzmüller has a sample code in there for integrating Express and Angular. In that sample code's package.json file, use uses the scripts.build property to give webpack a command which watches the angular files and updates accordingly. I don't want to copy his code here but that's the general idea. The rest will require some discovery work.

In the readme file, he suggests running npm run build which runs webpack, and then in a new terminal running npm start for the node server. So in theory, this runs two programs like you suggested in your version of the answer. But, it does a more "scripted"/pre-defined way of starting the Angular build process, instead of navigating to the Angular sub-directory and typing ng build --watch in there, and starting the Express app separately.

squirrelsareduck
  • 874
  • 1
  • 10
  • 15
0

May be you can add a dependency called 'concurrently', or (npm-run-all, parallelshell).

npm i concurrently --save-dev

then edit the package.json like this: `

"scripts": {
        "dev": "concurrently \"ng build -w\"  \"cross-env NODE_ENV=development node .\" "
    }

` this may be work.

References:

concurrently example: https://stackoverflow.com/a/30950298/7421101,

npm-run-all example: https://stackoverflow.com/a/38213212/7421101,

parallelshell example: https://stackoverflow.com/a/42373547/7421101.

jackchen
  • 71
  • 8
0

A proxy.conf.json file in the src directory with the code -

{
  "/api/*": {
    "target": "http://localhost:3000",
    "secure": false,
    "logLevel": "debug",
    "changeOrigin": true
  }
}

And editing package.json by adding these 3 entries to it - (replace back.js with your express file which is in the root directory of the Angular project)

"scripts": {
    "client": "ng serve",
    "server": "nodemon back.js",
    "start": "npm-run-all -p client server"
  }

Now running npm start would start both Angular and Express at the same time in dev environment.

Vibhor Dube
  • 4,173
  • 1
  • 22
  • 32