跳到主要內容

進階

封裝

在 GitHub 上編輯此頁面

你可以使用 SvelteKit 來建置應用程式以及元件函式庫,使用 @sveltejs/package 套件(npm create svelte 有個選項可以幫你設定)。

當你建立應用程式時,src/routes 的內容是公開的;src/lib 包含你的應用程式的內部函式庫。

元件函式庫的結構與 SvelteKit 應用程式完全相同,但 src/lib 是公開的部分,而你的根目錄 package.json 用於發布套件。src/routes 可能是一個文件或範例網站,附屬於函式庫,或者它可能只是你在開發期間使用的沙盒。

@sveltejs/package 執行 svelte-package 指令將會取得 src/lib 的內容並產生一個 dist 目錄(可以 設定),其中包含以下內容

  • src/lib 中的所有檔案。Svelte 元件將會經過預處理,TypeScript 檔案將會轉譯成 JavaScript。
  • 為 Svelte、JavaScript 和 TypeScript 檔案產生的類型定義(d.ts 檔案)。你需要安裝 typescript >= 4.0.0 才能執行此動作。類型定義會放在它們的實作旁邊,手寫的 d.ts 檔案會照原樣複製。你可以 停用產生,但我們強烈建議不要這麼做 — 使用你的函式庫的人可能會使用 TypeScript,而他們需要這些類型定義檔案。

@sveltejs/package 版本 1 會產生一個 package.json。這不再是這樣,它現在會使用專案中的 package.json 並驗證它是否正確。如果您仍在版本 1,請參閱 此 PR 以取得遷移說明。

package.json 的解剖

由於您現在正在建置一個供公開使用的函式庫,因此 package.json 的內容將變得更加重要。透過它,您可以設定套件的進入點、發佈到 npm 的檔案,以及函式庫的相依性。讓我們逐一了解最重要的欄位。

name

這是套件的名稱。其他人可以使用該名稱安裝它,並在 https://npmjs.com/package/<name> 上看到它。

ts
{
"name": "your-library"
}

在此處 了解更多

license

每個套件都應該有一個授權欄位,以便人們知道他們如何被允許使用它。一個非常流行的授權,在不提供保證的情況下,在分發和重複使用方面也非常寬鬆,就是 MIT

ts
{
"license": "MIT"
}

在此處 了解更多。請注意,您還應該在套件中包含一個 LICENSE 檔案。

files

這會告訴 npm 它會打包哪些檔案並上傳到 npm。它應該包含您的輸出資料夾(預設為 dist)。您的 package.jsonREADMELICENSE 將永遠包含在內,因此您不需要指定它們。

ts
{
"files": ["dist"]
}

若要排除不必要的檔案(例如單元測試或僅從 src/routes 等匯入的模組),您可以將它們新增到 .npmignore 檔案中。這將產生較小的套件,安裝速度也更快。

在此處 了解更多

exports

"exports" 欄位包含套件的進入點。如果您透過 npm create svelte@latest 設定新的函式庫專案,它會設定為單一匯出,也就是套件根目錄

ts
{
"exports": {
".": {
"types": "./dist/index.d.ts",
"svelte": "./dist/index.js"
}
}
}

這會告訴打包器和工具,您的套件只有一個進入點,也就是根目錄,所有內容都應該透過它匯入,如下所示

ts
import { Something } from 'your-library';
Cannot find module 'your-library' or its corresponding type declarations.2307Cannot find module 'your-library' or its corresponding type declarations.

typessvelte 鍵是 匯出條件。它們會告訴工具在查詢 your-library 匯入時要匯入哪個檔案

  • TypeScript 會看到 types 條件並查詢類型定義檔。如果您未發布類型定義,請省略此條件。
  • Svelte 認識的工具會看到 svelte 條件並知道這是一個 Svelte 元件程式庫。如果您發布的程式庫未匯出任何 Svelte 元件,而且也可以在非 Svelte 專案中運作(例如 Svelte 儲存程式庫),您可以將此條件替換為 default

@sveltejs/package 的先前版本也新增了 package.json 匯出。這不再是範本的一部分,因為所有工具現在都可以處理未明確匯出的 package.json

您可以根據喜好調整 exports 並提供更多進入點。例如,如果您想要直接公開 src/lib/Foo.svelte 元件,而不是重新匯出元件的 src/lib/index.js 檔案,您可以建立以下匯出對應...

ts
{
"exports": {
"./Foo.svelte": {
"types": "./dist/Foo.svelte.d.ts",
"svelte": "./dist/Foo.svelte"
}
}
}

...而您的程式庫使用者可以像這樣匯入元件

ts
import Foo from 'your-library/Foo.svelte';

請注意,如果您提供類型定義,執行此操作需要額外的注意。進一步閱讀 此處 的注意事項

一般來說,匯出對應的每個金鑰都是使用者必須用來從您的套件匯入某些內容的路徑,而值是將被匯入的檔案路徑,或包含這些檔案路徑的匯出條件對應。

進一步閱讀 此處exports

svelte

這是一個舊欄位,讓工具可以辨識 Svelte 元件程式庫。當使用 svelte 匯出條件 時,不再需要它,但為了與尚未知道匯出條件的過時工具保持向後相容性,最好保留它。它應該指向您的根進入點。

ts
{
"svelte": "./dist/index.js"
}

TypeScript

您應該為您的程式庫發布類型定義,即使您自己不使用 TypeScript,這樣使用您的程式庫的人在使用時可以獲得適當的 IntelliSense。@sveltejs/package 讓產生類型的過程對您來說大多是模糊的。預設情況下,在封裝您的程式庫時,會自動為 JavaScript、TypeScript 和 Svelte 檔案產生類型定義。您只需要確保 exports 對應中的 types 條件指向正確的檔案。當透過 npm create svelte@latest 初始化程式庫專案時,這會自動設定為根匯出。

然而,如果您有根目錄匯出以外的其他項目,例如提供 your-library/foo 匯入,您需要特別注意提供類型定義。很遺憾的是,預設情況下,TypeScript 不會 解析像 { "./foo": { "types": "./dist/foo.d.ts", ... }} 這樣的匯出的 types 條件。相反地,它會在您的程式庫根目錄中搜尋 foo.d.ts(也就是 your-library/foo.d.ts,而不是 your-library/dist/foo.d.ts)。要解決這個問題,您有兩個選項

第一個選項是要求使用您的程式庫的人在他們的 tsconfig.json(或 jsconfig.json)中將 moduleResolution 選項設定為 bundler(自 TypeScript 5 起可用,未來最佳且建議的選項)、node16nodenext。這會讓 TypeScript 實際查看匯出對應並正確解析類型。

第二個選項是(濫)用 TypeScript 的 typesVersions 功能來連結類型。這是 package.json 中的一個欄位,TypeScript 用來根據 TypeScript 版本檢查不同的類型定義,其中也包含路徑對應功能。我們利用該路徑對應功能來取得我們要的。對於上面提到的 foo 匯出,對應的 typesVersions 如下所示

ts
{
"exports": {
"./foo": {
"types": "./dist/foo.d.ts",
"svelte": "./dist/foo.js"
}
},
"typesVersions": {
">4.0": {
"foo": ["./dist/foo.d.ts"]
}
}
}

>4.0 告訴 TypeScript,如果使用的 TypeScript 版本大於 4(實際上應該總是如此),則檢查內部對應。內部對應告訴 TypeScript,your-library/foo 的類型定義位於 ./dist/foo.d.ts 中,這基本上複製了 exports 條件。您也可以使用萬用字元 *,一次提供多個類型定義,而不用重複輸入。請注意,如果您選擇 typesVersions,您必須透過它宣告所有類型匯入,包括根目錄匯入(定義為 "index.d.ts": [..])。

您可以在 這裡 閱讀更多關於該功能的資訊。

最佳實務

除非您打算讓套件只能供其他 SvelteKit 專案使用,否則您應避免在套件中使用 SvelteKit 特定模組,例如 $app。例如,與其使用 import { browser } from '$app/environment',您可以使用 import { BROWSER } from 'esm-env' (請參閱 esm-env 文件)。您可能還希望傳入諸如目前 URL 或導覽動作等內容作為道具,而不是直接依賴 $app/stores$app/navigation 等。以這種更通用的方式撰寫您的應用程式,將讓設定測試工具、UI 示範等變得更為容易。

請務必透過 svelte.config.js (而非 vite.config.jstsconfig.json) 新增 別名,以便 svelte-package 處理這些別名。

您應仔細思考對套件所做的變更是錯誤修正、新功能或重大變更,並相應地更新套件版本。請注意,如果您從現有函式庫中移除 exports 中的任何路徑或其中的任何 export 條件,應視為重大變更。

{
	"exports": {
		".": {
			"types": "./dist/index.d.ts",
// changing `svelte` to `default` is a breaking change:
			"svelte": "./dist/index.js"
			"default": "./dist/index.js"
		},
// removing this is a breaking change:
		"./foo": {
			"types": "./dist/foo.d.ts",
			"svelte": "./dist/foo.js",
			"default": "./dist/foo.js"
		},
// adding this is ok:
		"./bar": {
			"types": "./dist/bar.d.ts",
			"svelte": "./dist/bar.js",
			"default": "./dist/bar.js"
		}
	}
}

選項

svelte-package 接受下列選項

  • -w/--watch — 監控 src/lib 中的檔案是否有變更,並重新建置套件
  • -i/--input — 包含套件所有檔案的輸入目錄。預設為 src/lib
  • -o/--o — 處理後的檔案寫入的輸出目錄。您的 package.jsonexports 應指向該目錄內的檔案,且 files 陣列應包含該資料夾。預設為 dist
  • -t/--types — 是否建立類型定義 (d.ts 檔案)。我們強烈建議這麼做,因為它能促進生態系函式庫的品質。預設為 true
  • --tsconfig - tsconfig 或 jsconfig 的路徑。未提供時,會在工作區路徑中搜尋下一個上層 tsconfig/jsconfig。

發布

發布已產生的套件

npm publish

注意事項

所有相對檔案匯入都必須完全指定,並遵守 Node 的 ESM 演算法。這表示對於像 src/lib/something/index.js 這樣的檔案,您必須包含帶有副檔名的檔案名稱

import { something } from './something';
import { something } from './something/index.js';

如果您使用的是 TypeScript,您需要以相同的方式匯入 .ts 檔案,但使用 .js 檔案結尾,而不是 .ts 檔案結尾。(這是我們無法控制的 TypeScript 設計決策。)在您的 tsconfig.jsonjsconfig.json 中設定 "moduleResolution": "NodeNext" 將有助於您解決此問題。

除了 Svelte 檔案(已預處理)和 TypeScript 檔案(已轉譯為 JavaScript)之外,所有檔案都會按原樣複製。

上一個 淺層路由
下一個 效能