8

Sorry if this has been answered somewhere.

I am able to deploy an Angular app to heroku but despite taking the steps in this article, it will not run in PRODUCTION mode.

https://medium.com/@hellotunmbi/how-to-deploy-angular-application-to-heroku-1d56e09c5147

We have two files in the environments folder:

  • environment.prod.ts
  • environment.ts

Essentially, it seems Heroku uses the 2nd env file named environment.ts instead of using environment.prod.ts

In environment.ts, there is a env variable:

// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.

export const environment = {

  production: false,

};

fileReplacements is setup correctly also.

The environment.prod.ts file contains the variable production also and the value is true.

We know it's not production mode using the following simple code:

export class SettingsComponent implements OnInit {

  environmentIsProduction: boolean = false;

  constructor() {

  }

  ngOnInit() {
    this.environmentIsProduction = environment.production;
    console.warn('Environment is PRODUCTION: ' + environment.production);
  }

}

Is anybody able to make a suggestion on a step we may have forgotten?

Here is the entire package.json file

{
  "name": "angular-frontend",
  "version": "0.0.0",
  "engines": {
    "node": "8.11.2",
    "npm": "6.2.0"
  },
  "scripts": {
    "ng": "ng",
    "start": "node server.js",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "postinstall": "ng build --aot --prod"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^6.1.0",
    "@angular/cdk": "^7.2.1",
    "@angular/cli": "~6.2.3",
    "@angular/common": "^6.1.0",
    "@angular/compiler": "^6.1.0",
    "@angular/compiler-cli": "^6.1.0",
    "@angular/core": "^6.1.0",
    "@angular/forms": "^6.1.0",
    "@angular/http": "^6.1.0",
    "@angular/platform-browser": "^6.1.0",
    "@angular/platform-browser-dynamic": "^6.1.0",
    "@angular/router": "^6.1.0",
    "@ng-bootstrap/ng-bootstrap": "^3.2.2",
    "@swimlane/ngx-datatable": "^14.0.0",
    "angular-notifier": "^4.1.1",
    "angular-svg-icon": "^7.0.1",
    "angularx-social-login": "^1.2.6",
    "bootstrap": "^4.1.3",
    "core-js": "^2.5.4",
    "express": "^4.16.4",
    "flag-icon-css": "^3.3.0",
    "jquery": "^1.9.1",
    "jw-bootstrap-switch-ng2": "^2.0.2",
    "ng-connection-service": "^1.0.4",
    "ng-pick-datetime": "^6.0.16",
    "ng2-currency-mask": "^5.3.1",
    "ng2-nouislider": "^1.7.12",
    "ngx-bootstrap": "^3.0.1",
    "ngx-flag-icon-css": "^1.0.1",
    "ngx-webstorage-service": "^3.1.1",
    "nouislider": "^11.0.0",
    "path": "^0.12.7",
    "popper.js": "^1.14.4",
    "rellax": "^1.7.0",
    "rxjs": "~6.2.0",
    "typescript": "~2.9.2",
    "zone.js": "~0.8.26"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.8.0",
    "@angular/cli": "~6.2.3",
    "@angular/compiler-cli": "^6.1.0",
    "@angular/language-service": "^6.1.0",
    "@types/jasmine": "~2.8.8",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "~8.9.4",
    "codelyzer": "~4.3.0",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~3.0.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~1.1.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.11.0",
    "typescript": "~2.9.2"
  }
}
1
  • What's supposed to tell the software whether it should use environment.ts vs. environment.prod.ts? I'd expect that to be driven by an environment variable (e.g. NODE_ENV) so it doesn't make much sense to set a variable to define the environment inside the file. Generally speaking Heroku expects you to set things like this using heroku:config, not via files. Environment files are just a roundabout way of setting environment variables. Commented Mar 15, 2019 at 14:39

3 Answers 3

19

I hope this helps somebody....

Found the solution at last : https://devcenter.heroku.com/articles/nodejs-support#heroku-specific-build-steps

In package.json, it was necessary to change the following line:

"postinstall": "ng build --aot --prod"

to

"heroku-postbuild": "ng build --configuration=production"

Although the original command did go through all the steps of the production build and obsfucation of file names etc, pruning.... it then was running a normal ng build afterwards.

I noticed this behaviour in the logs during deployment to Heroku.

Once, heroku-postbuild was used, the build only happened once ... for production.

Sign up to request clarification or add additional context in comments.

3 Comments

This helped me! Thank you!
You do not have to remove/replace the "postinstall" setting, enough to add a new "heroku-postbuild"
I think this finally solved my issue. For some reason Heroku is telling me to use --prod flag if missing, and when it is present Angular doesn't recognize it. Then I added NODE_BUILD_FLAGS=--prod in apps settings and then it tries to run ng build --prod --prod and then build fails... -- At least for now it seems like everything is working
1

For anyone running into this problem in 2021, an alternative to using postinstall or heroku-postbuild in your package.json is going to your Heroku app's settings to add a NODE_BUILD_FLAGS to your config vars (https://devcenter.heroku.com/articles/nodejs-support#build-flags).

Once in your Heroku app's settings, it's as simple as clicking reveal config vars, setting a new key of NODE_BUILD_FLAGS and its value to --configuration=production, and voila! Heroku will automatically append --configuration=production to ng build. Once you click deploy, it'll know to run ng build based on your build script,

"build": "ng build"

append the newly configured flag, and your app should be in production mode without any actual changes to your repo!

It's a nifty little Heroku trick that can help and should work similarly with plenty of Node.js based apps, so hopefully this helps anyone out there who runs into this problem!

Comments

1

To expand on @Nick C 's answer for those of you deploying Angular Universal. When building Angular Universal the command ends up looking like:
ng build --configuration=production && ng run my-app:server:production

Unfortunately I could not get this to work with Heroku's NODE_BUILD_FLAGS. I ended up creating a small node script instead. This solution also allows me to deploy to a Heroku staging server and a production server. The node script reads a node environment variable and then decides which build command to run.

In package.json: "build": "node build-app.js",

build-app.js:

const { exec } = require('child_process');

let buildScript = 'ng build --configuration=staging && ng run my-app:server:staging';
if (process.env.ANGULAR_ENVIRONMENT_CONFIGURATION === 'production') {
    buildScript = 'ng build --configuration=production';
}
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!");
});

I go into more detail, including updating angular.json, in my blog post: https://dev.to/jfbloom22/a-better-way-to-deploy-angular-universal-to-multiple-environments-206j

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.