Skip to content
This repository has been archived by the owner on Oct 14, 2024. It is now read-only.

Show how to use multiple environments (for browser and prerender) #673

Open
kmturley opened this issue Mar 22, 2019 · 4 comments
Open

Show how to use multiple environments (for browser and prerender) #673

kmturley opened this issue Mar 22, 2019 · 4 comments

Comments

@kmturley
Copy link

In your angular.json, you show how to use file replacement for environments:
https://github.com/angular/universal-starter/blob/master/angular.json

"configurations": {
  "production": {
    "optimization": true,
    "outputHashing": "all",
    "sourceMap": false,
    "extractCss": true,
    "namedChunks": false,
    "aot": true,
    "extractLicenses": true,
    "vendorChunk": false,
    "buildOptimizer": true,
    "fileReplacements": [
      {
        "replace": "src/environments/environment.ts",
        "with": "src/environments/environment.prod.ts"
      }
    ]
  }
}

In your package.json
https://github.com/angular/universal-starter/blob/master/package.json

You show a shorthand for production configuration builds using --prod:

"scripts": {
  "ng": "ng",
  "start": "ng serve",
  "build": "ng build",
  "lint": "ng lint ng-universal-demo",
  "build:client-and-server-bundles": "ng build --prod && ng run ng-universal-demo:server:production",
  "build:prerender": "npm run build:client-and-server-bundles && npm run compile:server && npm run generate:prerender",
  "build:ssr": "npm run build:client-and-server-bundles && npm run compile:server",
  "compile:server": "tsc -p server.tsconfig.json",
  "generate:prerender": "cd dist && node prerender",
  "serve:prerender": "cd dist/browser && http-server",
  "serve:ssr": "node dist/server"
},

This works if you import an environment in browser code like your main.ts:
https://github.com/angular/universal-starter/blob/master/src/main.ts

import {enableProdMode} from '@angular/core';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';

import {AppModule} from './app/app.module';
import {environment} from './environments/environment';

if (environment.production) {
  enableProdMode();
}

document.addEventListener('DOMContentLoaded', () => {
  platformBrowserDynamic().bootstrapModule(AppModule);
});

But this doesn't work when the same code is used in prerender.ts:

import {environment} from './environments/environment';

if (environment.production) {
  enableProdMode();
}

Even if you add fileReplacement to angular.json "server" configuration:

"server": {
  "builder": "@angular-devkit/build-angular:server",
  "options": {
    "outputPath": "dist/server",
    "main": "src/main.server.ts",
    "tsConfig": "src/tsconfig.server.json"
  },
  "configurations": {
    "production": {
      "optimization": true,
      "sourceMap": false,
      "fileReplacements": [
        {
          "replace": "src/environments/environment.ts",
          "with": "src/environments/environment.master.ts"
        }
      ]
    },
  }
}

In my Angular 6 version I had to work around this using multiple webpack configs and a webpack file replacement:

// Work around for https://github.com/angular/angular-cli/issues/7200

const path = require('path');
const webpack = require('webpack');

module.exports = {
  mode: 'none',
  entry: {
    // This is our Express server for Dynamic universal
    server: './server.ts',
    // This is an example of Static prerendering (generative)
    prerender: './prerender.ts'
  },
  target: 'node',
  resolve: { extensions: ['.ts', '.js'] },
  // Make sure we include all node_modules etc
  externals: [/node_modules/],
  output: {
    // Puts the output at the root of the dist folder
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    rules: [
      { test: /\.ts$/, loader: 'ts-loader' },
      {
        // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
        // Removing this will cause deprecation warnings to appear.
        test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
        parser: { system: true },
      },
    ]
  },
  plugins: [
    new webpack.NormalModuleReplacementPlugin(
      /src\/environments\/environment\.ts/,
      './environment.master.ts'
    ),    
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?angular(\\|\/)core(.+)?/,
      path.join(__dirname, 'src'), // location of your src
      {} // a map of your routes
    ),
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?express(\\|\/)(.+)?/,
      path.join(__dirname, 'src'),
      {}
    )
  ]
}

Do you have a solution when using the typescript compiler?
"compile:server": "tsc -p server.tsconfig.json"

@robert-king
Copy link

I just tried this:

 517  git clone https://github.com/angular/universal-starter.git
  518  ls
  519  cd universal-starter/
  520  ls
  521  vi server.ts
  522  npm install
  523  npm run build:ssr && npm run serve:ssr

added two lines to server.ts

import {environment} from "./src/environments/environment";
console.log('is prod', environment.production);

it says environment.production is false. Seems like there's a bug in the universal-starter?

@robert-king
Copy link

Anyone got this working?

@kmturley
Copy link
Author

I got working using the code above for Angular 6 which is older webpack config.
Not tried for Angular 7+ but presume it will need a different solution as the config is inside Angular Cli code

@martinvano
Copy link

alright, I finally got this working. The code is inspired by @kmturley and https://webpack.js.org/plugins/normal-module-replacement-plugin/

`
// Work around for angular/angular-cli#7200

const path = require('path');
const webpack = require('webpack');

module.exports = function (env) {
var configEnv = '';

if (env && env.configuration) {
    configEnv = env.configuration;
}

if (configEnv !== '' && configEnv !== 'prod') {
    throw `Unknown configuration name (was ${configEnv}). Check this script for more info about supported environments.`
}

if (configEnv)
    configEnv = `.${configEnv}`;

return {
    mode: 'none',
    entry: {
        // This is our Express server for Dynamic universal
        server: './server.ts',
        // This is an example of Static prerendering (generative)
        prerender: './prerender.ts'
    },
    target: 'node',
    resolve: {extensions: ['.ts', '.js']},
    // Make sure we include all node_modules etc
    externals: [/node_modules/],
    output: {
        // Puts the output at the root of the dist folder
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    module: {
        rules: [
            {test: /\.ts$/, loader: 'ts-loader'},
            {
                // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
                // Removing this will cause deprecation warnings to appear.
                test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
                parser: {system: true},
            },
        ]
    },
    plugins: [
        new webpack.NormalModuleReplacementPlugin(
            /relative-path-to-your-project\/src\/environments\/environment\.ts/,
            `./environment${configEnv}.ts`
        ),
        new webpack.ContextReplacementPlugin(
            // fixes WARNING Critical dependency: the request of a dependency is an expression
            /(.+)?angular(\\|\/)core(.+)?/,
            path.join(__dirname, 'src'), // location of your src
            {} // a map of your routes
        ),
        new webpack.ContextReplacementPlugin(
            // fixes WARNING Critical dependency: the request of a dependency is an expression
            /(.+)?express(\\|\/)(.+)?/,
            path.join(__dirname, 'src'),
            {}
        )
    ]
}

};
`

The script supports 2 environments - local and production. You can easily extend it with other envs.
To run local build:
webpack --config webpack.server.config.js --progress --colors
and production build:
webpack --config webpack.server.config.js --progress --colors --env.configuration=prod

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants