跳至主要内容

高级

打包

在 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.net.cn/package/<name> 上看到它。

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

在此处了解更多信息 here

license

每个包都应该有一个许可字段,以便人们知道他们如何被允许使用它。一个非常流行的许可证在分发和无担保再利用方面也非常宽松,即 MIT

ts
{
"license": "MIT"
}

在此处了解更多信息 here。请注意,你还应该在包中包含一个 LICENSE 文件。

files

这告诉 npm 它将打包哪些文件并上传到 npm。它应该包含你的输出文件夹(默认情况下为 dist)。你的 package.jsonREADMELICENSE 将始终包含在内,因此你无需指定它们。

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

要排除不必要的文件(例如单元测试或仅从 src/routes 等导入的模块),你可以将它们添加到 .npmignore 文件中。这将生成更小的包,安装速度更快。

在此处了解更多信息 here

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 store 库),则可以用 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,你也应该为你的库提供类型定义,以便使用你的库的人在使用时获得适当的智能感知。@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)之外的所有文件都按原样复制。

上一页 浅层路由
下一页 性能