UrsaKit 將 SvelteKit 2 應用升級到 SvelteKit 3 的指南封面

SvelteKit 3 於 2026 年 10 月 1 日發布,而發布說明異常坦白:它是同一個框架,但打磨更多、型別更安全、雜物更少。這對升級是好消息,因為工作大多是機械性的——但仍有幾項變更會碰到大量檔案,所以官方遷移是唯一理性的起點。

本文會先跑遷移,再逐一說明它無法替你完成的四個變更。

01實際上改了什麼

破壞性變更數量不多,但影響範圍很廣:

領域SvelteKit 2SvelteKit 3
框架設定svelte.config.jsvite.config.ts
共用程式碼別名$lib#lib subpath imports
TypeScript 設定extends ./.svelte-kit/tsconfig.jsonextends $app/tsconfig
環境變數隱式在 src/env.ts 宣告
Service worker API$service-worker$app/env、$app/paths、$app/manifest
淺層路由pushState / replaceStategoto(..., { shallow: true })
Vite支援 7需要 8(Rolldown)

另外兩項在正式環境很重要:錯誤處理現在涵蓋 render 錯誤,不只 load 錯誤;而且所有錯誤——包括你自己用 error(...) 丟出的那些——都會經過 handleError。堆疊追蹤現在也套用了 sourcemap。

需要 Svelte 5 與 Vite 8

SvelteKit 3 建立在 Svelte 5 的 error boundary 之上,並需要 Vite 8。若你還在 Svelte 4,請先升到 Svelte 5,並把兩次遷移分開。

02先跑官方遷移

sv CLI 內置遷移,會改寫它能改的部分,並把其餘留成 TODO 清單。請在乾淨、沒有未提交變更的分支上執行。

git checkout -b chore/sveltekit-3
npx sv migrate sveltekit-3 --tasks all --confirm

--tasks all 會依序執行每個遷移任務,--confirm 跳過互動提示,讓執行可重現。動手編輯前先看產生的 TODO 清單——它會告訴你工具無法改寫哪些 import 與設定區塊。

接著更新相依套件,讓工具鏈浮出剩下的問題:

npm install
npx svelte-kit sync
npm run check

svelte-kit sync 會重新產生 tsconfig 與 #lib 變更所依賴的型別。若跳過它,編輯器會回報建置時其實能解析的壞掉 import。

03把設定移進 vite.config.ts

SvelteKit 插件現在在 Vite 需要的地方接收設定,而不是透過非同步解析 svelte.config.js。實務上,你把插件 import 進 vite.config.ts,並把原本的設定物件傳給它。

import { sveltekit } from '@sveltejs/kit/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    sveltekit({
      // 原本 svelte.config.js 的 `kit` 物件。
      adapter: undefined,
      alias: {}
    })
  ]
})

物件的確切形狀記載於 SvelteKit 3 遷移指南,因為它取決於你的應用用了哪個 adapter 與前處理器選項。請把上面的區塊當成目的地,而不是可直接複製的答案:把你的 kit 設定搬過去、刪掉 svelte.config.js,並在真實建置中確認 adapter 能解析,而不是只在 dev 裡。

04把 $lib 換成 #lib

共用程式碼仍放在 src/lib,只有 import 路徑改變。Subpath imports 是 Node 功能,Vite 與 TypeScript 原生支援,這也是 SvelteKit 能刪掉過去同步兩者程式碼的原因。

// SvelteKit 2
import { formatPrice } from '$lib/format'
import { Button } from '$lib/components'

// SvelteKit 3
import { formatPrice } from '#lib/format.ts'
import { Button } from '#lib/components/index.ts'

陷阱在解析。Subpath imports 必須明確,所以單獨的 #lib/format 會失敗,你需要 #lib/format.ts 或 #lib/format/index.ts。遷移任務會自動改寫多數 import;完成後請 grep 出任何殘留的 $lib。

grep -rn "\$lib" src/ --include='*.ts' --include='*.svelte' | head -30

模糊的 subpath import 會在型別檢查時失敗

若 npm run check 回報找不到 #lib/foo,解法幾乎都是補上明確副檔名或 index.ts。這是解析規則,不是 SvelteKit 的 bug。

05簡化 tsconfig 並宣告環境變數

你的 tsconfig.json 不再 extends .svelte-kit 裡的產生檔,而是 extends $app/tsconfig。它帶有更多建議的編譯器選項,所以多數應用可以刪掉自己的 compilerOptions 區塊。你應明確設定 include 與 exclude,並把 service worker 放進 exclude。

環境變數的變更更大。不再到處臨時使用 $env/static/private 之類模組,而是在 src/env.ts 宣告應用依賴的變數,標記每個是公開或私有、在建置時或啟動時解析。Standard Schema 函數庫可以驗證它們。

// src/env.ts —— 形狀示意;確切 API 請查遷移指南。
import { defineEnv } from '$app/env'

export const env = defineEnv({
  DATABASE_URL: { private: true },
  PUBLIC_API_BASE: { public: true, buildTime: true }
})

好處是型別安全、經驗證的變數,在使用處 import,而不是從雜物袋模組拉出來。代價是每個隱式 process.env 參照都需要宣告,漏掉會在建置時而非執行時失敗——這正是目的。

06Service worker、錯誤與淺層路由

三個值得手動檢查的較小變更:

  • Service worker 不再從 $service-worker import,改從 $app/env、$app/paths 與新的 $app/manifest 取得所需內容。若想要準確型別,請在 service worker 旁新增 extends $app/tsconfig/service-worker 的 tsconfig.json。
  • 錯誤處理 現在涵蓋 render 錯誤,且每個錯誤都會經過 handleError。請稽核該函數:過去假設只有 load 錯誤會進來的記錄邏輯,可能突然看到大量流量。
  • 淺層路由 改用 goto(url, { shallow: true }),而非 pushState/replaceState。淺層導覽現在會觸發 beforeNavigate,而 persistState: true 讓頁面狀態在重新載入後保留。

07合併前先驗證升級

  1. 跑 npm run check 並清掉每個型別錯誤,不要繞過它們合併。
  2. 跑正式建置,而不只是 dev,讓 adapter 與 Vite 8 路徑都被走過。
  3. 端到端測一條完整用戶流程,包含 form action 與一條會失敗的路由。
  4. 檢查錯誤回報:觸發一個 render 錯誤,確認它帶著 sourcemap 堆疊抵達 handleError。
  5. 把 vite.config.ts 與舊的 svelte.config.js 做 diff,確認搬移過程中沒有漏掉任何 kit 選項。

讓遷移單獨成為一個 commit

sv 遷移會碰到大量檔案。請讓它單獨提交,再用 diff 工具審查,之後才加入你自己的後續修正。把 200 個檔案的機械式更名與功能開發混在一起,會讓回歸幾乎無法二分定位。

08常見錯誤與修正

錯誤原因修正
找不到模組 #lib/foosubpath import 不明確改用 #lib/foo.ts 或 #lib/foo/index.ts
設定選項沒有作用還留在殘餘的 svelte.config.js搬進 sveltekit() 插件
乾淨 checkout 出現型別錯誤產生的型別過期執行 npx svelte-kit sync
建置時缺少環境變數未在 src/env.ts 宣告宣告它,公開或私有
Service worker 型別失敗舊的 $service-worker import改從 $app/* 模組 import

對小型應用來說,升級是一下午的工作;對大型應用則是一週的謹慎活。但形狀是可預測的:讓 sv 做更名,再把注意力放在設定搬移、環境宣告與錯誤路徑上。那三個地方,是綠色建置仍可能藏著壞掉應用的所在。

常見問題

SvelteKit 3 是重寫嗎?

不是。團隊形容它是同一個框架,但有更多打磨、更好的型別安全與更少的歷史包袱。多數變更是機械性的,官方遷移能處理大部分。

最大的破壞性變更是什麼?

設定從 svelte.config.js 移到 vite.config.ts。其餘都較小,但 #lib 更名與 tsconfig 變更幾乎會碰到大型應用裡的每個檔案。

#lib 一定要寫明確的副檔名嗎?

解析上要。因為這些是 Node subpath imports,TypeScript 與 Node 要求路徑明確,所以 `#lib/foo` 會變成 `#lib/foo.ts` 或 `#lib/foo/index.ts`。

SvelteKit 3 的 remote functions 穩定了嗎?

還沒。remote functions 仍需實驗性旗標,團隊表示完成它是發布後的首要任務。

可以從 Svelte 4 應用直接升級嗎?

SvelteKit 3 需要 Svelte 5,所以實務順序是先升到 Svelte 5,再跑 SvelteKit 遷移。一次做兩件事會讓失敗難以隔離。

返回文章列表

相關文章

相關工具