Remote Software Engineer at Stripe and cellist based out of Ontario. Previously at GitLab. Fascinated with building usable, delightful software.
May 14, 2018 | 5 minutes to read
Not my snappiest title, but this topic is too near to my heart to obscure with puns. Tight feedback loops are one of my favorite aspects of front-end development.
One of my favorite features of Angular 2+ is the Angular CLI. The CLI cleanly replaces the hodge-podge of custom gulp, grunt, or npm scripts that power the build behind every AngularJS (Angular 1) app.
Perhaps the best feature of the CLI is the ng serve
command. This command builds the app, serves it (using webpack-dev-server), and then watches for changes to source files, incrementally rebuilding and reloading the app when changes are detected.
Unfortunately, it’s pretty easy to break some features of this command. For example, say you use a local webserver like NGINX to hide your app behind a URL like https://localhost/my-app. This common setup allows the app to communicate with a server hosted at a different domain or port without causing cross-origin issues. However, it also blocks some of the traffic the ng serve
feature uses to trigger the live reload feature, so your app will lose the ability to refresh itself when its source files are changed.
Fortunately, it’s possible to proxy this live reload traffic and regain live reload functionality.
First, update your Angular project’s angular.json
file to ng serve
on a unique port - one that isn’t already in use by another Angular app. This step is optional if you only plan on working on a single Angular 2+ app.
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"projects": {
"my-project": {
"architect": {
"serve": {
"options": {
"port": 4201
}
}
}
}
}
}
Note: only relevant properties are shown in the example above.
Next, update your nginx.config
to map a friendly URL to your app:
# proxy my-project traffic
location ^~ /my-project/ {
proxy_pass http://127.0.0.1:4201/;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
}
After restarting or reloading your NGINX instance (the simplest way is to run nginx -s reload
) and starting up your Angular build (ng serve
), you should be able to navigate to https://localhost/my-project and view your app.
One quick tip: make sure you update the <base>
tag in your app’s index.html
to point to your app’s new home. Continuing the example from above, this tag should look like <base href="/my-project/">
. If you forget to update your <base>
tag, you’ll end up with a blank screen and a lot of confusing errors in your developer tools.
This is the most important step. The live reload feature of Angular 2+ communicates on the path https://domain:port/sockjs-node/, so we need to forward along this traffic as well:
# proxy traffic for ng serve live reload
location ^~ /sockjs-node/ {
proxy_pass http://127.0.0.1:4201;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
}
You’ll need to restart or reload your NGINX instance again after making these changes.
Refresh your app. With your app on one screen and your editor on the other, make a change to a source file and hit Ctrl+S. Your app will refresh just like it did in pre-NGINX days!
The observant reader will notice that the /sockjs-node/ NGINX proxy above is hardcoded to 127.0.0.1:4201
, which will only work for one app - the app hosted at port 4201. What if you have multiple Angular 2+ apps on the go? In this case, your NGINX proxies would look something like this:
# proxy my-project-1 traffic
location ^~ /my-project-1/ {
proxy_pass http://127.0.0.1:4201/;
# etc...
}
# proxy my-project-2 traffic
location ^~ /my-project-2/ {
proxy_pass http://127.0.0.1:4202/;
# etc...
}
# proxy my-project-3 traffic
location ^~ /my-project-3/ {
proxy_pass http://127.0.0.1:4203/;
# etc...
}
All of these apps will attempt to use /sockjs-node/ to communicate with their respective ng serve
live reload server. Unfortunately, our /sockjs-node/ NGINX proxy above will only route traffic to one of these apps - meaning you can only use the live reload with one app at a time. In order to start working on a different app, you’ll have to manually edit the port in your NGINX config. This is a pain, but it’s better than not having live reload at all.
Know a way around this? Answer my question on Stack Overflow!
Other posts you may enjoy:
November 25, 2024 | 10 minutes to read
October 14, 2024 | 3 minutes to read
May 31, 2024 | 6 minutes to read
June 26, 2023 | 14 minutes to read
January 25, 2022 | 6 minutes to read