電影流水帳(2020/06/01~2020/06/10)

Carrie Fisher aka Princess Leia figure at Madame Tussauds London
Carrie Frances Fisher 飾演星際大戰裡的莉亞公主
  • Star Wars: The Rise of Skywalker (IMDB, Wikipedia),台譯:星際大戰九部曲:天行者的崛起。
  • Rambo: Last Blood (IMDB, Wikipedia),台譯:藍波:最後一滴血。

Star Wars: The Rise of Skywalker

每次看沒有中文字幕的,總是會覺得少了一點什麼,我想是英文的聽讀還不夠強的緣故吧。

這集主要的故事線是 Rey 的身世。Ben Solo 找到了 Palpatine ,加入了西斯,但他始終知道,自己只是被利用,對於這整個銀河他有另外的想法。Rey 隨著原力的指引,身世的部份慢慢有了線索,後來跟 Ben Solo 碰面之後,Ben 告訴她,她就是 Palpatine 的孫女,並且告訴她,我們一起聯手統治銀河吧。打了一場,Ben Solo 受到母親原力影響,被 Rey 刺了一劍,但 Rey 相信他有善良的一面,以原力救活了 Ben。Rey 很害怕自己加入邪惡的一方,就跑去躲了起來,而 Ben 卻因此變為善良。

之後,反抗軍跟西斯軍展開戰鬥。Rey 則是在絕地英靈的啟迪下,知道了能定義自己的,不是血統,而是自己的選擇,於是前往尋找 Palpatine 。遇到 Palpatine 以後,她拒絕了 Palpatine 的提議,跟 Palpatine 打了起來。Ben 這時也趕到,跟 Rey 一起對抗 Palpatine。果然薑是老的辣,Palpatine 汲取了他們兩人的原力,讓自己恢復到最強大的狀態,眼看 Rey 跟 Ben 就要輸了。就在這個時候,絕地英靈幫 Rey 開了外掛,一個反擊,將 Palpatine 打過來的閃電反彈回去,消滅了 Palpatine。Rey 這時氣力放盡,就要掛了。重傷的 Ben 這時將自身僅存的原力傳給了 Rey,算是報恩吧,然後自己面對了死亡。

抵抗軍跟 Rey 雙雙告捷,西斯軍被打敗,宇宙再也沒有邪惡勢力。

Rambo: Last Blood

有一點點 Old Man Logan 的味道,藍波歷經了人生了波折,回到家鄉,只想好好過後半生的藍波,卻因為Garbrielle,決定重新拿起之前的專業來復仇。我覺得很中規中矩,有點讓人惆悵,也能讓人感受到藍波最後的那種心情。

藍波經歷幾次任務以後,心裡是百感交集,對美國與人生失去了希望,回到出生地以後,他看到了可愛的Gabrielle,跟她生活了一陣子以後,他開始慢慢對人生恢復了信心。Gabrielle長大以後,她的朋友告訴她有Gabrielle生父的消息,於是Gabrielle不聽祖母與藍波的勸,冒險越過墨西哥國境去找生父。

意外就這樣發生了,Garbrielle被壞人帶走,強迫賣淫並注射毒品讓她成癮。藍波去找人,輾轉找到,殺進妓院,跟壞人打了一陣,救出了奄奄一息的Garbrielle。可惜Garbrielle沒能順利回到家,在回家的路上,她就已經走了。藍波很難過,非常非常難過,帶她回去見Garbrielle的祖母,祖母也是非常難過。埋了Garbrielle以後,藍波超不爽的,先送走Garbrielle的祖母,然後開始佈署陷阱,做迎敵的準備。透過當地朋友的幫忙,去挑釁壞人,讓對方殺到自家農場來。

怒氣沖沖的壞人殺到家門來了,藍波利用之前佈下的陷阱,打起自己最擅長的地道游擊戰,殲滅了壞人,為Garbrielle報仇,也是為當地除了一個禍害。

gitlab 看不到 last commit 跟 last updated 問題

gitlab 升級到 13.0.5 以後,發現有這問題,原本以為是 gitlab-ce 問題,下次升級就解決了。但是今天升級到 13.0.6 以後,並沒有解決。 利用瀏覽器的開發者工具去查看,發現有個請求是回傳 404,仔細看他網址裡,有 %2F

https://host/user/gitlab-ce-commit-info-bug/-/refs/master/logs_tree/folder_1%2Ffolder_2?format=json&offset=0

手動把 %2F 改為 / 以後,就可以拿到資料。

利用 “gitlab-ce “refs/master” “%2F” 404gitlab-ce “refs/master” “%2F” 404” 這幾個關鍵字在 gitlab issue 209941 找到線索,是 Apache 問題。

Apache 要在 virtualhost 裡加上 AllowEncodedSlashes NoDecode

但我這樣試了以後,發現還是不行。後來看了 Apache 文件,知道除了 NoDecode 之外,還可以設定為 On:AllowEncodedSlashes On 

於是這樣就可以成功顯示了。

但是為了安全性問題 (Apache 文件不建議這樣設定),再去找了一下,看為什麼會這樣。
後來在 StackOverflow 上找到解答,除了要改 AllowEncodedSlashes 之外,還要改 mod_proxy ProxyPass ,在後面加上 nocanon 即可。

範例

AllowEncodedSlashes NoDecode
<Location /example/>
  ProxyPass http://anotherserver:8080/example/ nocanon
</Location>

電影流水帳(2020/05/11~2020/05/31)

Q'Orianka
Q’orianka Kilcher 飾演 Dora and the Lost City of Gold 裡守護黃金城的公主。
  • Secret Superstar (IMDB, Wikipedia),台譯:隱藏的大明星。
  • Dora and the Lost City of Gold (IMDB, Wikipedia),台譯:朵拉與失落的黃金城。

Secret Superstart

早上吃早餐時,轉到Fox Movie,剛好「隱藏的大明星」剩下30分鐘。茵希雅去了孟買,跟沙克帝在告別,沙克帝跟她說,我雖然每次被提名都沒得獎,但像你這樣的才華,就跟汽水裡的泡泡一樣,是會自己浮上去的,會慢慢的發光發熱。沒多久,場景帶到茵希雅家裡,茵希雅跟媽媽說,我去了孟買找了沙克帝,我覺得你應該要離婚,我可以靠唱歌來養你跟弟弟。媽媽很驚訝也有點生氣,告訴他你怎麼可以自己去孟買,回來還叫我離婚。對,茵希雅長期受到丈夫的暴力對待,兒女都看不下去。這場爭執在母親斥責女兒後結束,茵希雅跑回房間去,這時奶奶走了過來,跟茵希雅說了她媽媽當時懷她的事情。本來在知道懷的是女兒以後,是決定要墮胎的,但是茵希雅的媽媽逃走躲起來,到了十個月後才抱著孩子回來求情說,下次一定會生個男生的,現在孩子也生下來了,我們就撫養她吧。

茵希雅這時才知道當初媽媽並不是她所想的那樣懦弱,而是鼓了很大的勇氣逃走,才生下她。於是她放下對媽媽的怨,配合媽媽一起準備搬家的東西,再過一陣子全家跟父親一起去沙烏地阿拉伯工作。電視上一直在播報著「隱藏的大明星」的報導,這個女孩蒙著面,彈著吉他唱歌的影片透過Youtube頻道在全國各地走紅,但是沒有人知道她是誰,只有她的好友跟沙克帝知道。但電視上一直在播放著,媽媽也或多或少猜到了,她沒有多說什麼,只是看著最近女兒落寞的神情,也想著自己的處境,心疼,但是好像也不能做些什麼。在茵希雅學期結束後,一家人前往機場搭飛機,在排隊辦理登機程序,快輪到他們到櫃檯時,父親內急去上了廁所。就輪到他們了,可是媽媽不知所措,櫃檯人員本來要他們先讓後面的辦理,但茵希雅挺身而出,成熟的跟櫃檯人員應對,辦完手續。

上了飛機,茵希雅的位子上有人佔了她的位子,茵希雅婉轉的告知,並請他移座。在一旁的媽媽看到自己的女兒,深深的覺得自己女兒已經長大,可以成熟的應對了。到了孟買轉機,要託運行李,父親不願意多付吉他託運的錢。媽媽冷靜的跟父親說明,這是女兒的夢想,請他也一起託運,但是父親不肯,還威嚇她。接下來的一幕,讓我眼眶含著眼淚看完。媽媽不退縮,再次說明自己的立場,父親還是不願意,媽媽這時拿出了文件簽名,然後告知了自己女兒的事情,以及自己等一下要怎麼做。簡單的說,你如果動手打我,這裡有攝影機,而且你這樣做也會影響到你工作。我們婚姻就走到這裡,你就帶著你媽去沙烏地阿拉伯吧,等你回來,我們再來談後續的事情。說完,媽媽就帶著茵希雅跟弟弟走了。

後續,他們去參加了頒獎典禮,茵希雅得到了獎項,在台上發表了感人的演說。大概就這樣吧,很感人的故事,仔細想想,我碰到這種母愛、父愛的故事都很容易留下眼淚。

Dora and the Lost City of Gold

我覺得導演跟編劇的安排很好,直接把 Dora 拉到國高中的年紀,這樣可以讓演員的年紀不會那麼突兀。同時,也設定讓 Dora 從小在叢林長大,到了國高中才到城市裡唸書,讓小女孩經歷青少年對於交友的困擾,也讓 Dora 除了長大之外,還保有純真的一面。

故事蠻簡單的,看了前面 30 分鐘,大致上可以猜到後面的劇情。Dora 從小在叢林長大,受到父母的薰陶,對於冒險這件事情非常有興趣。表哥 Diego 小時候也是住在叢林,但並沒有住很久,之後就搬去城市唸書了。Dora 的父母接受了委託,要去調查事情,而 Dora 則被送到表哥所在的城市去唸書。Dora 在學校裡算是一個怪咖,不是很受歡迎,表哥 Diego 則對此感到困擾。某天校外教學,Dora 跟表哥以及其他兩個同學被湊成一組,然後就被壞人捉走了。壞人是為了黃金城而來的,他們想要挾持 Dora ,威脅 Dora 父母帶他們去找黃金城。Dora 跟其他三人被帶到叢林裡,被一個自稱是 Dora 父母朋友的教授救了,5個人就在叢林裡探險尋找黃金城。經過冒險的橋段之後,原來那個自稱是 Dora 父母朋友的教授就是壞人,利用好警察、壞警察的手法,設計 Dora 帶他們去找到黃金城。可是,Dora 也不是笨蛋,早就留了一手,讓壞人掉入陷阱,被叢林守護者捉住。最後,黃金城是找到了,可是也因為觸發機關的關係而被封住了。

整個故事就是很有家庭歡樂的氣氛,蠻適合陪孩子一起看的。

iperf3 測試網路速度

閱讀 指令式的網路速度測試工具 iPerf3 ,揪出網路頻寬真實的一面 以後做的小摘錄。

簡單說用法,因為是要測試內部網路的網路速度,所以要兩台電腦。一台執行

iperf3 -s

一台執行

iperf3 -c <server_ip>

這樣就可以了。也有公用的伺服器可以測,這樣就要一台電腦就行 (用 ipef3 -c <server_ip>),亞洲區只有兩台,一台在中亞(哈薩克),一台在印尼,要注意,使用公用伺服器的話,測出來的速度並不是網路內部電腦間的速度,而是電腦到Router到外部伺服器的速度。

flutter stable/beta 並存

簡單說,有專案因為怕被影響到,只想用 stable 來建置,不想用 beta,可是又想要試驗 flutter web ,而 flutter web 又只有 beta channel 才有,所以想讓他們並存。

其實意外的簡單,就只是放在不同目錄,只要在使用的時候小心,不要用到不對的 flutter 就行,在 terminal 直接下指令的話,會需要特別注意。

# 切到你要放 flutter beta channel 的資料夾
git clone https://github.com/flutter/flutter.git flutter-beta -b beta
cd flutter-beta/bin
./flutter precache
./flutter config —enable-web
./flutter devices

在 Android Studio 建立 flutter project 時,會問 flutter SDK 路徑,把路徑指到剛剛放 flutter beta channel 的位置,就可以了。

Visual Studio Code 的話,需要改 workspace preferences ,改裡面的 dart.flutterSdkPath (來源1 / 來源2 )

"settings": {
"dart.flutterSdkPath": "/Users/youruser/flutter-beta"
}

直接用指令的話,就要確定 PATH 是對的,這時候可以預先寫好環境變數檔案,然後用 source 來處理

# flutter-stable.env
export PATH=/Users/youruser/flutter-stable:$PATH
# flutter-beta.env
export PATH=/Users/youruser/flutter-beta:$PATH
# 切換到 stable
source flutter-stable.env

# 切換到 beta
source flutter-beta.env

紀錄一下 MacOS 的中文輸入法

之前有找過一次了,今天又再找一次,這次把找的過程記錄下來。那這次為什麼要找呢?是因為小麥注音輸入法不知道為什麼當機終止了,選不到這個輸入法,想說找穩定的輸入法來使用。

之前換小麥注音輸入法的主因是因為我實在是無法適應 MacOS 的內建注音輸入法,用了一陣子還是無法適應,特別是打注音符號,就斷然放棄。

言歸正傳,目前可以找到的幾個:

  1. 小麥注音
  2. Yahoo!奇摩注音輸入法
  3. 超注音
  4. 香草輸入法 (沒有注音)
  5. 自然注音輸入法
  6. 鼠鬚管

小麥注音

用 homebrew 就可以安裝:brew install mcbopomofo

目前免費,沒有智慧選字,也沒有詞庫,按 shift+, 可以輸入全形標點符號。 網址:https://github.com/openvanilla/McBopomofo

Yahoo!奇摩注音輸入法

安裝需要手動,homebrew 以前有這個 cask,但是後來被移出去了。

目前免費,有智慧選字,輸入法程式沒有持續更新,Yahoo 已經將這整個輸入法開放原始碼了,安裝包是 zonble 大大熱心去編譯並打包的 (zonble大大就是OpenVilla香草輸入法/小麥注音輸入法的開發者)。 網址:https://github.com/zonble/ykk_installer/

按 shift+, 可以輸入全形標點符號

介紹:

超注音

安裝要繞個路,透過 Google Play,我猜想這是開發者要收費的緣故。價格:500 NTD

安裝方法:

  1. 使用 Android 手機,去 Google play 安裝 (超注音 for macOS)
  2. 開啟 app,裡面有操作說明,簡單的說,這包 apk 裡面有超注音的安裝程式,你要依照操作說明把這個安裝程式放到你的 macos 機器上,然後安裝。

網址:https://www.superkbd.com/

參考資料:超注音 for macOS 開放下載!為 Mac 再添一款輸入法

香草輸入法

安裝:brew install openvanilla

如果你需要倉頡、簡易(速成)、大易、行列、符號與日文假名、粵拼等輸入法,裝這個就對了,不過我沒用過。

網址:https://openvanilla.org/

自然注音輸入法

老牌的輸入法,要上官方網站購買,網址:https://www.goingpro.me/products

價格 2000 NTD,如果你有雙系統需求,可以考慮購買 Win+Mac 共通版,價格 3500 NTD,可以安裝在三台電腦上。

鼠鬚管

感謝推友 Ralphsun73221 的推薦。鼠鬚管就是只有注音的 RIME (Linux版是中州韻,Windows 版是小狼毫)。

安裝:brew cask install squirrel

介紹:【RIME 鼠鬚管注音版】Mac 中最好用的注音輸入法!

最終的選擇

之前是使用小麥注音輸入法,這個先保留,不移除。現在則是安裝了 Yahoo!奇摩注音輸入法來試用看看,未來如果不好用,再來考慮安裝鼠鬚管或是購買超注音或是購買自然注音輸入法。

剛剛使用,注意到一點,選字的游標位置不太一樣:

  • 小麥注音輸入法跟內建的注音輸入法,選字是選前個位置的字。
  • Windows/Linux 上的輸入法跟Yahoo!奇摩注音輸入法,選字是選後面位置的字。

筆記:Best practices for REST API design

來源:Best practices for REST API design

下面是看完以後,我的整理、摘要以及一點自己的想法:

  • 盡可能使用 JSON (application/json),除非有特殊需求,才來考慮使用其他格式,例如 form (上傳檔案) 或是 xml
  • 使用名詞,而非動詞:這樣才能搭配 HTTP verbs 的 POST/DELETE/GET/PUT,POST 放新資料到伺服器上,DELETE 移除資料,GET 取得資料,PUT 是更新資料
  • 時使用複數,表示取得一堆資料。
  • 階層物件可以使用巢狀資源,例如 /articles/article_id/comments/ 。P.S. 碰到這種情況其實也可以考慮使用 GraphQL
  • 漂亮的處理錯誤並回傳錯誤代碼,盡可能利用 HTTP 狀態碼而不要另外建立新的錯誤代碼。伺服器端在回傳錯誤時,可以帶上錯誤訊息,讓客戶端便於判斷、處理。
  • 允許篩選、排序跟分頁。篩選跟分頁可以避免一次拿過多資料,導致伺服器傳輸過多資料,也可以提升速度,拿的少,自然就快,對吧~
  • 安全性,SSL/TLS 是必要的,再來就是處理好使用者能存取的資源權限,這部份是實作 API 時必須要考慮到的。
  • 要用 cache,實作時要想,這資料會很常變動嗎?會很常被索取嗎?不常變動又很常被索取,就放到 cache 吧。
  • 幫 API 編上版號,這可以避免影響到舊有的 API,一方面也可以單純化,不用考慮到過多相容性的問題。例如:/v1, /v2

Angular i18n 的另外一個選擇 ngx-translate

Angular i18n 的官方作法並不讓人滿意,我後來找到 ngx-translate

先說明一下他的作法,他把這些翻譯好的字詞放到 JSON 翻譯檔去,在執行時就可以透過 http client 去拉取回來作動態的替換。

好處是,程式只要建置一次,不需要針對個別語言再次建置,網頁伺服器那邊也不需要特別寫設定去處理,而且可以做到動態切換語言。壞處是會有額外的 HTTP 請求,會增加流量。

ngx-translate 額外好的地方是,他提供了相應的工具、plugin,相當的方便。

那麼怎麼使用呢?我推薦看這篇【Angular】ngx-translate 多語系實務應用 ,他這篇的缺點是萃取字串的部分是手動,我建議萃取字串的部分可以用原作者 biesbjergngx-translate-extract  ,就不用自己找字串找的太累。

先進行安裝

npm install @ngx-translate/core —save
npm install @ngx-translate/http-loader --save

然後改 app.module.ts

import { TranslateModule, TranslateLoader, TranslateCompiler } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
import { HttpClientModule, HttpClient } from '@angular/common/http';

// … 省略 …

// 這主要是告訴 ngx-translate 翻譯檔該怎麼載入,用 TranslateHttpLoader 是表示以 HTTP 方式去下載、載入
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

// … 省略 …

// 設定
const translateConfig = {
  defaultLanguage: 'en-US',  // 預設是英文
  loader: {
    provide: TranslateLoader,
    useFactory: HttpLoaderFactory,  // 前面寫的 Factory
    deps: [HttpClient]
  },
  compiler: {
    provide: TranslateCompiler,
    useClass: TranslateMessageFormatCompiler
  }
};

@NgModule({
  // …
  imports: [
    BrowserAnimationsModule,
    BrowserModule,
    TranslateModule.forRoot(translateConfig),  // 模組帶設定
    // …
  ],
  // …
})

在 HTML 裡,使用

// 方法 1
{{ ‘your_translation_key’ | translate }}

// 方法 2
<div [translate]=“‘your_translation_key’”></div>

// 方法 3,適用於字串要用 HTML
<div [innerHTML]="'HELLO' | translate"></div>

他還可以帶參數,只是這邊我看不太懂,暫時也還用不到。

在程式裡,使用

// 先匯入
import {TranslateService} from '@ngx-translate/core';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';

// … 省略 …
export class AppComponent implements OnInit {
  l10n__title = '';

  constructor(public translate: TranslateService) {
  }

  ngOnInit(): void {
    const self = this;

    // 讓 ngx-translate-extract 可以抓到字串用的
    _('your_translation_key');

    // 取得字串都要使用 translate.get() 來預先取得
    this.translate.get('your_translation_key').subscribe((res: string) => {
      self.l10n__title = res;
    });
  }
}

這裡要特別說明一點,也是我當初用的時候搞錯的地方,就是上面用到的 your_translation_key 並不是字串,而是你自定義的代碼,裡面有使用 ‘.’ 的時候,在產出的 JSON 裡會變成 nested object ,舉個例子,假設這個 key 是 login.title,那麼 JSON 翻譯檔就會是

{
  "login": {
    "title": ""
  }
}

接下來講 ngx-translate-extract,ngx-translate-extract 的安裝

npm install @biesbjerg/ngx-translate-extract --save-dev

裝好以後,在 package.json 的 scripts 裡加入 (要產生什麼語言,請替換 {en,da,de,fi,nb,nl,sv} 這個字串,以繁體中文來說,是zh-TW或zh-Hant,只有英文跟繁體中文的話,就放 {en-US,zh-TW}。 )

// package.json
...
"scripts": {
  "i18n:init": "ngx-translate-extract --input ./src --output ./src/assets/i18n/template.json --key-as-default-value --replace --format json",
  "i18n:extract": "ngx-translate-extract --input ./src --output ./src/assets/i18n/{en,da,de,fi,nb,nl,sv}.json --clean --format json"
}
...

然後建立存放字串的資料夾:mkdir -p src/assets/i18n,執行 npm run i18n:extract 以後,就可以在 src/assets/i18n 裡看到翻譯檔了。

bfg

因為 git repository 裡有敏感資訊,為了安全起見,必須要把這些敏感資訊移掉。
找到這兩篇:

裡面大同小異,主要提到兩個方法,一個是 git filter-branch,一個是 bfg,這邊只介紹 bfg。 bfg 是一個相對於 git filter-branch 來說簡單、快速的工具,除了可以清理敏感資訊之外,也可以清掉超級大的檔案。

MacOS 的安裝可以用 brew:brew install bfg

使用步驟如下:

  1. 移除掉你要處理的檔案或是先清理掉你要處理的檔案內容,然後提交、推送到 repository 去。這段官方有特別說明 (在 Your current files are sacred… 這個小節),我是已經做完下面步驟,上 gitlab 網頁看檔案怎麼沒消失,花了點時間才在網頁上注意到這段,所以這個步驟要先作!!
  2. 切到另外一個目錄,例如 $HOME/tmp,對 repository 作 mirror,這樣拿下來的檔案結構不是一般的檔案佈局,而是 .git 下的佈局:git clone –mirror your_repository.git ,這時候 $HOME/tmp 下會有一個 your_repository.git
  3. 幾種使用方法:
    • 刪除檔案:bfg –delete-files your_file your_repository.git
    • 移除超過指定大小的檔案:bfg –strip-blobs-bigger-than 50M your_repository.git
    • 清理敏感資訊:先新增一個 passwords.txt,裡面放置要移除的文字,範例可以參考這個 gist ,然後執行 bfg –replace-text passwords.txt your_repository.txt
    • 刪除資料夾:bfg –delete-folders .git –delete-files .git –no-blob-protection your_repository.git
  4. 切到 your_repository.git 下,依照指示執行 git reflog expire –expire=now –all && git gc –prune=now –aggressive
  5. 推送回去:git push
  6. 大功告成

把敏感設定的內容跟 Angular 程式分離

以我用過 Django / Docker 的經驗,一般都是利用環境變數來作分離,程式在執行時,會去讀取環境變數來當作設定,盡量不依靠設定檔,進而達到 12 factor –  config 的要求。

到了 Angular ,就需要做出調整。Angular 是需要先進行建置產出 javascript / html / css ,再把這些產出的檔案放到網頁伺服器,瀏覽器再去下載,所以完全沒辦法使用環境變數作為設定,必須要把設定寫到檔案裡,再做建置。那設定寫到檔案的話,其實我們都知道,這些敏感設定內容不適合放到 git repository,即使是 private repository,這樣會有安全上的風險。那這樣就兩難了啊?

說來很妙,我是覺得官方早就應該有比較好的作法了,但是,並沒有。不管怎麼樣,我還是找到解決方法了,基本上跟我想的也差不多。

這兩篇文章的作法大同小異,這邊作簡單的說明:

  1. 移除 src/environment/environment.ts
  2. 新增一個腳本,這個腳本會讀取環境變數,並產生一個新的 src/environment/environment.ts
  3. 修改 package.json
    1. 在 scripts 裡增加 config,這個 config 會去執行步驟 2 的腳本,用以產生 environment.ts
    2. 修改 scripts 裡的 start / build,在執行原來的指令前,先執行 npm run config 去產生 environment.ts

下面兩個片段是關鍵的改動部分:

// set-env.ts
// 放在專案根目錄下
import { writeFile } from 'fs';
import { name, version } from './package.json';


// Configure Angular `environment.ts` file path
const targetPath = './src/environments/environment.ts';


// 載入 colors 模組,主要是用來顯示
const colors = require('colors');


// 可以把敏感內容放到 .env 檔案裡,nodejs 會把內容讀出來,放到環境變數裡
// 也可以在執行 npm run 之前,先設定好環境變數
const result = require('dotenv').config();
if (result.error) {
  // throw result.error;
}


// 原來 environment.ts 裡的內容,把該替換的,用 template literals 來替換

// https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Template_literals
const envConfigFile = `export const environment = {
  production: ${process.env.PRODUCTION},
  VERSION: '${version}’,
};

`;


// 顯示
console.log(colors.magenta('The file `environment.ts` will be written with the following content: \n'));
console.log(colors.grey(envConfigFile)); writeFile(targetPath, envConfigFile, (err) => {
  if (err) {
    throw console.error(err);
  } else {
    console.log(colors.magenta(`Angular environment.ts file generated correctly at ${targetPath} \n`));
  }
});
// package.json
// 只摘錄重要的部分
{
  “scripts”: {
    "config": "ts-node -O '{\"module\": \"commonjs\"}' ./set-env.ts",
    "start": "npm run config && ng serve",
    "build": "npm run config && ng build”
  }
}