實測相容性
每個版本除了單元測試之外,都會實際在真實專案上跑一次導入來驗證。
本頁記錄實際跑過的情境、結果與注意事項,讓你判斷哪些環境已經驗證過、哪些還是未知領域。
這一頁背後有什麼
這些層沒有一層是備援 —— 每一層被加進來,都是因為既有的那些全綠了,卻看不到某個真實的缺陷。
- 導入 e2e 測試套件 —— 納入版本控制的起始範本,涵蓋本頁記錄的 Vite、Next.js 與 workspace 各種形態,再加上一個植入既有債務的既有專案;整組就是
fixtures/adoption/。
每次 commit、push 與發佈,每個範本都會跑一遍init;再往下走多深,則看它是為了證明什麼而存在 —— 有的停在「init寫出來的檔案樹」,有的接著跑inspect,而既有專案那個走完整條路,一路到 baseline 棘輪。
安裝步驟一律跳過,只有 workspace 範本例外 —— 它們是開著安裝、拿一個假的exec把指令攔下來,因為只有這樣才驗得到「套件管理工具是從 workspace 根目錄讀出來的,不是從套件本身」(pnpm add -D/yarn add -D)。
所以這一層證明的是「init在真實起始範本上寫出來的檔案樹」與「inspect回報的檢測項目」:它從不執行 ESLint。 - 一致性測試套件 —— 每一則實地回饋的情境都被固化成一個 fixture repo,用 DSL 現搭、走 CLI 自己的分派流程,而且用的是本 repo 開發依賴裡那份真正的 ESLint。
這正是上面那個 e2e 套件當不了的一層:impact與合併存活檢查,只有在真的 ESLint 解析真的 config 時才有意義,所以它們是在這裡被驗的。
真實導入測試找到的新情境,會連同修正一起變成這裡的 fixture。 - Linux 與 Windows,兩邊都要回報 —— CI 在
ubuntu-latest與windows-latest上各跑一次完整檢核,任一邊失敗都不准被另一邊蓋掉。
這個工具會去讀寫別人的 repo,為此帶了好幾條專門處理 Windows 的分支;在 posix 上那些分支等同空操作,所以它們的行為以前從來沒被實際觀察過。
另有一條獨立的流程:用當前版本的 Node 建置,再把建置產物拿到18.18.0上執行 ——engines宣告的下限是被跑出來的,不是宣稱的。 - 你實際會解析到的那個 ESLint 大版本 ——
init安裝eslint時不鎖版本,所以你會落在「每個承載外掛的 peer 範圍都收」的最新大版本上,而那一版比本 repo 自己開發用的還新。
另有一條獨立的流程把那個大版本換進來,拿整套測試在它上面跑一次 —— 所以工具交到你手上的版本是它實際執行過的,不只是宣告允許的。
這條流程刻意不跑本 repo 自己的npm run lint:「這個專案的 config 在新版本上乾不乾淨」跟「blueprint 產出的 config 在那裡還載得起來、規則還守得住」是兩個問題,而只有後者是對你的承諾。 npm run dist:verify—— 行程內測試碰不到的那一層:它實際執行dist/bin.js、解析bin欄位、匯入套件進入點。
它存在的理由是 0.1.1 的那個 bug —— npm 會把 bin 裝成 symlink,少了realpathSync會讓發佈出去的 CLI 什麼都沒做就以 exit 0 收場,而這個狀態在每一項行程內測試裡都是通過的。
CI 建置後跑一次,實際發佈的那個 job 再跑一次,因為 npm 收到的產物是那個 job 產出來的。- 每週的地形檢查 —— 用最新的上游
create-vite與create-next-app範本實際建專案跑導入,範本長相漂移時自動開 issue。
刻意排除在 PR 檢核之外:它依賴網路,而且變數在上游。 - 真實導入測試 —— 讓真正的 agent CLI 帶著真實 repo 走過
init→inspect→impact→doctor,全程無人介入,最後用真的 doctor 驗收。
它負責找新的情境 —— 已知的那些由上面那些套件顧著。
逐項的來龍去脈是公開的,就在本 repo 已關閉的field-runissues。
突變測試是 3.0.0 之後才有的,它稽核的是測試套件本身 —— 問的不是「這行有沒有被測到」,而是「這行如果被改錯,斷言接不接得住」。
測試套件因此大約翻倍,而其中大部分找出來的,都是「原始碼改錯了也會帶著全綠的測試出貨」的地方。
它是需要時手動跑,刻意不當成 gate:分數門檻會是一個每次改 code 就失效的數字,而這個專案的立場是不要一種沒人能安撫的紅燈。
已驗證且通過
Vite + Vue 3(JavaScript、pnpm)
- 專案形態 —— 489 個檔案的正式產品,既有 structure-lint 治理與手寫的 CLAUDE.md
- 結果 —— 依蒐證數據與專案自身的意圖文件推導 config;零檢測項目;
emitLint併入既有的 flat config(結構規則與原有檢查工具證實等價);守則依手寫 CLAUDE.md 自身的結構完成整合;完整測試套件(4,196 項)通過。未修改任何原始碼。
Vite + React + TypeScript(npm、舊制 .eslintrc)
- 專案形態 —— 852 個檔案的正式產品,先前無結構治理
- 結果 —— 依蒐證數據推導 config;246 項真實檢測項目鎖定為基準(包含一條真實的
services → types → resources → services循環依賴);採用分層各異的模組配置(resources為資料夾式模組)。舊制 ESLint config 的遷移列為待決事項,不強制執行。
create-vite react-ts(全新)
- 專案形態 —— 全新專案
- 結果 —— 單一指令完成:preset 建置、精簡守則,程式碼檢查、架構檢測與建置全數通過。
create-vite vue-ts(全新)
- 專案形態 —— 全新專案
- 結果 —— 同上,另附範本整理指引:起始範本的
../assets相對匯入違反 preset —— init 逐項列出違規位置與修正方式(接上匯入別名,共三處小幅修改)。
create-next-app —— App Router、src/、TypeScript
- 專案形態 —— 全新專案
- 結果 —— 單一指令:自動選用
nextPreset(偵測 router 與 srcDir),configapp→components→hooks→lib,架構檢測與next build全數通過;手寫的 CLAUDE / AGENTS 不動。
Next.js —— App Router 位於專案根(無 src/)
- 專案形態 —— 全新專案
- 結果 —— 以
sourceRoot: '.'掃描根層的app/目錄樹;對其反向匯入照常攔截。
Next.js —— Pages Router(src/pages)
- 專案形態 —— 全新專案
- 結果 ——
pages/為頂層;pages/api/*handler 向下匯入lib,無違規。
Monorepo:turbo + pnpm
- 專案形態 —— 以套件為單位導入
- 結果 —— 支援模式:於各套件目錄內執行
blueprint init(pnpm --filter <pkg> exec …)。套件管理工具自工作區根目錄偵測(向上層目錄尋找 lockfile 與pnpm-workspace.yaml)。Blueprint 必須為該套件自身的開發依賴,守則中的node_modules連結方能解析。建議以 turbo 任務逐套件接入blueprint inspect --baseline("inspect": "blueprint inspect --baseline"),再照你原本 gate monorepo 的方式接上即可。
框架注意事項
- Next.js:
init會偵測路由樹(app/與/或pages/,位於src/或專案根),產出nextPreset——
路由目錄即頂層、扁平模組配置,且不設fetch歸屬(server component 本就到處 fetch,強加限制即為造假)。
兩種 router 收斂為同一形態;匯入皆為顯式,依賴圖真實、強制有效。 - Vue 單檔元件:
<script setup>的匯入與一般原始碼相同納入掃描;
Vite 起始範本需將三處資源匯入改走匯入別名。 - Legacy ESLint(
.eslintrc/ v8):導入成本會從「跑個指令」跳成「一次遷移決策」——
flat-config 遷移由你拍板,且 ESLint 原生的 suppressions 帳本需要 ≥ 9.24。
遷移前的過渡姿勢是 severity'warn'(代價:新的度量債不擋);完整 doctrine 見弄紅,然後上棘輪。 - 上游 plugin 的規則漂移:規則改名(例如 typescript-eslint v8 把
no-var-requires併進no-require-imports)會讓舊的 disable 註解在合併途中變 stale ——
只有真的跑起 lint 才會浮現;逐條當合併決策處理,不是 blocker。 - Windows:每次 commit 都會在上面跑完整套檢核,所以那些做路徑正規化的分支(
scan、ignored、impact、相對路徑逃逸規則)是被實際執行的,不是用推論的。
在這個平台上有一件事值得知道:CRLF 換行的tsconfig.json(Windows 的預設)以前會掉進「請自己補上這些 paths」那條路,匯入別名沒被接上,而且什麼都不會說。
現在換行字元是從檔案本身讀出來的,這同時也避免了改動把兩種換行慣例混進同一個檔案 —— 那會被你自己的linebreak-style規則抓。 - 既有結構治理工具並存(structure-lint、dependency-cruiser):將 Blueprint 接於其後時,同名規則由 Blueprint 的語意接管(已於實測專案證實等價);
治理工具的整併列為團隊決策事項,不擅自執行。
不支援
- Nuxt —— blueprint 是依賴靜態匯入分析強制依賴流向在運作的,但 Nuxt 的自動匯入使原始碼不含 import 敘述,這對於 blueprint 來說完全失去檢查依據,
經評估後是選擇不支援 Nuxt 專案:init會直接拒絕,而不是產出一個什麼都查不到的假綠燈。
(未來若補上框架 auto-import 的還原器有機會翻案,但那是實打實的工程,目前沒有規劃。)
尚未驗證
Remix / React Router 框架模式、經 extends 鏈繼承的 tsconfig paths(偵測遺漏時可以 --alias 參數補足)。
如果你在上述環境跑過 blueprint,無論結果通過與否,回報 issue 都是最有價值的貢獻。
