【Angular6】ngコマンドでdev、stg、prodの3つの環境で設定を切り替えてビルドできるようにしてみる

Angular CLIのデフォルトだと、「ng build」または、「ng build --prod」で、2つの環境のみ切り替えができる状況ですが、ngコマンドでdev、stg、prodの3つの環境で設定を切り替えてビルドできるようにしてみたいと思います。
2018.08.25

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どうも!大阪オフィスの西村祐二です。

AngularではAngular CLIを使えば簡単にビルドすることができます。

ただ、デフォルトだと、

ng buildまたは、ng build --prodで、2つの環境のみ切り替えができる状況です。

しかし、環境はdev、stg、prodと3つあることが多いと思います。

そこで、今回、dev、stg、prodの3つの環境で設定を切り替えてビルドできるようにしてみたいと思います。

環境

  • Angular CLI: 6.1.5
  • Node: 8.11.3
  • OS: darwin x64
  • Angular: 6.1.4

テストプロジェクト作成

cliでプロジェクトを作成します。

$ ng new test-build

stg環境の環境ファイル作成と設定

デフォルトで作成される環境ファイルのenvironment.prod.tsをprod環境用、environment.tsをdev環境用とします。

stg環境用のファイルは自分で作成します。

  • environment.prod.ts
    • prod環境
  • environment.ts
    • dev環境
  • environment.stg.ts(作成)
    • stg環境
$ cd ./test-build/src/environments
$ touch environment.stg.ts

build時に設定が切り替わっているか、わかりやすいようにファイルを下記のように編集しておきます。

environment.prod.ts

export const environment = {
  production: true,
  apiUrl : 'prod環境のurl'
};

environment.stg.ts

export const environment = {
  production: false,
  apiUrl: 'stg環境のurl'
};

environment.ts

export const environment = {
  production: false,
  apiUrl: 'dev環境のurl'
};

angular.jsonを編集

build時にstg環境の環境ファイルを読み込むように設定を追加します。おまけで、ng serve -c stgでstg環境の設定を読み込んでサーバ起動するようにも設定しておきます。

angular.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "test-build": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/test-build",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            },
            "stg": {
              "fileReplacements": [{
                "replace": "src/environments/environment.ts",
                "with": "src/environments/environment.stg.ts"
              }],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "test-build:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "test-build:build:production"
            },
            "stg": {
              "browserTarget": "test-build:build:stg"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "test-build:build"
          }
        },
.
.
.

CSSのテーマも切り替えるようにする

よくAngular Materialを使うのですが、環境ごとにテーマを切り替えて環境の視認性を上げたいということがよくあります。

fileReplacementsを使ってファイルを差し替える方法はこちらのISSUEよりSCSSは動作しないようです。

そこで回避策として、ISSUEにも書かれているとおりstylePreprocessorOptionsを設定してSCSSのパス設定で切り替えるようにしてみます。

まずは、環境ごとにテーマファイルを作成します。中身は

@import '@angular/material/prebuilt-themes/deeppurple-amber.css';

など、それぞれ違うテーマや設定をしておきます。

また、ポイントとしては環境ごとにフォルダ分けするところと、テーマファイルのファイル名を揃えおきます。

環境ごとにthemeのファイルを作成しておきます

src/theme/local/theme.scss
src/theme/prod/theme.scss
src/theme/stg/theme.scss

styles.scssには下記のようにテーマを参照するように設定します。

src/styles.scss

@import 'theme';

angular.jsonで環境ごとにパスを設定します。

angular.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "test-build": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/test-build",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "stylePreprocessorOptions": {
              "includePaths": ["src/theme/local/"]
            },
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "stylePreprocessorOptions": {
                "includePaths": ["src/theme/prod/"]
              },
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            },
            "stg": {
              "stylePreprocessorOptions": {
                "includePaths": ["src/theme/stg/"]
              },
              "fileReplacements": [{
                "replace": "src/environments/environment.ts",
                "with": "src/environments/environment.stg.ts"
              }],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "test-build:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "test-build:build:production"
            },
            "stg": {
              "browserTarget": "test-build:build:stg"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "test-build:build"
          }
        },
.
.
.

これで、styles.scssではそれぞれの環境のtheme.scssを読み込んでくれます。

動作確認

環境ファイルに書き込んだapiUrlを表示するように設定します。

src/app/app.component.html

{{env}}

src/app/app.component.ts

import { environment } from './../environments/environment';
import { Component, enableProdMode } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'test-build';
  env = environment.apiUrl;
}

▼dev環境用の環境ファイルを読み込んでビルドしてみる。

$ ng build

ビルドされたファイルの確認はhttp-serveをつかえば簡単に確認できます。

$ cd dist/test-build
$ http-serve

ブラウザから
http://0.0.0.0:8000/
にアクセス

▼同様にstg環境用の環境ファイルを読み込んでビルドしてみる。

$ ng build -c stg

▼同様にprod環境用の環境ファイルを読み込んでビルドしてみる。

$ ng build --prod

さいごに

いかがだったでしょうか。

ngコマンドでdev、stg、prodの3つの環境設定に切り替えてビルドできるようにしてみました。これで環境ごとの自動デプロイの仕組みなど簡単に作れますね。

誰かの参考になれば幸いです。