開發
儲存庫結構、工具鏈、建置輸出、測試指令與發行流程。
技術預覽
這個儲存庫產出一個 Go 二進位檔、兩個擴充功能套件、一個 SDK 檔案與文件網站。建置需要 Go 1.27.3 或更新版本、Node 24 與 pnpm 11。封裝發行版本還需要 PATH 中有 tar 與 zstd。
儲存庫結構
| 路徑 | 內容 |
|---|---|
cmd/omw | CLI 進入點:start、serve、stop、status、pair、connection、call、service、skill、install-skill、doctor。 |
internal/bridge | HTTP 與 WebSocket 伺服器、hub 與路由、配對、綁定、CDP 代理、上傳。 |
internal/config | 組態目錄、token、位址、OMW_HOME。 |
internal/service | omw service install 寫入的 launchd 與 systemd 使用者服務。 |
extension/src | 兩個瀏覽器共用的背景 worker、動作、快照、預設集、網路擷取、活動層。extension/src/firefox 存放 Firefox worker 與注入的 page.js。 |
extension/ui | 彈出式視窗與應用程式頁面(初始設定、設定)。使用 Vite、React 19、來自 coss registry 的 Base UI 基礎元件,以及 Tailwind CSS 4。 |
packages/brand | 圖示 SVG 與 theme.css,由擴充功能頁面與文件網站共用。 |
sdk/ | index.ts,也就是打包為 dist/sdk.mjs 的 JavaScript SDK。 |
docs/ | 以 Next 建置的 Fumadocs 網站,採靜態匯出。頁面位於 docs/content/docs;meta.json 決定頁面順序。 |
scripts/ | 建置、過濾清單編譯、發行封裝、發布、稽核。 |
tests/ | Node 測試套件、端對端測試套件與測試資料。 |
benchmarks/ 存放瀏覽器工具的基準測試,examples/ 存放 SDK 指令碼,skills/ 存放由 omw install-skill 安裝的 Agent 技能,third_party/ 存放固定版本的過濾清單及其授權文字。
pnpm-workspace.yaml 列出根套件、docs、extension/ui 與 packages/*,因此 Changesets 會讓根套件與工作區一起升版。
工具鏈
| 工具 | 版本與用途 |
|---|---|
| Go | 1.27.3 或更新版本。唯一的第三方模組是 github.com/coder/websocket。 |
| Node | 24 或更新版本,設定於 engines。執行建置、測試、發行指令碼與文件網站。 |
| pnpm | 11,固定於 packageManager。執行任何指令碼之前,先用 pnpm install 安裝。 |
| TypeScript | 7,嚴格模式。擴充功能與 SDK 在 pnpm run check 中一併檢查。 |
| oxlint 與 oxfmt | 靜態檢查與格式化。oxlint 透過 oxlint-tsgolint 以型別感知模式執行。 |
| Vite | 8,建置擴充功能頁面。esbuild 打包 worker 與 SDK。 |
建置
pnpm install
pnpm run build
go build -trimpath -ldflags='-s -w' -o dist/omw ./cmd/omwmake build 執行相同的三個步驟,其中 pnpm install 帶 --frozen-lockfile。
pnpm run build 執行 scripts/build.mjs,它會:
- 檢查
package.json、兩份擴充功能 manifest,以及internal/bridge/protocol.go中的Version是否為同一個版本。 - 以 esbuild 將
extension/src/worker.ts打包為 ES module,經過壓縮,目標為chrome156。 - 將
extension/src/firefox/worker.ts打包,目標為firefox153,並將extension/src/firefox/page.ts打包為 IIFE。 - 在
extension/ui執行 Vite 建置,並把popup.html、app.html與其資源複製到兩個擴充功能目錄。 - 以 resvg 從
packages/brand/icons的 SVG 轉出工具列圖示與應用程式圖示。 - 編譯過濾清單,並複製所打包的 npm 套件與過濾清單來源的授權文字。
- 將
sdk/index.ts打包為dist/sdk.mjs,目標為 Node 24。 - 寫出
dist/extension.sha256.json與dist/extension-firefox.sha256.json。
輸出為 dist/omw、Chrome 用的 dist/extension、Firefox 用的 dist/extension-firefox,以及 dist/sdk.mjs。Chrome 把 dist/extension 當作未封裝的擴充功能載入。Firefox 把 dist/extension-firefox 當作暫時性擴充功能載入。
擴充功能頁面
彈出式視窗、初始設定頁面與設定頁面是同一個 Vite 專案。extension/ui/vite.config.ts 將 popup.html 與 app.html 列為輸入,以相對 base 建置,讓頁面能從 chrome-extension:// URL 運作,並輸出到 dist/extension-ui。建置也會產生 bundled-modules.json,scripts/build.mjs 用它蒐集頁面套件中每個 npm 模組的授權。
app/app.tsx 依 URL hash 選擇初始設定頁面或設定頁面,因此 app.html#settings 會直接開啓設定頁面。取自 coss registry 的元件位於 extension/ui/src/components/ui,保持 registry 提供的原樣;側欄、步驟清單等組合元件位於 extension/ui/src/components。儲存庫根目錄的 design.md 是這些頁面與文件網站的呈現規則。頁面從 chrome.storage 讀取連線狀態,並自行呼叫 GET /ping 與 POST /pair。WebSocket 由背景 worker 持有。
檢查與測試
pnpm run check
pnpm run format:check
pnpm test
go vet ./...
go test -race ./...make check 執行 go vet、型別感知的靜態檢查與格式檢查。make test 執行 go test -race 與 Node 測試套件。
| 指令 | 執行內容 |
|---|---|
pnpm run build | 上述的完整建置。 |
pnpm run check | oxlint --type-aware --type-check --deny-warnings --format=agent。 |
pnpm run format | oxfmt,並寫入變更。pnpm run format:check 只回報,不寫入。 |
pnpm test | tests/ 中的單元測試套件:SDK、worker、動作、預設集、預設集生命週期、狀態、Firefox、發行與基準測試。 |
pnpm run test:e2e | 針對 Chrome 執行 tests/e2e.test.mjs。需要 CHROME_BIN。 |
pnpm run test:e2e:firefox | 針對 Firefox 執行 tests/e2e-firefox.test.mjs。需要 FIREFOX_BIN。 |
pnpm run test:e2e:dual | 兩個瀏覽器連到同一個 daemon。需要兩個變數。 |
pnpm run test:e2e:firefox-page | 在 Firefox 內執行 page.js。需要 FIREFOX_BIN。 |
pnpm run bench | benchmarks/run.mjs。 |
pnpm run release:plan | 預覽下一個版本,不消耗變更片段。 |
pnpm run release:check | 檢查各處版本是否一致,以及變更片段能否解析;CI 會傳入基準 commit,額外要求已發布的變更必須附有變更片段。 |
pnpm run release:version | 消耗變更片段,並在本機準備版本。 |
pnpm run release:pack | 建置發行封存檔。pnpm run release:audit 驗證它們。 |
端對端測試套件會啓動 dist/omw,並載入 dist/extension 或 dist/extension-firefox,因此請先執行建置。CHROME_BIN 與 FIREFOX_BIN 是瀏覽器二進位檔的絕對路徑。缺少對應變數的測試套件會被略過。
文件網站
pnpm --filter @oh-my-webbridge/docs dev開發伺服器監聽連接埠 3884。頁面是 docs/content/docs 中的 MDX。docs/content/docs/meta.json 依側邊欄順序列出頁面,新頁面必須加到該檔案。每個路徑都以語言段開頭,例如 /zh-tw/sessions/;網站根目錄會依瀏覽器的第一個語言把讀者帶到對應的文件。pnpm --filter @oh-my-webbridge/docs build 產生供 GitHub Pages 使用的靜態匯出。建置時會讀取每個頁面的 Git 歷史,列出貢獻者與頁面歷史,因此需要完整的 clone。
示範影片與螢幕截圖放在孤立分支 assets,Pages 工作流程會把它 checkout 到 docs/public/media。pnpm run media 用 Chrome for Testing 把它們錄到 dist/media;pnpm run media --language zh-TW 以其他介面語言錄製含有擴充功能文字的場景。
翻譯
英文是來源語言。繁體中文(台灣)由英文人工翻譯。pnpm run i18n 用 OpenCC 把 zh-TW 文字轉成簡體中文(zh-CN)以及香港、澳門用字(zh-HK、zh-MO),再用 oxfmt 格式化輸出。只編輯英文與 zh-TW 檔案:其他檔案會被腳本覆寫。產生的檔案與來源不一致時,pnpm run i18n:check 會失敗,CI 會執行這項檢查。
| 文字 | 英文 | zh-TW 來源 | 產生的檔案 |
|---|---|---|---|
extension/locales/ | en.json | zh-TW.json | zh-CN.json、zh-HK.json、zh-MO.json、extension/_locales/ |
docs/content/docs/ | page.mdx、meta.json | page.zh-tw.mdx、meta.zh-tw.json | page.zh-cn.mdx、page.zh-hk.mdx、page.zh-mo.mdx、meta.* |
docs/messages/ | site.en.json | site.zh-tw.json、history.zh-tw.json | zh-cn、zh-hk 與 zh-mo 檔案 |
zh-CN 的轉換先套用 OpenCC 的詞彙表(twp 轉 cn),再套用 scripts/i18n.mjs 裏的中國大陸軟體用語表。zh-HK 與 zh-MO 的轉換只改字形(tw 轉 hk);OpenCC 沒有獨立的澳門標準。
en.json 的每個鍵都必須出現在 zh-TW.json,而且 {placeholders} 相同,否則腳本會停止。翻譯頁面的標題沿用英文標題的錨點,例如 ## 選擇器 [#selectors],讓指向章節的連結在每種語言都有效。
擴充功能頁面、彈出式視窗、工具列標題與活動層使用設定頁選擇的語言,或瀏覽器的語言。瀏覽器擴充功能清單中的擴充功能名稱與説明來自 extension/_locales,一律依瀏覽器語言顯示。
Changesets 與發行
版本號與發行説明來自變更片段,而不是來自 commit 訊息,也不會發布到 npm。
- 每個使用者可見的變更,在
.changeset/下新增一個檔案,並以該變更命名。front matter 記錄升版類型:修正用patch,新功能用minor,破壞性行為用major。 - 內文先寫一個簡短的 H1 標題,接着寫使用者看到的結果、適用的遷移或範圍説明,以及 PR 建立後的 PR 連結。變更片段以 GitHub Flavored Markdown 呈現,因此每個區塊都要正確關閉,原始 HTML 只用於註解,連結以行內方式書寫。
- PR 若變更已發布的輸入,例如原始碼、建置指令碼、相依套件、發行工作流程或擴充功能 manifest,沒有新的變更片段就會讓 CI 失敗。測試與內部文件可以不附。編輯既有的變更片段不算數。
- 推送到
main會維護一個草稿release/next版本 PR。它的工作流程執行scripts/release-pr.mjs,以scripts/release.mjs version消耗變更片段,同步套件、鎖定檔、daemon 與 manifest 的版本,並寫出CHANGELOG.md與docs/releases/<version>.md。 - 版本 PR 合併後,版本工作流程會為
chore(release): prepare <version>這個 commit 建立標籤。該標籤觸發發行工作流程:它重新建置、稽核每個封存檔、上傳資產、驗證其 SHA-256 摘要,之後才發布 GitHub Release。 - GitHub Release 發布後,商店工作流程(
.github/workflows/stores.yml)把omw-<version>-chrome-mv3.zip提交到 Chrome Web Store,並把未簽章的附加元件連同標籤 commit 的git archive與給審查人員的建置説明提交到 addons.mozilla.org。兩個套件都從已發布的 GitHub Release 下載,並以其摘要與SHA256SUMS驗證。各商店審查通過後才發布該版本。商店已有的版本保持不變,因此發行可以重新執行。Chrome 若有另一個版本仍在審查或等待發布,Chrome 的提交會停止。 - Chrome 的工作在
chrome-web-store環境中執行。Google Workload Identity Federation 把工作的 GitHub OIDC token 換成發布者服務帳户的短期 access token。Workload Identity 提供者只接受本儲存庫在該環境中執行的stores.yml,因此不保存任何 Google 金鑰。AMO 的工作從addons-mozilla-org環境的AMO_JWT_ISSUER與AMO_JWT_SECRET這兩個 secret 讀取 AMO 的 JWT issuer 與 JWT secret。被呼叫的工作流程只會收到呼叫端傳入的環境 secret,因此發行工作流程以名稱把這兩個 secret 傳給商店工作流程。兩個環境都只允許從main與v*標籤部署。 - 從
main手動執行商店工作流程會列出各商店的狀態,藉此檢查兩組憑證。在tag輸入填入發行標籤時,這次執行會簽出該標籤,並像發行工作流程一樣提交該標籤已發布的 GitHub Release:gh workflow run stores.yml --ref main -f tag=v0.2.1。商店資訊、螢幕截圖與隱私權問答在各商店的開發人員主控台中編輯。 - 封存檔使用 zstd 層級 3,以
zstd -dc archive.tar.zst | tar -xf - -C DIR解開。
授權
本專案採用 Apache-2.0 授權。NOTICE 存放聲明,THIRD_PARTY.md 列出所打包的過濾清單與 npm 套件。擴充功能建置在 licenses/ 下附上完整的授權文字。