tsdown-migrate

tsdown-migrate

熱門

將 TypeScript 函式庫專案從 tsup 遷移到 tsdown。提供完整的選項對應、設定轉換規則、預設值差異,以及不支援選項的替代方案,讓 AI 代理可以智慧地執行遷移。

4238星標
184分支
更新於 2026/8/28
SKILL.md
唯讀
名稱
tsdown-migrate
描述

將 TypeScript 函式庫專案從 tsup 遷移到 tsdown。提供完整的選項對應、設定轉換規則、預設值差異,以及不支援選項的替代方案,讓 AI 代理可以智慧地執行遷移。

從 tsup 遷移到 tsdown

提供 AI 代理將 tsup 專案遷移到 tsdown(以 Rolldown 為核心的函式庫打包工具)的知識庫。

目標版本:兩階段遷移

tsdown v0.23 移除了所有先前已棄用的 tsup 相容選項——bundleoutExtensionpublicDirremoveNodeProtocolinjectStyleskipNodeModulesBundle 不再被辨識。它們會導致 TypeScript 型別檢查失敗,且在執行時會被靜默忽略,因此在 v0.23+ 上遺漏對應會產生錯誤輸出而不會報錯。直接遷移到 v0.23+ 因此不安全。tsdown v0.22.14 是最後一個仍接受這些選項並對每個選項發出棄用警告的版本,使其成為安全的遷移檢查點。請分兩個階段遷移:

  1. 階段 1——在 tsdown@0.22.14 上遷移:安裝 tsdown@0.22.14,根據下方表格遷移設定,執行建置,並透過將每個標記的 tsup 選項對應到真正的 tsdown 等效選項來解決每個棄用警告。警告是完整性檢查——直到建置產生零警告,遷移才算完成。
  2. 階段 2——升級到最新的 tsdown(^0.23.0 或更新版本):僅在 0.22.14 上建置無警告後進行。由於設定不再使用任何已移除的相容選項,v0.23+ 的靜默忽略行為不再構成風險。

執行需求

tsdown 需要 Node.js ^22.18.0 || ^24.11.0 || >=26.0.0 才能執行(僅建置時期)——也就是 Node.js 22.18+、24.11+ 或 26+。奇數版本和 EOL 發行線(例如 Node.js 23、25)不受支援。打包的輸出仍可透過 target 選項指定較低的 Node.js 版本,因此先前使用 tsup 支援 Node.js 18 / 20 的函式庫在遷移後可以繼續支援。

支援 Node.js 18 / 20 時的建議工作流程:

  • 在 CI 中使用 Node.js 22+ 建置,設定明確的 target,例如 'node18''node20'
  • 在需要支援的較低 Node.js 版本上測試建置輸出(或打包的 tarball)

使用時機

  • 將專案從 tsup 遷移到 tsdown
  • 了解 tsup 和 tsdown 選項之間的差異
  • 檢閱或修正遷移後的設定問題
  • 為使用者提供 tsup→tsdown 相容性建議

遷移概覽

請依照以下步驟遷移 tsup 專案:

  1. 重新命名設定檔tsup.config.*tsdown.config.*
  2. 更新匯入'tsup''tsdown'
  3. 套用選項對應:根據下方表格重新命名/轉換選項
  4. 保留 tsup 預設值:明確設定有差異的選項(format、clean、dts、target)
  5. 更新 package.json:相依套件(階段 1:tsdown@0.22.14)、腳本、根設定欄位
  6. 移除不支援的選項:在有替代方案時替換
  7. 在 0.22.14 上測試建置:執行 tsdown 並解決每個棄用警告——需要零警告
  8. 升級到最新的 tsdown^0.23.0 或更新版本)並再次驗證建置

設定檔遷移

檔案重新命名

tsup tsdown
tsup.config.ts tsdown.config.ts
tsup.config.cts tsdown.config.cts
tsup.config.mts tsdown.config.mts
tsup.config.js tsdown.config.js
tsup.config.cjs tsdown.config.cjs
tsup.config.mjs tsdown.config.mjs
tsup.config.json tsdown.config.json

匯入和識別碼變更

// 之前
import { defineConfig } from 'tsup'

// 之後
import { defineConfig } from 'tsdown'

取代所有識別碼:tsuptsdownTSUPTSDOWN

選項對應

屬性重新命名

tsup tsdown 備註
entryPoints entry 在 tsup 本身也已棄用
cjsInterop cjsDefault CJS 預設匯出處理
esbuildPlugins plugins 現在使用 Rolldown/Unplugin 外掛
outExtension outExtensions 自訂輸出副檔名
publicDir copy 複製靜態檔案到輸出
bundle: true (移除) 打包是預設行為
bundle: false unbundle: true 保留檔案結構
removeNodeProtocol: true nodeProtocol: 'strip' 移除 node: 前綴
injectStyle: true css: { inject: true } CSS 注入
injectStyle: false (移除) 預設行為
skipNodeModulesBundle deps: { neverBundle: true } 將所有相依套件外部化

tsdown v0.23+ 不辨識任何舊名稱——一律使用新名稱。相容選項(outExtensionskipNodeModulesBundlepublicDirbundleremoveNodeProtocolinjectStyle)在 v0.22.14 之前會接受並發出棄用警告,並在 v0.23 中完全移除;在 v0.23+ 上殘留的選項會被靜默忽略,而不是報錯,因此建置會在沒有警告的情況下行為異常。這就是為什麼階段 1 在 v0.22.14 上執行,每個殘留選項都會被標記。

已棄用但仍接受

externalnoExternal 是 tsdown v0.23 仍接受的唯一 tsup 選項名稱。它們會發出棄用警告,將在未來版本中移除,且不能與其替代選項結合使用(將 externaldeps.neverBundle 混合,或將 noExternaldeps.alwaysBundle 混合,會拋出錯誤)。一律使用替代選項。

tsup(已棄用) tsdown(建議) 備註
external: [...] deps: { neverBundle: [...] } 移至 deps 命名空間
noExternal: [...] deps: { alwaysBundle: [...] } 移至 deps 命名空間

輸出檔名差異

對於 IIFE 建置,tsdown 會產生像 [name].iife.js 這樣的名稱,而 tsup 通常產生 [name].global.jsoutExtensions 可以自訂副檔名或後綴,但不會移除內建的 .iife.umd 區段。使用 outputOptions.entryFileNames: '[name].global.js' 來保留舊的 IIFE 檔名。

相依套件命名空間移動

相依套件設定已移至 deps 命名空間下。如果同時存在 externalnoExternal,請合併為單一 deps 物件:

// 之前(tsup)
export default defineConfig({
  external: ['react'],
  noExternal: ['lodash-es'],
})

// 之後(tsdown)
export default defineConfig({
  deps: {
    neverBundle: ['react'],
    alwaysBundle: ['lodash-es'],
  },
})

tsdown 也新增了 deps.onlyBundle(允許打包的套件白名單)——tsup 沒有對應選項。

tsdown v0.23+ 的相依套件處理預設值:

  • dependenciespeerDependenciesoptionalDependencies 預設都會外部化(tsup 只外部化 dependenciespeerDependencies,因此 optionalDependencies 在遷移後可能從打包改為外部化)。
  • deps.resolveDepSubpath(解析外部化套件的子路徑匯入,當沒有 exports 欄位時)預設停用

外掛匯入轉換

// 之前(tsup - esbuild 外掛)
import plugin from 'unplugin-example/esbuild'

// 之後(tsdown - Rolldown 外掛)
import plugin from 'unplugin-example/rolldown'

所有 unplugin-*/esbuild 匯入都應改為 unplugin-*/rolldown

如需每個轉換的完整前後範例,請參閱 guide-option-mappings.md

預設值差異

tsdown 變更了 tsup 的幾個預設值。遷移時,請明確設定這些選項以保留 tsup 行為,然後讓使用者決定要採用哪些新預設值。

選項 tsup 預設值 tsdown 預設值 遷移動作
format 'cjs' 'esm' 設定 format: 'cjs' 以保留
clean false true 設定 clean: false 以保留
dts false 若 package.json 中有 types/typings 則自動啟用 設定 dts: false 以保留
target (無) 自動從 package.json 的 engines.node 讀取 設定 target: false 以保留

遷移後,建議使用者檢閱這些選項——tsdown 的預設值通常更好:

  • ESM 是現代標準
  • 清理輸出可防止過時檔案
  • 從 package.json 自動產生 DTS 可減少設定
  • 從 engines.node 自動設定 target 可確保一致性

不支援的選項

這些 tsup 選項在 tsdown 中沒有直接等效選項。請移除並告知使用者。

tsup 選項 狀態 替代方案
splitting 永遠啟用 移除——tsdown 中無法停用程式碼分割
metafile 不可用 建議使用 devtools: true 進行 Vite DevTools 套件分析
swc 不支援 移除——tsdown 使用 oxc 進行轉換(內建)
experimentalDts 不支援 改用 dts 選項
legacyOutput 不支援 移除——沒有替代方案
plugins(tsup 實驗性) 不相容 手動遷移到 Rolldown 外掛;tsup 的外掛 API 與 Rolldown 不同

Package.json 遷移

腳本

將所有腳本指令中的 tsuptsup-node 替換為 tsdown

// 之前
{
  "scripts": {
    "build": "tsup src/index.ts",
    "dev": "tsup --watch"
  }
}

// 之後
{
  "scripts": {
    "build": "tsdown src/index.ts",
    "dev": "tsdown --watch"
  }
}

相依套件

位置 動作
dependencies.tsup 重新命名為 dependencies.tsdown
devDependencies.tsup 重新命名為 devDependencies.tsdown
optionalDependencies.tsup 重新命名為 optionalDependencies.tsdown
peerDependencies.tsup 重新命名為 peerDependencies.tsdown
peerDependenciesMeta.tsup 重新命名為 peerDependenciesMeta.tsdown

根設定欄位

如果 package.json 有根層級的 tsup 欄位(內聯設定),請重新命名為 tsdown

// 之前
{ "tsup": { "entry": ["src/index.ts"] } }

// 之後
{ "tsdown": { "entry": ["src/index.ts"] } }

如需詳細的 package.json 範例,請參閱 guide-package-json.md

新的 tsdown 功能

遷移後,建議使用者使用這些 tsdown 專屬功能:

功能 設定 描述
Node 協定 nodeProtocol: true | 'strip' 在內建匯入上新增或移除 node: 前綴
Workspace workspace: 'packages/*' 在 monorepo 中建置多個套件
套件匯出 exports: true 自動產生 package.json 中的 exports 欄位
套件驗證 publint: trueattw: true 檢查套件並驗證型別正確性
可執行檔 exe: true 打包為 Node.js 獨立可執行檔(SEA)
DevTools devtools: true Vite DevTools 整合,用於套件分析
Hooks hooks: { 'build:done': ... } 生命週期 hooks:build:preparebuild:beforebuild:done
CSS modules css: { modules: { ... } } .module.css 檔案提供作用域類別名稱
Glob 匯入 globImport: true 支援 import.meta.glob(Vite 風格)

如需詳細比較,請參閱 guide-differences-detailed.md

參考資料

主題 描述 參考
選項對應 每個選項轉換的完整前後對照 guide-option-mappings
詳細差異 架構、功能、相容性比較 guide-differences-detailed
Package.json 相依套件、腳本和設定欄位遷移 guide-package-json

遷移檢查清單

執行遷移時請使用此檢查清單:

- [ ] 重新命名 tsup.config.* → tsdown.config.*
- [ ] 將匯入從 'tsup' 更新為 'tsdown'
- [ ] 將 tsup/TSUP 識別碼替換為 tsdown/TSDOWN
- [ ] 套用屬性重新命名(cjsInterop→cjsDefault、esbuildPlugins→plugins、outExtension→outExtensions、publicDir→copy、bundle→unbundle、removeNodeProtocol→nodeProtocol、injectStyle→css.inject)
- [ ] 將 external/noExternal 移至 deps 命名空間,並將 skipNodeModulesBundle 替換為 `deps.neverBundle: true`
- [ ] 將 unplugin 匯入從 /esbuild 更新為 /rolldown
- [ ] 設定明確的預設值以保留 tsup 行為(format、clean、dts、target)
- [ ] 移除不支援的選項(splitting、metafile、swc 等)
- [ ] 更新 package.json 腳本(tsup→tsdown)
- [ ] 更新 package.json 相依套件(階段 1:tsdown@0.22.14)
- [ ] 如果存在,重新命名根層級的 tsup 設定欄位
- [ ] 在 0.22.14 上執行 tsdown 並解決每個棄用警告(需要零警告)
- [ ] 升級到最新的 tsdown(^0.23.0 或更新版本)並再次驗證建置
- [ ] 向使用者建議新的 tsdown 功能