Dynamically Add Angular Base Href

前言

這篇雖然跟 DevOps 沒有直接關係,但是這也關係到了系統的可用性。所以,也將此問題收錄在我的筆記中。

發生的問題

昨天,開發人員在本機開發完 Angular 的專案之後並且利用 Jenkins 完成佈署後,噹啷~~ 進入頁面後只看見一片空白…。

在看了一下 Chrome DevTools 後發現,Client 端在讀頁面的時候並沒有正確網頁資源的位置。 因為過去有開發過 Angular 的經驗,當下便知道一定是 Angular Base Href 造成的問題。

解決方式

我找了三種解法。三種方法的複雜度依序排列為下。

  • 直接 Hard Code 在 index.html
  • 利用 Angular CLI 的指令來完成設
  • 利用程式碼進行動態配置

直接 Hard Code 在 index.html

最簡單的方式,但同時也造成了開發人員的困擾。一開始我就是用這個方式先解決無法正常讀取網頁的問題。 我先在 Web Server 裡面直接對 index.html 下手,並且把修改的地方也上到了專案程式碼裡。但是, 開發人員馬上跟我反應他在本機端發生無法正常執行的問題。 原因是 Angular 在本機開發上不需要 Base Href,所以在換頁的時候是直接導路徑的。例如: 在正式環境上的位置是 https:/your_domain/my_base_href/my_path,而開發環境上會變成 localhost:4200/my_path

如果直接在 index.html 上做 Hard Code,就會造成他們在開發上的問題。所以,這個方法只能對伺服器端進行。

利用 Angular CLI 的指令來完成設

Angular 專案裡面都有個 package.json。通常工程師們都會把 Build Command 寫在 scripts 欄位裡面。

"scripts": {
  "ng": "ng",
  "start": "ng serve --open --aot",
  "build": "ng build",
  "build:prod": "node node_modules/@angular/cli/bin/ng build --prod",
  "build:sit": "node node_modules/@angular/cli/bin/ng build -c sit --base-href=/your/base/href/",
  "test": "ng test",
  "lint": "ng lint",
  "e2e": "ng e2e"
},

上面 build:sit 最後面的 --base-href 就是第二個解法。直接在後面打上你的 Base Href, 在每次 Build 的時候會主動在生成的 index.html 裡寫入 Base Href。如下:

<base href="/your/base/href/" />

利用程式碼進行動態配置

這個方式只能讓專案在 Routing 的時候不用再加上 Base Href,可參考官方文,但其實是無法解決讀取網路資源找不到的問題。

這邊利用了 Angular Provider 來對 APP_BASE_HREF屬性進行設定。

import { Component, NgModule } from "@angular/core";
import { APP_BASE_HREF } from "@angular/common";

@NgModule({
  providers: [{ provide: APP_BASE_HREF, useValue: "/my/app" }],
})
class AppModule {}

useValue中值的部份,我們可以將它寫入到 environment 裡面,讓程式看來更具可讀性。

import { Component, NgModule } from "@angular/core";
import { APP_BASE_HREF } from "@angular/common";
import { environment } from "src/environments/environment";

@NgModule({
  providers: [
    {
      provide: APP_BASE_HREF,
      useValue: environment.baseRef,
    },
  ],
})
class AppModule {}

總結

想要解決網路資源無法正常讀取的問題,只能在ng build的時候利用 Build Tools 來幫我們把 Base Href 寫入index.html裡面。

參考資料

https://angular.io/guide/deployment#the-base-tag https://angular.io/guide/deployment#deploy-to-github-pages https://stackoverflow.com/questions/51182322/whats-the-difference-between-base-href-and-deploy-url-parameters-of-angular