
如何使用環境配置
在實際開發中,總是需要針對不同的環境設定不同的參數,Angular 提供了一種應用環境機制,當使用 ng new 建構一個新項目時預設會在 src/environments 目錄下針對開發環境與生産環境(environment.prod.ts)的配置項。
絕大多數情況下,我們生産環境的後端請求位址與開發環境是不一樣,是以可以分别為其定義不同的域,例如:
// environment.ts
export const environment = {
production: false,
apiBaseUrl: `https://test.asdf.com/`
};
對于生産環境可以為:
// environment.prod.ts
export const environment = {
production: true,
apiBaseUrl: `https://api.asdf.com/`
};
當然,對于開發人員而言,無須如何去辨識它們,隻需要在 src 目錄的任意位置引用 apiBaseUrl 變量即可,就像這樣:
import { environment } from 'src/environments/environment';
console.log(`${environment.apiBaseUrl}`);
當通過 ng s 開發模式時自動使用 environment.ts,反之 ng b 會使用 environment.prod.ts 來替代。
事實上,不管 ng s 還是 ng b 兩種模式,本質上都可以利用 -c 參數來互換,例如:
// ng s -c development -> environment.ts
// ng s -c production -> environment.prod.ts
雖然 Angular 在建立時隻産生兩種環境,倘若需要針對 CI 單獨做一些額外的環境配置,隻需要在 angular.json 檔案配置的 architect/build/configurations 下新增一個新的節點,例如:
// angular.json
"architect": {
"build": {
"configurations": {
// 新增 ci 節點
"ci": {
"fileReplacements": [{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.ci.ts"
}]
}
}
},
// 如果希望 ng s 也生效,則以下也是必須的
"serve": {
"configurations": {
"ci": {
"browserTarget": "test:build:ci" // 注意 test 是項目名
}
}
}
}
然後在 src/environments 目錄下,新增 environment.ci.ts 檔案:
// environment.ci.ts
export const environment = {
production: false,
apiBaseUrl: `https://ci.asdf.com/`
};
最後,可以使用 ng b -c ci 指令,所有 apiBaseUrl 都将使用 https://ci.asdf.com/ 來替代了。
index.html 配置
不同環境使用不同的 index.html,比如說希望生産環境下多增加一些 Google Analytics 統計代或IM之類的,可能你也很希望在開發環境下不希望加載這些讓開發變慢的東西吧。
跟 environments 做法類似,隻需要在 angular.json 增加一點配置即可:
// angular.json
"architect": {
"build": {
"configurations": {
"production": {
"index": {
"input": "src/index.prod.html",
"output": "index.html"
}
}
}
}
}
同樣,需要在 src 下新增一個 index.prod.html 檔案;當使用 ng b 時會采用 index.prod.html 作為 index.html 的内容。
優化Tree-Shake
Angular 環境配置不光能替換配置;同時,根據這種檔案替換形式,來幫助我們更友好的進行 Tree-Shake 動作,而且非常徹底。
那麼什麼情況下會遇到呢?例如不希望在開發環境下加載某個子產品,以 NG-ALAIN 提供的 Mock功能 為例,并不希望在生産環境下依然加載它。
正常我們第一想到的是使用 environment.production 來區分環境進行動态加載,假設隻希望開發環境下加載 NG-ZORRO 的按鈕子產品:
import { NzButtonModule } from 'ng-zorro-antd/button';
const moduels: Array<Type<any>> = [];
if (environment.production) {
moduels.push(NzButtonModule);
}
@NgModule({
imports: [BrowserModule, ...moduels],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
即便代碼層面已經很明确不需要 NzButtonModule 子產品,但對于編譯而言依然需要先加載編譯,再到 Tree-Shake 環節剔除它;但它依然會有一點狗皮膏藥似的,還會包含一點點并不需要的代碼在上面,這取決于目标子產品是依賴關系。
是以,要想讓它真正從我們檔案中消失,最直接的辦法就是讓它不需要加載編譯。這有兩種方式可以做到:
粗暴
細心的讀者可能早已發現為什麼這種配置的替換是用 fileReplacements 來描述,沒錯,誠如 fileReplacements 意思,本質上就是檔案的替換;并且這裡還是一個數組,意味者允許加入更多的替換,但這類必須是符合 TypeScript 程式的檔案類型。
是以,可以直接替換某個 .ts 檔案,比如粗暴的把 app.module.ts 分為 app.module.prod.ts ,同時修改 angular.json 的配置:
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
},
{
"replace": "src/app/app.module.ts",
"with": "src/app/app.module.prod.ts"
}
]
溫和
另一種方式是,将子產品的導入放到 environment.ts 檔案當中,例如:
// environment.ts
import { NzButtonModule } from 'ng-zorro-antd/button';
export const environment = {
production: false,
apiBaseUrl: `https://test.asdf.com/`,
modules: [NzButtonModule],
};
最後,再将 modules 數組導入到根子產品下。
// app/app.module.ts
import { environment } from 'src/environments/environment';
@NgModule({
imports: [BrowserModule, ...environment.modules],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
結論
本篇隻是 Angular 的一個簡單運用,利用 Angular Cli 提供的檔案替換能力,可以幫助我們解決不同環境下使用不同參數、子產品、檔案等。
總之,也算是側面的說明 Angular Cli 的可塑性也還是很強的。
學習更多技能
請點選下方公衆号