
系列:30 天打造企業級 PLM|面向:全端|素材:部署腳本、版本機制實作
開發環境跑得好好的,上線那天的清單卻長得嚇人:機密設定不能進版控、SPA 的快取策略沒想好會讓使用者拿舊前端打新 API、資料庫 migration 在生產環境只有一次機會,還要準備萬一不行怎麼退。
更麻煩的是上線這件事本身沒有練習場。前 28 天的每個決定都可以改、可以重跑、可以在本機重來;上線那天你面對的是一份真資料、一群正在等著開單的使用者,和一個「兩小時內修不好就要回退」的倒數。今天把最後一哩路走完。
以前部署一套 Oracle Agile PLM,是一場耗資巨大且極端繁瑣的工程:
這個架構最大的隱性成本不是硬體,是**「不敢動」**:每次升級都是一場動員,於是升級間隔越拉越長,安全補丁越積越多,最後變成不升級的惡性循環。
Mini-PLM 採用單一產物交付(Single Artifact)與輕量化部署架構:前端 build 出來的純靜態資產在打包時直接複製進後端 static 目錄,由 Spring Boot 統一託管提供 Web 服務與 REST API,組態外置,一個 WAR/JAR 檔即可搞定全系統部署,幾秒內完成冷啟動。

圖的左半是建置管線,右半是這個選擇換來的三件事。要特別注意中間那條橘色虛線:機密不在產物裡,是啟動時才從伺服器本機疊上去的。這條線決定了同一個 WAR 檔可以原封不動地部到測試與生產——兩個環境的差異全部關在外部檔裡,而不是關在兩份不同的建置產物裡。
Day 2 的打包架構在此兌現:前端 npm run build 產物由腳本複製到後端靜態資源目錄(static/),與後端一起打包成單一 WAR。伺服器直接承載 SPA 路由與 REST API:
取捨要說清楚:前後端綁在同一個產物裡,代表只改前端一行字也要重新打包整包。以我們的節奏(一週一次到兩次發布)這個成本可以接受,換來的是「部署單位只有一個」的維運單純度。如果團隊大到前後端要獨立發布節奏,這個選擇就該重新評估。
生產環境的 datasource URL、密碼放外部配置檔(伺服器本機路徑,Spring 啟動時疊加載入),版控與封裝檔裡只有無害的預設值。理由有三:
git filter-branch 洗得掉檔案,洗不掉已經 clone 出去的那幾份Flyway 在生產的規矩(Day 27 的延伸):
ALTER TABLE,在三百萬列的生產表上可能是十分鐘的鎖表flyway_schema_history,出問題走 flyway repair 或開新版修正第三條是血淚:手改歷史表是把小事故升級成大事故的標準路徑,因為改完之後資料庫的實際狀態與紀錄不再一致,之後每一次 migration 都建立在一個謊言上。
SPA 上線後最陰的問題:使用者停在舊版前端打新版 API。瀏覽器快取著上週的 JS,而 API 契約這週改了,各種詭異錯誤只有特定幾個使用者遇得到,重現不能——你在自己的機器上怎麼點都是對的,因為你的快取是新的。
解法是把資源分三類各給策略:
| 資源 | 快取策略 | 理由 |
|---|---|---|
hash 資產(index-a1b2c3.js) |
immutable 長快取 | 檔名含內容 hash,內容變了檔名就變,舊檔永遠正確地舊著 |
index.html |
不快取(no-cache) | 它是指向 hash 資產的指標,必須每次拿最新 |
version.json |
不快取 + 前端輪詢 | 版本偵測通道 |

這張圖上半的三張卡只有一個邏輯:快取期限該由「這個檔會不會變」決定。hash 資產永遠不會變(變了就是另一個檔名),所以可以無限期快取;index.html 每次發布都會變(指向新的 hash),所以完全不能快取。搞混這兩者的方向,就是 SPA 快取事故的全部成因。
下半的迴圈是承認現實:使用者永遠有辦法停在舊版,筆電闔蓋一週再打開就是了。version.json 配前端的新版通知橫幅——build 時寫入版本號(Day 2 打包腳本的 Step 0),前端定期比對,伺服器版本比手上新就顯示「新版本已發布,請重新整理」。與其保證他不會舊,不如保證他知道自己舊了。
搭配的防線是 vendor chunk 紀律(Day 2):改動 chunking 必跑生產驗證腳本。白畫面事故的絕大多數,都是快取策略與 chunk 結構的組合技——單獨看每一邊都沒問題,湊在一起就是使用者拿著舊的 index.html 去要一個已經不存在的 chunk。
□ 生產複本上 migration 演練通過(含耗時紀錄)
□ 外部配置檔就位、無版控殘留機密
□ health check 通(/actuator/health——只答自己,Day 22)
□ 煙霧測試:登入 → 開單 → 簽核 → 放行(核心動線,人工或 E2E smoke)
□ version.json 版本正確、What's New 內容就緒
□ 回退預案:上一版封裝檔在手、migration 回退腳本或相容性確認
□ 監控頁開著(Day 22)、第一小時盯著錯誤指紋
這份清單的設計原則是:每一項都要能在上線前就得到明確的是或否,不能有「應該沒問題」。「回退預案」那一項尤其——上一版的 WAR 檔實際放在哪個路徑,要打得出來,不是「應該還在 build server 上」。
前端靜態資源封裝單一產物交付、機密外部化、migration 生產紀律、SPA 快取三分法加版本偵測。
上線這件事的技術含量其實不高,難的是把所有「應該沒問題」換成「我剛剛確認過」。30 天的建造到此完工。明日 Day 30:總結回顧、踩坑排行榜、未來的 AI 藍圖,以及一點心路歷程。