Bun Shell 腳本完整教學:用 JavaScript 取代 Bash 打造現代化開發環境
你是不是也受夠了在專案裡寫 Bash 腳本?那些神秘的 $?、2>&1、set -euo pipefail 看了就頭痛。好消息是,Bun Shell 讓你可以直接用 JavaScript 寫 Shell 腳本,而且跨平台、型別安全、開發體驗超好。這篇教學帶你從零開始,用 Bun Shell 打造現代化的前端開發環境。
什麼是 Bun Shell?
Bun Shell 是 Bun runtime 內建的 Shell 直譯器,透過 Bun.$ tagged template literal 語法,讓你在 JavaScript/TypeScript 中直接執行 Shell 命令。它不是簡單地呼叫 child_process,而是自帶一套跨平台的 Shell 解析引擎,在 Windows、macOS、Linux 上行為一致。
核心優勢包括:跨平台相容(不依賴系統 Shell)、原生 JavaScript 互通(變數直接傳遞)、內建 Glob 支援、管線與重導向語法、以及比 execa 或 shelljs 更快的執行速度。
安裝 Bun 與環境設定
首先安裝 Bun。在 macOS/Linux 上一行搞定:
curl -fsSL https://bun.sh/install | bash
Windows 使用者可以用 PowerShell:
powershell -c "irm bun.sh/install.ps1 | iex"
安裝完成後,確認版本:
bun --version
# 1.2.x 或更新版本
建立你的第一個 Bun Shell 腳本檔案 scripts/dev.ts,不需要額外安裝套件,Bun.$ 是內建 API。
Bun.$ 語法基礎入門
Bun Shell 的核心是 $ tagged template literal。看看基本用法:
import { $ } from "bun";
// 執行簡單命令
await $`echo "Hello from Bun Shell"`;
// 取得輸出結果
const result = await $`ls -la`.text();
console.log(result);
// 變數插值 — 自動跳脫,防止注入攻擊
const dir = "src/components";
await $`ls ${dir}`;
// 條件執行
const files = await $`find . -name "*.ts" -type f`.text();
const count = files.trim().split("\n").length;
console.log(`共找到 ${count} 個 TypeScript 檔案`);
重點:插值變數會自動跳脫特殊字元,所以不會有 Shell injection 的安全問題,這比 Bash 安全多了。
Glob 模式與檔案匹配
Bun Shell 內建 Glob 支援,跨平台一致(Windows 上也能用 * 和 **):
import { $ } from "bun";
// 列出所有 TypeScript 檔案
await $`echo src/**/*.ts`;
// 搭配 Bun.Glob API 做更細綻的匹配
const glob = new Bun.Glob("**/*.{ts,tsx}");
for await (const file of glob.scan({ cwd: "./src" })) {
console.log(file);
}
// 實際應用:批次處理圖片
await $`mkdir -p dist/images`;
await $`cp public/images/*.{png,jpg,webp} dist/images/`;
跟 Bash 的 Glob 不同,Bun 的 Glob 在所有作業系統上行為一致,不會因為 Windows 的路徑分隔符號而出問題。如果你正在用 Astro 5 Islands 架構 建站,Bun Shell 的 Glob 能讓你更方便地管理靜態資源。
管線串接與輸出重導向
管線(pipe)是 Shell 腳本的精髓,Bun Shell 當然支援:
import { $ } from "bun";
// 管線串接
await $`cat package.json | grep "name"`;
// 多層管線
const topFiles = await $`find src -name "*.ts" | xargs wc -l | sort -rn | head -5`.text();
console.log("行數最多的 5 個檔案:\n", topFiles);
// 輸出重導向
await $`echo "build log" > build.log`;
await $`echo "more logs" >> build.log`;
// 結合 JavaScript 處理管線結果
const deps = await $`cat package.json`.json();
console.log("專案名稱:", deps.name);
console.log("相依套件數:", Object.keys(deps.dependencies || {}).length);
注意 .json() 方法可以直接解析輸出為 JSON 物件,省去 JSON.parse 的步驟。
環境變數管理
Bun Shell 處理環境變數比 Bash 直覺很多:
import { $ } from "bun";
// 讀取環境變數
const nodeEnv = $.env.NODE_ENV ?? "development";
console.log(`當前環境:${nodeEnv}`);
// 設定環境變數給子命令
await $`NODE_ENV=production bun run build`;
// 使用 .env 檔案 — Bun 原生支援,不需要 dotenv
// 直接在 .env 寫入變數,Bun 自動載入
console.log($.env.DATABASE_URL);
// 條件式執行
if ($.env.CI === "true") {
await $`bun test --coverage`;
} else {
await $`bun test`;
}
實戰腳本:自動化開發流程
來寫幾個真正實用的自動化腳本。第一個是完整的專案建置與部署腳本:
import { $ } from "bun";
// 自動化建置腳本
async function build() {
console.log("🔨 開始建置...");
// 清理舊檔案
await $`rm -rf dist`;
// 型別檢查
await $`bun x tsc --noEmit`;
// 執行測試
await $`bun test`;
// 建置專案
await $`bun run build`;
// 產生 build info
const hash = await $`git rev-parse --short HEAD`.text();
const info = { hash: hash.trim(), time: new Date().toISOString() };
await Bun.write("dist/build-info.json", JSON.stringify(info));
console.log("✅ 建置完成!");
}
build().catch(console.error);
第二個範例是開發環境一鍵啟動腳本:
import { $ } from "bun";
// 開發環境啟動
async function dev() {
// 檢查相依套件是否需要更新
const lockfileChanged = await $`git diff --name-only HEAD~1 | grep bun.lockb`.text().catch(() => "");
if (lockfileChanged) {
console.log("📦 偵測到 lockfile 變更,重新安裝...");
await $`bun install`;
}
// 啟動開發伺服器與其他服務
await Promise.all([
$`bun run --watch src/server.ts`,
$`bun run --watch src/worker.ts`,
]);
}
dev();
搭配 Vitest 單元測試一起使用,你可以在腳本中整合完整的 CI 流程。如果你的專案使用 React Compiler,Bun Shell 腳本能幫你自動化編譯驗證的步驟。
Bun Shell vs Bash vs Node.js 比較
| 特性 | Bash | Node.js (execa) | Bun Shell |
|---|---|---|---|
| 跨平台 | 需要 WSL/Git Bash | 部分支援 | 原生跨平台 |
| 型別安全 | 無 | 有 | 有 |
| Glob 支援 | 依賴系統 | 需要額外套件 | 內建 |
| 管線語法 | 原生 | 需要串接 API | 原生語法 |
| 啟動速度 | 快 | 慢(約 100ms) | 極快(約 10ms) |
| 安全性 | 容易注入 | 需手動處理 | 自動跳脫 |
| 學習曲線 | 陡峭 | 中等 | 低(會 JS 就行) |
對於前端團隊來說,Bun Shell 幾乎是最佳選擇:團隊成員不需要額外學 Bash 語法,維護成本大幅降低。
最佳實踐與常見陷阱
幾個使用 Bun Shell 的建議:
- 錯誤處理用 try/catch:命令失敗時會拋出例外,務必包裝
try/catch,不要讓腳本無聲失敗。 - 善用
.quiet():不想看到命令輸出時,用await $`cmd`.quiet()抑制 stdout。 - 避免超長管線:超過 3 層管線建議拆成多個步驟,用 JavaScript 變數串接,可讀性更好。
- 善用
.nothrow():某些命令(如grep)找不到結果時會回傳非零 exit code,用.nothrow()避免不必要的例外。 - 搭配
package.jsonscripts:在package.json中用"scripts": { "dev": "bun run scripts/dev.ts" }統一入口。
如果你正在開發 Next.js 15 Server Actions 的專案,可以把表單處理相關的建置腳本也用 Bun Shell 來寫,統一技術棧。
結語:前端開發環境的未來
Bun Shell 代表了前端工具鏈的一個重要趨勢:用 JavaScript 統一一切。從建置、測試、部署到系統管理,你不再需要在 Bash、Python、Node.js 之間切換。一套語言、一個 runtime,搞定所有自動化需求。
如果你的團隊還在用 Bash 寫 CI 腳本、用 Makefile 管理建置流程,現在是時候試試 Bun Shell 了。學習曲線幾乎為零(你已經會 JavaScript 了),但帶來的開發體驗提升是巨大的。
2026 年的前端開發,不再只是寫元件和樣式。掌握 Bun Shell 這樣的工具,讓你成為真正的全端自動化工程師。
繼續閱讀
Next.js Partial Prerendering (PPR) 完整教學:靜態殼加動態串流大幅提升 LCP
Next.js 15 的 Partial Prerendering(PPR)是近年來前端效能優化最令人興奮的突破之一。它讓你在同一個頁面中,同時擁有靜態內容的極速首屏和動態內容的即時更新。本文深入解析 PPR 的運作原理,並帶你實作靜態殼加動態串流的頁面架構,讓你的 Core Web Vitals 分數大幅提升。
相關文章
Next.js Partial Prerendering (PPR) 完整教學:靜態殼加動態串流大幅提升 LCP
Next.js 15 的 Partial Prerendering(PPR)是近年來前端效能優化最令人興奮的突破之一。它讓你在同一個頁面中,同時擁有靜態內容的極速首屏和動態內容的即時更新。本文深入解析 PPR 的運作原理,並帶你實作靜態殼加動態串流的頁面架構,讓你的 Core Web Vitals 分數大幅提升。
Rspack 2.0 完整指南:Rust 打包工具與 Webpack 遷移實戰 2026
Rspack 2.0 是以 Rust 開發的高效能 webpack 相容打包工具,建構速度比 webpack 快 5-10 倍。
你可能也喜歡
探索其他領域的精選好文