高级
打包
在 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.json
、README
和 LICENSE
将始终包含在内,因此你无需指定它们。
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 {Cannot find module 'your-library' or its corresponding type declarations.2307Cannot find module 'your-library' or its corresponding type declarations.Something } from'your-library' ;
types
和 svelte
键是 导出条件。当它们查找 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
importFoo 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 起可用,未来最佳推荐选项)、node16
或 nodenext
。这会选择 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.js
或 tsconfig.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.json
的exports
应指向其中的文件,并且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.json
或 jsconfig.json
中设置 "moduleResolution": "NodeNext"
将对此有所帮助。
除了 Svelte 文件(预处理)和 TypeScript 文件(转译为 JavaScript)之外的所有文件都按原样复制。