AngularでEnvironmentを使って複数環境のアプリをデプロイする

More than 1 year has passed since last update.


趣旨

もともと、Angular(1.x)でアプリを開発していて、似たような機能をもつ2つのアプリをリリースしていました。

それぞれいくつかのControllerを使っていたのですが、下記のように共通している機能(ページ)が多いアプリでした。

アプリA
アプリB

Controller A

Controller B

Controller C

Controller D

Controller E

リポジトリも複数に分けて管理していて、とても管理がかっこ悪い状態でした。

そこで、このアプリをAngular(2.x)に移行し、それぞれをComponent化することでリポジトリを一つで管理できるようにすることを考えました。


方針

Angular(2.x)のビルドにAngular CLIを使っている場合、ビルド時にenvironmentを使って環境を切り替えることができます。

Angular CLIで作成したコードは、初期状態で以下の2つのenvironmentが設定されています。


angular-cli.json

"environments": {

"source": "environments/environment.ts",
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}

この状態では、開発環境と本番環境の2つしか存在していません。

この本番環境を複数用意することで、複数のアプリに対応させます。


サンプル


構成

今回は4つのComponentをもつアプリを作ります。

Prodという環境とProd-limitedという環境のアプリを作成します。

Prod
Prod-limited

Menu

Component1

Component2

Component3


Componentの作成

Angular CLIをインストールしていない場合は、下記のコマンドであらかじめインストールしておいてください。

npm install -g angular-cli

まず、ベースとなるコードを作成します。

ng new angular-multi-build-sample

Angular CLIを使って作成します。

ng g component menu

ng g component component1
ng g component component2
ng g component component3


menu.component.ts

ここはあってもなくてもいいのですが、Componentが使えるのかどうかというのをわかりやすくするために、読み込んでいるComponentへのリンクをまとめたヘッダーメニューを作成します。

生成されたmenu.component.tsを編集します。

ここでは、app.module.tsと同様にenvironmentroutes要素を読み込んでメンバ変数にセットしています。


menu.component.ts

import { Component, OnInit } from '@angular/core';

import { Routes } from '@angular/router';
import { environment } from '../../environments/environment';

@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css']
})
export class MenuComponent implements OnInit {
private routes: Routes = [];

constructor() {
this.routes = environment.routes;
}

ngOnInit() { }
}



menu.component.html

そして、menu.component.htmlに読み込まれているComponentへのリンクをリストで出力します。


menu.component.html

<ul>

<li *ngFor="let route of routes">
<a routerLink="{{route.path}}">{{route.path}}</a>
</li>
</ul>



各環境の設定


environment.prod.ts

Prod環境用のEnvironmentを編集します。

environment.prod.tsはAngular CLIで作成されているので、ファイルを編集します。


environment.prod.ts

import { Component1Component } from '../app/component1/component1.component';

import { Component2Component } from '../app/component2/component2.component';
import { Component3Component } from '../app/component3/component3.component';

export const environment = {
production: true,
routes: [
{
path: 'component1',
component: Component1Component
}, {
path: 'component2',
component: Component2Component
}, {
path: 'component3',
component: Component3Component
}
]
};


この環境で使用するComponentを読み込んでRoutesとして扱うオブジェクト配列を用意します。


environment.prod-limited.ts

次に、Prod-limited環境用のEnvironmentを作成します。

environment配下にenvironment.prod-limited.tsを作成し、environment.prod.tsと同様にComponentの読み込みとRoutes用の配列を定義します。

ただし、Prod-limited環境ではComponent1とComponent3だけ使用できる環境としたいため、Component2は読み込みません。


environment.prod-limited.ts

import { Component1Component } from '../app/component1/component1.component';

import { Component2Component } from '../app/component2/component2.component';
import { Component3Component } from '../app/component3/component3.component';

export const environment = {
production: true,
routes: [
{
path: 'component1',
component: Component1Component
}, {
path: 'component3',
component: Component3Component
}
]
};



ルーティングの設定


app.module.ts

実際にルーティングを行う部分を実装します。

RouterModuleに与えるRoutes配列に、先程定義したenvironmentroutes要素の配列を与えます。


app.module.ts

import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule, Routes } from '@angular/router';
import { environment } from '../environments/environment';

import { AppComponent } from './app.component';
import { Component1Component } from './component1/component1.component';
import { Component2Component } from './component2/component2.component';
import { Component3Component } from './component3/component3.component';
import { MenuComponent } from './menu/menu.component';

const routes: Routes = environment.routes;

@NgModule({
declarations: [
AppComponent,
Component1Component,
Component2Component,
Component3Component,
MenuComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
RouterModule.forRoot(routes)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }


また、MenuComponentを表示できるようにするために、declarationsに追記しておきます。


app.component.html

最後に、各Componentを表示する設定をします。

app.component.htmlapp-menurouter-outletを記述します。

app-menuタグは先程作成したMenuComponentが挿入されます。

router-outletタグはURLのパスに応じて対応したComponentを挿入します。


app.component.html`

<app-menu></app-menu>

<router-outlet></router-outlet>


実行結果

サンプルコードを実行します。


Prod

下記コマンドで開発用サーバーを起動します。

ng serve -e prod

すべてのComponentがメニューに表示されており、リンクをクリックして遷移することができます。

スクリーンショット 2017-01-01 14.40.55.png


Prod-limited

同様にオプションの引数を変えてサーバーを起動します。

ng serve -e prod-limited

Component2がメニューには表示されず、http://localhost:4200/component2にアクセスすることもできません。

スクリーンショット 2017-01-01 14.41.32.png


まとめ

Angular CLIのEnvironmentを使うことで複数環境向けにアプリをビルドすることができました。

私がこの機能を実際に使ったのはあるアプリで管理者用とその他利用者用で利用できる機能を制限したものとそうでないものをデプロイする必要があったからです。(冒頭の表のようなイメージ)

きちんとアプリの機能制限を実装するのであれば、バックエンドとうまく連携させて権限によって制御をかけるのが望ましいとは思います。

今回私が対象としていたアプリはバックエンドに複数のAPIを組み合わせていたり、そこまで厳密な認証等は不要であったため今回の方法を採用しています。

今回のソースコードはここにおいています。

mukopikmin/angular-multi-build-sample


参考