Deploying Angular and especially Angular Universal using CI to a staging and a production environment is very difficult. A quick Google search reveals a lot of really ugly solutions. Here is a cleaner solution:
The root of the issue is how the Angular CLI decides which angular environment to use based on a command line variable.
ng build --configuration=production
Will build the application with the production environment variables set in environments/environment.prod.ts
. How do you get a production Heroku server to build with ng build --configuration=production
and a staging server to build with ng build --configuration=staging
?
Heroku now automatically calls npm install
and npm build
. Have your npm build script call: node build-app.js
const { exec } = require('child_process');
console.info(
'node env var ANGULAR_ENVIRONMENT_CONFIGURATION',
process.env.ANGULAR_ENVIRONMENT_CONFIGURATION
);
let buildScript = 'npm run build:staging:ssr';
if (process.env.ANGULAR_ENVIRONMENT_CONFIGURATION === 'production') {
buildScript = 'npm run build:prod:ssr';
}
const child = exec(buildScript, function (err, stdout, stderr) {
if (err) throw err;
else console.info(stdout);
});
child.stdout.on('data', function (data) {
process.stdout.write(data);
});
child.stderr.on('data', function (data) {
process.stdout.write(data);
});
child.on('exit', function (data) {
process.stdout.write("I'm done!");
});
The idea here is that this node app is able to read node environment variables and then decide on which angular build command to call.
In Heroku, set the node environment variable ANGULAR_ENVIRONMENT_CONFIGURATION
to either staging
or production
appropriately.
This is pretty much all you need to know for deploying Angular. Take a look below at the npm build scripts and simply omit the :ssr
and ng run my-app:server:production
. There are plenty of other tutorials out there that demonstrate how to add staging
to the angular.json file. Here are a few:
https://tattoocoder.com/angular-cli-using-the-environment-option/
https://blog.angulartraining.com/how-to-manage-different-environments-with-angular-cli-883c26e99d15
Angular Universal
If you are using Angular Universal it will always default to building the pre-render files with the production environment. You have to add some additional configuration in order to get it to pre-render with the staging environment. The key is to setup your npm build scripts like so:
"build:prod:ssr": "ng build --configuration=production && ng run my-app:server:production",
"build:staging:ssr": "ng build --configuration=staging && ng run my-app:server:staging",
And update your angular.json
"server": {
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/my-app/server",
"main": "server.ts",
"tsConfig": "tsconfig.server.json"
},
"configurations": {
"production": {
"outputHashing": "media",
"sourceMap": false,
"optimization": true
},
"staging": {
"outputHashing": "media",
"sourceMap": false,
"optimization": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.staging.ts"
}
]
}
}
},
"serve-ssr": {
"builder": "@nguniversal/builders:ssr-dev-server",
"options": {
"browserTarget": "my-app:build",
"serverTarget": "my-app:server"
},
"configurations": {
"production": {
"browserTarget": "my-app:build:production",
"serverTarget": "my-app:server:production"
},
"staging": {
"browserTarget": "my-app:build:staging",
"serverTarget": "my-app:server:staging"
}
}
},
"prerender": {
"builder": "@nguniversal/builders:prerender",
"options": {
"routes": [
"/"
]
},
"configurations": {
"production": {
"browserTarget": "my-app:build:production",
"serverTarget": "my-app:server:production"
},
"staging": {
"browserTarget": "my-app:build:staging",
"serverTarget": "my-app:server:staging"
}
}
}
Top comments (0)