跳至主要内容

Diffoci:讓容器建構可重現的驗證捷徑

· 閱讀時間約 3 分鐘
balnibarbian

Diffoci 來自 reproducible-containers/diffoci,它把容器的每一層、清單和設定拆解成容易比較的片段,用以檢查本地建構或 CI 執行是否真的可重複輸出同樣的映像。這篇分享 Diffoci 的角色、驗證流程與 CI 整合思路,讓你不必再用人工 diff 無數個 tarball。

何謂 Diffoci

Diffoci 的核心概念是「解構」容器映像。它會把 OCI image layout 和映像內部的檔案系統逐一展開成 tarball,再比對 metadata(manifest、config)與物理內容,這樣就能照顧到檔案權限、時間戳與層順序等細節,而不是只比較映像 ID。

比較時,Diffoci 會提供可經驗證的差異報表(包括檔案新增/刪除、二進位內容差異、metadata 不一致),也能把結果存成檔案以供追查。若你在本地手動 build 出來的映像與上游 CI 給的 artifact 有差異,Diffoci 能指出是哪一層、哪個檔案不對,甚至反推是否是建構參數或 buildkit cache 導致。

驗證流程切片

Diffoci 支援把驗證拆成幾個步驟,方便串到工作流程:

  • 拉出參考映像:先把前次可信任的映像或某個 release 下載成 OCI layout(例如 docker save + umoci unpack),作為 baseline。
  • 產生待驗證映像:用相同 Dockerfile/BuildKit pipeline 產出新的映像,並將它也轉成 OCI layout。
  • 執行 Diffoci 比對:用 diffoci diff(或類似指令)比較兩個 OCI layout,差異會分門別類地列出檔案層、metadata 層與 config 層的差異。
  • 分析報告:Diffoci 可輸出 XML/JSON 或 human-readable 形式的報告,並載入到 CI artifact,以便快速定位檔案不一致、層內重複或時間戳漂移等問題。
  • 回饋開發流程:若差異在不可接受範圍(例如確保 byte-for-byte 相同),可以直接使該步驟 fail;若只是時間戳變動,可透過指令清除 metadata,確認誤判再走下一輪。

這種分層比較讓你不必猜測哪個檔案被改寫,也避免單純比較 digest 時疏漏時間戳或權限的變化。此外,這個流程也可套用在多平台建構(例如 amd64 與 arm64),只要把不同平台的映像各自解構,就能逐層對齊差異。

把 Diffoci 拉進 CI

在 CI(比如 GitHub Actions、GitLab CI)中,只要把 Diffoci 當成一個步驟來執行,就能在建構完成後立刻驗證結果:

  1. 先執行 build,產生映像與 OCI layout。
  2. 從 release 或 artifacts 下載先前的 OCI layout 作 baseline。
  3. 以 Diffoci 比對兩者,Diffoci 會回傳差異數據與檔案清單。
  4. 根據 policy 決定:若要 strict reproducibility,就讓差異導致 job fail;若只需資料一致,就把報告存起來讓人 review。

透過 Diffoci 的報告還可以自動化產生監控告警,例如「新映像多出了私密金鑰」或「某系統套件版本被升級」,以便在 release 前即時攔截潛在風險。

小結

Diffoci 並非單純把映像 tarball 做 diff,而是把 OCI 元素拆解成會被 CI 消費的維度(metadata、層、檔案內容),再提供可讀報告與 exit code,讓可重現性從「理想」變成「pipeline guard」。若你的團隊在意每次 build 的 bitwise 相同性,或希望在多個環境比對結果,Diffoci 是一個值得納入的檢查步驟。

短網址設計

· 閱讀時間約 4 分鐘
balnibarbian

短網址的核心目標,是用有限字元表達最多的唯一值。本篇釐清常見的三種生成思路,並談碰撞、資訊洩漏與可追蹤性的差異。

hash function

把原始 URL 投射到如 SHA256 或 MD5 的雜湊值,再取前面幾個字元做為短網址。這種做法的好處是每次只要有 URL 就能快速產生對應值,不需先寫入資料庫即可比較是否重複。但缺點也很明顯:

  • 縮短後缺乏唯一性保證,必須加上碰撞檢查與重試邏輯。
  • 雜湊值仍承載原始 URL 的資訊片段,理論上可供暴力逆推(尤其選用太短時)。
  • 無法表示建立順序、也不易追蹤來源,對一些流量分析情境不友善。

若需求是臨時、開發測試用的短網址,hash 方案能快速上手;但正式服務需要加強碰撞處理與 idempotency,才能避免重複導向。

id + base62

最常見的方式是讓資料庫自增 id,再把值轉成 base62(0-9a-zA-Z)。成品的特徵如下:

  • 唯一性:只要 id 不會重複,短網址就一定獨一無二。
  • 可逆性:只要能轉回 base62,就能還原 id,進一步查出原始 URL。
  • 長度可控:可以預先規劃 id 的最大範圍,轉成 base62 之後落在 6~8 個字元內。

缺點是需要中心化的資料庫或序列器來協調 id 的分配。若要擴展到多個節點,有額外的分區或跨節點同步成本。此外,字串會隨時間遞增,若想躲避暴露資料量或流量模式,就需要加些混淆手法。

snowflake / uuidv7 + base62

進階系統會採用分散式序列產生器,例如 Twitter 的 snowflake 或新的 uuidv7,它們把時間戳、節點編號、序號組合起來,再轉成 base62。這類方案的優勢包括:

  • 分散式:各節點可以獨立生成 id,不需集中鎖定。
  • 可排序:產生順序可反映時間(尤其 uuidv7 與 snowflake 的時間前綴)。
  • 長度合理、碰撞機率接近零。

將這種 id 再 encode 成 base62,就能在不犧牲可排序性的前提下得到可分享的短網址。如果想更短,可以只取時間戳與序號部分、再加 checksum,降低使用者手動輸入錯誤的風險。這類做法適合高吞吐、跨區域部署或需要追蹤來源的產品級服務。

整體架構要素

可以把短網址系統想成兩層:儲存層負責維護短碼與原始 URL 的對應,邏輯層負責產生 id、判斷歸戶、追蹤與排程。常見的架構要素包括:

  • 資料表設計:主表 short_links 包含 idshort_codetarget_urlcreator_idcreated_atexpires_atstatus(例如 active/disabled)、usage_countlast_accessed_at。若衍生功能如 A/B 測試或廣告導流,可再加 campaign_idvariant_tag。建議以 short_code 為唯一索引,加速查找。
  • 解析與 redirect:解析層收到短碼後,先查資料並更新 usage_count/last_accessed_at,再回傳 302 redirect 到 target_url。這個流程可以部署在 edge 或 CDN 層,盡量維持低延遲;複雜的條件(驗證、廣告插頁)可交由後端服務處理。
  • HTTP 狀態選擇:302(Found)是常見選擇,即使施工中也能快速改回原 URL。若希望搜尋引擎自然索引原址,改用 301(Moved Permanently)。對於可能要調整的短網址,分別設定 redirect_type 欄位控制返回值。
  • 快取與同步:由於查表頻率高,配合 Redis/L1 cache 快取 short_code -> target_url,並設定 TTL。若有分散寫入,應設計事件或 stream(Kafka/Change Data Capture)同步至快取節點以免 stale。
  • 廣告與觀察:若要放廣告或橫幅頁面,可以在 redirect 前插入檢查,例如 campaign_id 决定是否先導至吸引頁、再透過 client-side script 紀錄曝光後跳轉。也可在 short_linkslanding_page_html 選項,讓某些短碼呈現自訂落地頁再跳轉。
  • 追蹤與安全:加入 referer/utm 欄位、IP 黑名單、rate limit,讓濫用時能降載。另外可以記錄 fingerprintuser_agent 供分析使用頻率與地域。

總結

若是單機、初期方案,id + base62 提供簡單可逆、長度易控的產出;想快速實驗或不想自己維護序列器,就可考慮 hash function(記得補上碰撞處理與 retry)。若系統將來會分散部署、需排序或高可用,snowflake / uuidv7 + base62 是比較周全的選項。也可以混搭,例如用 uuidv7 生成原始 id,再 encode 成 base62,最後加 checksum,兼顧易讀與健壯性。整體架構應涵蓋儲存表、快取、redirect 處理、狀態控制與廣告/觀察擴充,才能支援不同使用情境。

大稻埕走讀:延伸參考與深度補充

· 閱讀時間約 4 分鐘
balnibarbian

以下內容作為主文〈歷史走讀:大稻埕「英語」導覽研習〉的補充,用於教案準備、導覽深化或外國遊客延伸閱讀。


1. 板橋林本源園邸(林家花園)

板橋林家是清代臺灣最具代表性的仕紳家族之一。
林家花園保留完整的江南庭園造景,被譽為北台灣最精緻的傳統豪宅。

延伸重點:

  • 與大稻埕「六連棟」林家系出同源
  • 展現 19 世紀臺灣望族的生活美學
  • 透過庭園配置、廳舍規制理解傳統家族階序

作為大稻埕茶商、仕紳階層的對照,可幫助導覽者解釋當時的富商文化。


2. 台語歌謠名作:〈望春風〉與〈四季紅〉

民謠巷紀念的是台語歌謠名家 李臨秋。他的創作深深刻畫了臺灣的庶民生活。

望春風(1933)

  • 作曲:鄧雨賢
  • 作詞:李臨秋
  • 描寫少女思慕情懷
  • 是日治時期最具代表性的台語歌謠之一

其旋律帶有日本演歌、美國福音曲調影響,展現殖民時期的文化混融。

四季紅

  • 以四季更迭比喻愛情
  • 是歌仔戲、布袋戲常用曲牌
  • 歌詞質樸、廣為傳唱

此兩曲能作為導覽時的文化補強,讓旅客更完整感受當時的大眾文化。


3. 日治時期的大眾文化與媒體發展

1920–1940 年代的大稻埕是臺灣現代文化的核心地帶。

可補充的背景如下:

  • 電影戲院林立(如新舞台)
  • 唱片行、黑膠產業興盛
  • 講古、布袋戲錄製蓬勃
  • 報業副刊帶動新文學(如《臺灣日日新報》)

導覽若加入這段文化史,能讓外國客人理解大稻埕不只是老街,而是臺北近代娛樂產業的起點。


4. 頂下郊拼(1853):大稻埕形成關鍵

大稻埕的街區形成深受 泉州人(頂郊)與同安人(下郊) 的衝突影響。

延伸說明:

  • 衝突後,同安人撤離艋舺,遷入今日的大稻埕
  • 建立霞海城隍廟作為族群中心
  • 影響今日大稻埕的文化、地名與信仰分布

這段歷史對於理解大稻埕的族群流動至關重要。


5. 茶葉文化:從 Formosa Oolong 到四季春

若想讓外國旅客理解臺灣茶文化的脈絡,可分兩段介紹。

19 世紀:Formosa Oolong(烏龍茶)

李春生與外國洋行合作,帶動臺灣烏龍茶外銷。
最重要的補充:

  • 美國《紐約時報》評論 Formosa Oolong 是 “Tea Champagne”(茶中香檳)
  • 當時在紐約、波士頓、倫敦極受歡迎
  • 以「香氣像香檳、甘甜像花蜜」著稱
  • 讓臺灣在 19 世紀後期成為世界知名的茶葉出口地
  • 大稻埕的茶行因此成為國際商業中心

此稱號影響深遠,甚至讓 19 世紀歐美市場把臺灣茶視為高級茶的象徵。

20 世紀後:四季春(1980s–)

  • 1980 年代普及的自然混種
  • 香氣清新、帶花香
  • 是現代台茶的新象徵
  • 可作為大稻埕舊茶文化的「當代延伸」

導覽時可利用「一老一新」呈現臺灣茶葉跨世代的演變。


6. 宗教與生活:霞海城隍廟的文化意義

霞海城隍廟結合:

  • 族群認同(38 義勇軍)
  • 城市守護神(城隍信仰)
  • 情感寄託(月老文化)

此信仰形式展現臺灣「生活中的宗教性」(lived religion),是外國旅客最容易理解、最具溫度的文化切點。


7. 推薦的延伸走讀路線

導覽者可依客群需求,安排以下延伸動線:

  • 永樂市場五樓設計師街區
  • 大稻埕貨櫃市集・夕陽拍照點
  • 台灣新文化運動紀念館(原北一女禮堂)
  • 太平町(日治市街現代化布局)
  • 迪化街南段・屈臣氏大藥房舊址
  • 河岸碼頭與輕工商業歷史

此路線能將大稻埕從「宗教 × 商業 × 文創 × 音樂 × 茶葉」多軸切入。


8. 建議教案延伸

若你是導覽老師或課程設計者,可加入:

  • 英文導覽口語練習句型
  • 音樂+故事的導覽說法
  • 茶葉聞香(Dry Leaf Aroma)體驗
  • 老照片對照(Before / After)展示

能讓整體導覽從「走街」進化成「沉浸式文化體驗」。

歷史走讀: 大稻埕「英語」導覽研習|臺北市觀光導遊協會

· 閱讀時間約 6 分鐘
balnibarbian

歷史走讀: 大稻埕「英語」導覽研習|臺北市觀光導遊協會

https://www.accupass.com/event/2511240411162018535005

1. 課程開始:聲音確認與暖場

English Summary:
The guide begins with audio checks and casual conversation to warm up the audience. Starting relaxed helps build trust and reduces distance between guide and guests.

中文說明:
老師先確認大家的音量是否清楚,再以聊天方式暖場。她說導覽不該一開始就太正式,輕鬆對談能讓客人更快進入狀況。


2. Vivian 導覽老師:旅居背景與教學風格

English Summary:
Vivian has lived extensively abroad, including the U.S., Morocco, Thailand, and Taiwan. Her multicultural communication style shapes her guiding method: friendly, natural, and emotionally warm.

中文說明:
Vivian 旅居全球,包括美國、摩洛哥、泰國等地。她曾任職於多國際機構,擅長跨文化溝通。她在課堂上強調導覽要「自然、有溫度、好聊天」,並示範如何利用生活化語氣與客人建立第一層信任。


3. 大稻埕導覽需分三段

English Summary:
Because of Da Daocheng’s long history, a complete tour must be divided into three major sections. A two-hour walk can only cover selected highlights.

中文說明:
大稻埕的故事太長,因此導覽通常拆成三段課程。今天的兩小時只能挑出精華,帶大家從六連棟一路到茶文化。


4. 六連棟與十連棟的門牌誤解

English Summary:
Many visitors misunderstand the building numbers and confuse the six connected houses with the ten-house row. The guide clarifies how to identify the correct section.

中文說明:
241–251 號容易讓人以為是十連棟,其實六連棟與十連棟是不同區段。老師解釋門牌是單雙號分列,需細看位置才能辨認。


5. 茶葉產業:大稻埕繁榮的源頭

English Summary:
Traditional tea shops evolved into modern creative tea bars, serving nitrogen tea and sparkling tea. Tea is the key to Da Daocheng’s economic rise.

中文說明:
茶葉是大稻埕的起點。老師說明從舊式茶行、拼茶技術,到氮氣茶、精品茶飲的轉型。大稻埕因茶葉出口而富裕,並成為北台灣重要的國際貿易中心。


6. 老屋新生:文創店家與生活空間

English Summary:
Old buildings are revived as cafés, bars, creative studios, and lifestyle shops. This blend of vintage and modern is Da Daocheng’s signature.

中文說明:
許多老屋改建成咖啡館、選物店、酒吧,讓街區充滿新舊交融的特色,這正是大稻埕最迷人的地方。


7. 城隍廟:義勇軍與月老文化

English Summary:
The City God Temple honors both the city god and 38 justice warriors. The beloved Yue Lao (matchmaker god) attracts many young visitors seeking relationship blessings.

中文說明:
城隍廟祭祀城隍爺與 38 位在頂下郊拼犧牲的義勇軍。月老更是人氣最高的神明,老師也分享正確的求籤與祈願方式。


8. 建築細節:牛眼窗、竹節柱與八角樓

English Summary:
The guide highlights unique architectural features like cow-eye windows and bamboo-joint columns. Only one true octagonal building remains in Da Daocheng.

中文說明:
牛眼窗曾被用來傳遞秘密訊息;竹節柱原是水管保護裝飾。大稻埕唯一的八角樓也在本區,是珍貴的歷史建物。


9. 李春生與茶葉出口史

English Summary:
Li Chun-sheng was crucial to Taiwan’s rise as a global tea exporter. His collaboration with Western traders boosted Formosa Oolong’s international fame.

中文說明:
李春生被稱為台灣茶葉出口的重要推手。他引進種植與製茶技術,帶領烏龍茶遠銷海外,使台灣茶在國際間大放異彩。


10. 六連棟:林家致富與建築故事

English Summary:
The Ling family owned the six connected houses. Their wealth came from the rice and salt trade, which flourished during wartime scarcity.

中文說明:
六連棟原由林家所有。林家因經營米與鹽致富,並在大稻埕建造多處典雅商宅,形成街區早期的重要商業勢力。


11. 工藝與布市:明星設計師的基地

English Summary:
Many designer studios—including those working with Taiwanese celebrities—are located upstairs in old buildings. This reflects the area’s blend of tradition and modern creativity.

中文說明:
永樂布市樓上聚集新銳設計師,包括多位明星御用造型師。老師強調這也是大稻埕的「現代靈魂」。


12. 小吃文化:青草茶、蔥餅、蛋捲

English Summary:
Food tasting is part of the tour, featuring herbal tea, onion pancakes, and handmade egg rolls. Visitors enjoy experiencing local flavors firsthand.

中文說明:
導覽途中會安排試吃青草茶、蔥餅、蛋捲,讓飲食成為理解街區文化的重要方式。


13. 民謠巷與李臨秋:四季紅・望春風

English Summary:
Folk Song Alley honors the contributions of composer Lee Lin-Chiu, who wrote iconic Taiwanese songs such as “Sì-jì-hông” and “Bông-chhun-hong.”

中文說明:
民謠巷紀念臺灣著名作詞家 李臨秋。他的作品包括《四季紅》《望春風》,都是影響深遠的台語經典歌曲。老師在這段帶大家認識日治時期的大眾文化與音樂創作背景。


14. 教堂、戰爭時期與秘密電報

English Summary:
The church once had a grand Baroque façade, later removed during wartime. Cow-eye windows were cleverly used to run concealed telegraph lines.

中文說明:
教堂原本極為華麗,但因戰時不得不移除裝飾。牛眼窗也曾利用其設計讓電報線穿牆,是大稻埕歷史上特殊的一段。


15. 導覽收尾與回程建議

English Summary:
Vivian closes by encouraging participants to revisit Da Daocheng through different themed tours. Two hours are never enough to uncover its layered history.

中文說明:
最後,Vivian 鼓勵大家未來再加入其他主題導覽。大稻埕的文化深度遠超過一場課程,值得多次探索。

使用 MDX 打造互動式文件

· 閱讀時間約 2 分鐘
balnibarbian

為什麼選擇 MDX?

當你需要說明重點提示、互動範例或分頁程式碼等更豐富的敘事方式時,可以在 Markdown 中混用 React 元件;而一般文字仍維持純 Markdown,兼顧易寫與彈性。

提示

讓 MDX 區塊維持精簡(建議 40 行內),並替所有媒體提供描述性的 alt 文字,方便後續翻譯與在地化。

分頁內容範例

  1. 下載最新範本並執行 npm install
  2. 透過 npm run start 在本機確認頁面載入正常。
  3. 將遇到的錯誤與重現步驟加到 issue 描述中。

可用的主題元件

前端常見測試框架比較:Vitest、Jest、Karma、Jasmine

· 閱讀時間約 3 分鐘
balnibarbian

為什麼要比較測試框架?

團隊在規劃測試策略時,往往需要兼顧開發體驗、既有 CI/CD 工具與瀏覽器支援度。這篇文章整理 Vitest、Jest、Karma 與 Jasmine 的定位差異,讓你快速判斷哪一套最符合專案需求。

核心差異一覽

框架核心定位執行環境亮點適合情境
VitestVite 生態系預設測試框架Node.js(可透過 Vitest UI 觸發瀏覽器)與 Vite 設定共享、原生 ESM、啟動極快使用 Vite/Vue/React 並追求極速回饋的專案
JestFacebook 推出的通用測試框架Node.js、JSDOMSnapshot 測試、模組模擬、社群資源豐富需要穩定 API、搭配 React/React Native 的團隊
Karma利用真實瀏覽器跑測試的 Test Runner真實瀏覽器(Chrome、Firefox 等)可整合 Webpack/SystemJS,適合舊專案必須驗證瀏覽器 API 或需要大量整合測試
Jasmine早期 BDD 風格測試框架瀏覽器或 Node.js零依賴、語法簡潔嵌入式或低依賴場景、AngularJS 舊專案
備註

若專案使用 Angular 14+ 並維持 CLI 預設,通常會同時搭配 Karma + Jasmine;若改用 Vite 驅動專案,就可考慮 Vitest 取代 Jest/Karma。

快速評估指南

  1. 優先考慮開發體驗:需要快速回饋與原生 ESM?Vitest 幾乎零設定,且能共用 Vite alias。
  2. 看重生態與教學資源:Jest 在社群套件、文件、CI 範例上仍最完整,適合多語言團隊。
  3. 要測到真實瀏覽器:Karma 擅長打開多個瀏覽器並收集覆蓋率,對 Web API、Legacy 專案仍有價值。
  4. 依賴最少、可嵌入:Jasmine 沒有外部 runner,但可輕鬆嵌入自訂腳本或 Karma、Protractor 等工具。

實務選型建議

  • Vite + Vue/React 新專案:直接選 Vitest,搭配 vitest run --coverage 即可整合 CI。
  • Next.js 或 React Native:Jest 有現成的環境模擬與 Snapshot 工具,且能與 Testing Library 無縫整合。
  • 長期維護的 AngularJS/Angular 專案:保留 Karma + Jasmine,逐步以 Web Test Runner 或 Vitest 替換即可。
  • 需要真實瀏覽器 E2E 但不想導入 Cypress/Playwright:Karma + Jasmine 仍是輕量選擇,可與 WebDriver 共享設定。

總結

選擇測試框架時請先盤點:

  • Build 工具(Vite、Webpack、Angular CLI)
  • 目標執行環境(Node、瀏覽器、Hybrid)
  • 期望維護成本(社群範例、既有腳本)

只要釐清上述條件,就能在 Vitest、Jest、Karma、Jasmine 之間做出更符合團隊節奏的決策。

在 WebStorm 中整合 Codex 工作流程

· 閱讀時間約 3 分鐘
balnibarbian

什麼是 Codex?

Codex 是 OpenAI 提供的程式碼生成助手,能解讀自然語言並輸出程式碼、指令或文字。本文示範如何在 WebStorm 中透過 Codex CLI 建立一個以對話驅動的工作流程。

為什麼要在 IDE 中使用 Codex?

WebStorm 已經提供完善的 TypeScript/React 體驗,但若再結合 Codex CLI,就能以對話方式生成模板、整理文件或批次修改檔案。這讓日常的重複性動作(例如建立部落格、填寫 front matter、插入多國語系內容)都能在同一個 IDE 視窗完成。

提示

Codex 維持在同一個版本最容易除錯,建議專案以 package.json script 管理,例如 "codex": "npx codex",避免團隊成員版本不一致。

安裝與初始設定

  1. 先在系統層級安裝 Codex CLI:
    npm install -g @openai/codex-cli
  2. 在專案根目錄建立或更新 .context/(例如 docusaurus-guidelines.md),把前置規範寫入,並於每次執行前指示 Codex 先閱讀。
  3. 若想用固定指令呼叫 Codex,可在 package.json 中加入腳本(底層仍呼叫全域 codexnpx codex):
    {
    "scripts": {
    "codex": "codex",
    "codex:plan": "codex --plan"
    }
    }

在 WebStorm 綁定 Codex 指令

  1. 打開 Run/Debug Configurations,新增 npmShell Script
  2. 指定 Script 為 codex,Working directory 指向專案根目錄。
  3. 勾選 Activate tool window 讓結果出現在 Run 面板,方便複製貼上。
  4. 若想要快速輸入指令,可在 Keymap → Plugins → External Toolscodex 配快捷鍵,例如 Ctrl + Shift + ;

透過以上設定,就能在任意檔案按一次快捷鍵,立即呼叫 Codex 完成編輯或回覆。

常見工作流程

  • 撰寫部落格:執行 npm run codex -- "create blog on webstorm",Codex 會依照 .context 中的規範與當天日期產生檔案,再由你在 WebStorm 內調整。
  • 批次重構:在終端切換到目標資料夾,讓 Codex 讀取檔案後輸入具體需求,例如「將所有 fetch 換成 axios」。
  • Docs QA:透過 codex --plan 整理多步驟修改,把輸出貼進 .mdx 檔案,並利用 WebStorm Diff 介面快速檢查。做法是先在終端執行 npm run codex:plan -- \"<需求描述>\",依序執行計畫並將 Codex 產生的內容貼回對應文件,最後用 Diff 檢查每一步是否符合預期。

疑難排解

  • 終端無法解析 codex 指令:確認 WebStorm 使用的 Node 版本與系統一致,或在設定中的 Shell path 改成 /bin/zsh -l
  • CLI 無法寫入檔案:在 Codex 命令前加入 CODEx_SANDBOX=workspace-write(依專案需求)或檢查 repository 權限。
  • 輸出語言錯誤:把「預設使用繁體中文」寫在 .context,並提醒 Codex 每次編輯前重新閱讀該檔案。

善用這套流程,就能在 WebStorm 中持續保持專注,同時享受到 Codex 的自動化與解題效率。

其他可搭配的工具

  • Claude:在需要長篇推理或分析文件時可當作補充顧問。
  • Kiro:主打工程自動化,可接續 Codex 的結果進行端到端測試或部署。

將多個 Nx Apps 部署到同一個 Nginx 下

· 閱讀時間約 3 分鐘

Nx monorepo 內通常包含多個前端或後端應用,例如:

apps/
app1/
app2/
app3/

透過 Nx build 後,你會得到:

dist/apps/app1/
dist/apps/app2/
dist/apps/app3/

本篇文章將教你如何把這些 apps 同時部署到同一個 Nginx 下,並使用不同路徑或不同子網域。


方法 A:使用不同路徑(最常見)

例如:

Nginx 設定

server {
listen 80;
server_name example.com;

location /app1/ {
alias /usr/share/nginx/html/app1/;
try_files $uri $uri/ /app1/index.html;
}

location /app2/ {
alias /usr/share/nginx/html/app2/;
try_files $uri $uri/ /app2/index.html;
}
}

Angular / Nx Build 指令

nx build app1 --configuration production --base-href=/app1/
nx build app2 --configuration production --base-href=/app2/

部署的資料夾結構

/usr/share/nginx/html/
app1/
app2/

方法 B:使用不同子網域

例如:

Nginx 設定

server {
server_name app1.example.com;
root /usr/share/nginx/html/app1;
try_files $uri $uri/ /index.html;
}

server {
server_name app2.example.com;
root /usr/share/nginx/html/app2;
try_files $uri $uri/ /index.html;
}

Angular / Nx Build 指令

由於每個 app 直接掛在根目錄(/),baseHref 設為 / 即可:

nx build app1 --configuration production --base-href=/
nx build app2 --configuration production --base-href=/

方法 C:透過 Proxy Pass 導流到後端服務(API / SSR / Node / NodeJS)

如果你的 Nx monorepo 中包含後端服務(例如 NodeJS API),你可以使用 proxy_pass: 讓 Nginx 將 /api 相關請求導向後端 server。

Nginx Proxy Pass 設定範例

server {
listen 80;
server_name example.com;

# 前端 Angular App
location / {
root /usr/share/nginx/html/app1;
try_files $uri $uri/ /index.html;
}

# API Proxy
location /api/ {
proxy_pass http://localhost:3333/; # Nx serve / NodeJS 的 API port
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

常見 Proxy Pass 場景

  1. Nx + Angular 前端 + NodeJS API

    • / → 前端
    • /api → 後端(NodeJS)
  2. 多後端服務(微服務結構)

    • /auth → Auth service
    • /order → Order service
    • /payment → Payment service

Nx + NodeJS 服務常用指令

nx serve api
nx build api

常見問題(FAQ)

為什麼重新整理會出現 404?

SPA(如 Angular)本身沒有真正的路徑,因此 Nginx 需要設定:

try_files $uri $uri/ /index.html;

這會讓所有路徑回到 Angular 的 router 處理。

Proxy Pass 無法連線?

檢查:

  • 後端 port 是否正確(如 3333
  • 後端是否允許來自 localhost 的 request
  • Nginx 有沒有加 proxy_set_header Host $host
  • 是否需要 HTTPS → HTTP 的 proxy_redirect off;

總結

你可以透過三種方式把多個 Nx apps 與後端部署在同一個 Nginx:

  1. 不同路徑(最常見、單一 domain)
  2. 不同子網域(乾淨、好管理)
  3. Proxy Pass 導後端 API(前後端整合最佳解)

只要正確設定:

  • Nginx alias/root
  • Angular baseHref
  • try_files
  • proxy_pass(如有後端 API)

即可達成完整的 Nx monorepo 部署架構。

Nx App 拆分優勢與策略步驟

· 閱讀時間約 7 分鐘
balnibarbian

1. 背景說明

目前前端專案採用 Nx monorepo,原本僅有單一應用程式 shopping-app,同時承載:

  • 一般使用者(前台)功能
  • 管理者/營運人員(後台)功能

隨著功能擴充與角色複雜度提升,單一 App 逐漸出現以下問題:

  • bundle 體積愈來愈大,首屏載入時間增加
  • 測試與除錯範圍變廣,改一小段功能要驗證很多頁面
  • 權限、導覽、UI 風格混雜在一起,維護成本高
  • 部署策略無法細緻,例如:只想更新後台功能但仍須重建整個 App

為解決上述問題,我們規劃將前端拆分為兩個獨立 App,並保留既有路由邏輯與使用者習慣。


2. 拆成兩個 App 的優勢

2.1 架構與責任分離

拆分後我們會有兩個應用:

  • shopping-app:前台,面向一般使用者
  • backoffice-app:後台,面向管理者/營運人員

優勢:

  • 前後台的路由、版型、權限可以完全分開設計
  • 開發時不會被另一個角色的 UI 汙染
  • 規格討論可以針對各自 App 進行,不互相牽扯

2.2 打包與建置時間優化

在 Nx 下,拆分多個 App 可以搭配:

  • incremental build(增量編譯)
  • affected:* 指令(只建置有受影響的專案)

實際效果:

  • 只修改後台程式碼時,可僅建置 backoffice-app
  • 前台沒有變動就不需重新 build,CI 時間與成本下降
  • 本地開發時可以只啟動自己關心的 App,啟動速度較快

2.3 bundle 大小與載入效能改善

  • 前台不再需要下載後台相關的頁面與元件
  • Admin 專用 UI / library 不會出現在前台 bundle 中
  • Lazy loading 策略可以更乾淨,依 App 設計懸掛不同的 chunk

2.4 權限與安全性清晰化

  • 後台 App 可以在 routing 層、部署層各自設計權限控管
  • 反向代理(nginx / gateway)可針對不同 path/domain 做額外保護
  • 不讓 admin 專用的頁面隨前台一起被發佈

2.5 部署與版本獨立

未來可實現:

  • 前台與後台採用不同的發版節奏
  • 僅更新後台功能時,不動到前台 bundle
  • 甚至可分別部署到不同 domain 或子路徑

3. 拆分核心策略:Clone & Carve

本次拆分採用「Clone & Carve」策略:

先完整複製,再在複製版本中慢慢「削減」成新形狀,而不是直接改原本的 App。

流程概念:

  1. 先複製現有 App → 得到兩份一模一樣的應用
  2. 確保兩個 App 都能正常 serve / build
  3. 在新 App 中逐步刪除不需要的功能頁面
  4. 建立路由/部署分流
  5. 拆完後,再逐步抽出共用的 libs

好處:

  • 原本的 shopping-app 在拆分初期完全不被動到
  • 出現問題可以隨時回退到舊的單一 App
  • 每個步驟都可以單獨測試與驗證

4. 視覺化流程與目錄結構

4.1 流程圖(文字版)

[現有 shopping-app]
|
v
[複製為 backoffice-app]
|
v
[確認兩者可獨立 serve & build]
|
v
[在 backoffice-app 內刪除前台頁面]
|
v
[建立兩者 routing / 部署分流]
|
v
[未來再抽出 shared libs]
|
v
[Build / 部署 / 權限 全面分離]

4.2 目錄結構變更

拆分前:

apps/
shopping-app/
pages/
home
note
article
tag
search
backoffice
admin
transcript

拆分後:

apps/
shopping-app/
pages/
home
note
article
tag
search

backoffice-app/
pages/
backoffice
admin
transcript

未來再視需求抽出 libs:

libs/
shared-model
shared-api
shared-domain
shared-ui
shared-utils

5. 實作步驟(操作手冊)

以下步驟以 Nx + Angular 為例,重點在「最小異動」與「可隨時回退」。

5.1 複製現有 App

  1. 在 repo 根目錄複製:

    cp -R apps/shopping-app apps/backoffice-app
  2. 確認複製後目錄存在:

    apps/
    shopping-app/
    backoffice-app/

此時兩個 App 的內容完全相同。

5.1.1 Nginx Proxy 導流測試(在拆分前先做)

server {
listen 80;
server_name yourdomain.com;

# 前台路由
location / {
proxy_pass http://localhost:4200;
}

# 後台路由
location /backoffice/ {
proxy_pass http://localhost:4300;
}

# 避免 Angular 路由錯誤
location /backoffice {
return 301 /backoffice/;
}
}

說明:

  • 在拆 App 之前,就先建立 nginx proxy 路由
  • nginx 充當反向代理,幫助我們先驗證 path 分流
  • 然後再複製 app 並建立 backoffice-app
[加上 nginx proxy → 建立 / 與 /backoffice 路由分流]
|
v
[確認分流可正常把流量導向不同開發 port]
|
v
[複製 shopping-app → backoffice-app]

5.2 調整 backoffice 專案設定

backoffice-app 底下,調整下列檔案:

  1. project.json

    • 將 name 由 shopping-app 調整為 backoffice-app
    • 確定 sourceRoot 指向 apps/backoffice-app/src
  2. tsconfig.app.json

    • 確認 extendsfilesinclude 等路徑指向 backoffice-app
  3. index.html

    • 修改 <title> 例如:Backoffice Admin

調整完成後,在本機執行:

nx serve shopping-app
nx serve backoffice-app

確認兩個 App 都能啟動且畫面正常,即可進入下一步。

5.3 在 backoffice-app 中刪除前台頁面

目標:在不影響 shopping-app 的前提下,慢慢把 backoffice-app 修剪成「只有後台功能」的應用。

做法:

  1. backoffice-app 中,先確定 routing 結構與檔案位置

  2. 針對明顯前台功能(例如:home, note, article, tag, search),依序:

    • 從 routing 設定中移除該 path
    • 移除頁面元件檔案
    • 移除對應的測試檔、style 等
  3. 每移除一組路由/頁面,都進行一次:

    nx build backoffice-app
    nx serve backoffice-app

    確認:

    • build 無錯誤
    • 主要後台路徑(例如 /backoffice, /admin, /transcript)仍可正常運作

完成後,目錄大致會變成:

apps/
backoffice-app/
pages/
backoffice
admin
transcript

5.4 建立路由與部署分流

在 gateway / nginx / 前端部署設定中,將路由切開,例如:

  • //app → 指向 shopping-app build 出來的 bundle
  • /backoffice/admin → 指向 backoffice-app build 出來的 bundle

如此一來:

  • 使用者造訪前台時,不會載入後台的程式碼
  • 後台可以獨立演進、獨立測試

5.5 拆分完成後的共用程式抽離(後期)

拆分前期不建議直接抽 libs,以免一次改動太大。

當兩個 App 穩定運作後,可以開始評估:

  • 共用的 model / DTO
  • 共用的 API service
  • 共用的 UI components
  • 共用的 util / helper

再逐步抽到 libs/ 底下的 shared 專案中,搭配 Nx 提供的 dependency graph 逐步優化結構。


6. 測試與風險控管

6.1 建議的測試順序

每一個拆分步驟都建議至少做:

  1. 單一 App build 測試:
    nx build shopping-app
    nx build backoffice-app
  2. 本地手動驗證關鍵路由:
    • 前台:主要使用者流程是否正常
    • 後台:登入、查詢、管理功能是否正常
  3. 重要節點時執行 e2e / smoke test

6.2 風險與對應策略

風險類型說明對應策略
build 爆炸一次改太多檔案每次只做小步驟,改完就 build 一次
路由錯亂path 指到錯的 App將前後台 routing 寫在文件與設定中統一管理
共用程式被誤刪後台仍需要前台某段邏輯初期只刪除「明顯純 UI」頁面,不動 domain / service
難以回退多步驟混在同一 commit每個重要步驟分開 commit,必要時可 git revert

7. 結語

本次 Nx App 拆分的目標,不是追求一次到位的「完美架構」,而是:

  1. 在不影響現有使用者的情況下,先把前後台在應用層分離開來
  2. 降低 build 時間與 bundle 大小,改善開發與使用體驗
  3. 為未來的 libs 抽離與獨立部署鋪路

核心心法:

Keep it working → Keep it separated → Keep it evolving

先讓系統穩定分家,再持續演進結構,是目前最務實、風險最低的拆分路線。

n8n Course Level 1

· 閱讀時間約 2 分鐘
balnibarbian

跟著人生攻略研究所所長的腳步,正式踏進 n8n Course Level 1 的測驗流程。
整體難度不算高,但實際作答時,還是有幾題需要重新確認邏輯與分類方式。

事前準備按著所長的教學完成註冊與金鑰取得:
https://lifecheatslab.com/n8n-course/#第一步:註冊_Level_1_測驗,取得個人金鑰

理論題

在整份題庫裡,理論題的第 4 題與第 6 題特別容易讓人猶豫。

  • 第 4 題:What can you do if there is no n8n node for an app/service that you want to use in a workflow?

  • 第 6 題:Which of the following are Trigger Nodes?
    依題目列出的選項來看,除了 Schedule node;Airtable node 實作上也可以。

其他題目主要檢查對 n8n 基礎概念的掌握:哪些節點能啟動 workflow、Code node 必須回傳什麼格式、資料結構怎麼判讀等等。
多利用官方文件與搜尋,大部分都能順利作答。

實作題

實作題的部分只要掌握流程邏輯,其實不算太複雜。
最方便的方式,是先匯入官方提供的完成版 workflow,再依照題目逐步調整即可。

官方 workflow JSON:
https://docs.n8n.io/_workflows/courses/level-one/finished.json

匯入後,照題目要求調整各個節點:補上 IF 條件、調整資料格式、確認流程順序。
Airtable 在這份測驗裡不需要真的去操作,直接略過就好,不會影響作答結果。
整體流程清楚、節點之間的連動也好檢查,照著步驟實作很快就能完成。

搭配課程文件的補充說明:
https://docs.n8n.io/courses/level-one/chapter-7/

雖然只是 Level 1,但完成後看到進度亮起來,還是有種踏出第一步的成就感。

n8n-course-level1.png