跳至主要内容

高级

仅服务器模块

在 GitHub 上编辑此页面

SvelteKit 就像一位好朋友,它会保守你的秘密。在同一仓库中编写后端和前端时,很容易将敏感数据意外导入到你的前端代码中(例如,包含 API 密钥的环境变量)。SvelteKit 提供了一种完全防止这种情况的方法:仅服务器模块。

私有环境变量

$env/static/private$env/dynamic/private 模块(在 模块 部分中介绍)只能导入到仅在服务器上运行的模块中,例如 hooks.server.js+page.server.js

仅服务器实用程序

$app/server 模块(其中包含用于从文件系统读取资产的 read 函数)同样只能由在服务器上运行的代码导入。

你的模块

你可以通过两种方式让自己的模块仅限服务器

  • 在文件名中添加 .server,例如 secrets.server.js
  • 将它们放在 $lib/server 中,例如 $lib/server/secrets.js

工作原理

任何时候,只要你有公开代码导入仅服务器代码(无论是直接还是间接)...

$lib/server/secrets.js
ts
export const atlantisCoordinates = [/* redacted */];
Variable 'atlantisCoordinates' implicitly has an 'any[]' type.7005Variable 'atlantisCoordinates' implicitly has an 'any[]' type.
$lib/server/secrets.ts
ts
export const atlantisCoordinates = [
/* redacted */
];
src/routes/utils.js
ts
export { atlantisCoordinates } from '$lib/server/secrets.js';
Cannot find module '$lib/server/secrets.js' or its corresponding type declarations.2307Cannot find module '$lib/server/secrets.js' or its corresponding type declarations.
export const add = (a, b) => a + b;
Parameter 'a' implicitly has an 'any' type.
Parameter 'b' implicitly has an 'any' type.
7006
7006
Parameter 'a' implicitly has an 'any' type.
Parameter 'b' implicitly has an 'any' type.
src/routes/utils.ts
ts
export { atlantisCoordinates } from '$lib/server/secrets.js';
Cannot find module '$lib/server/secrets.js' or its corresponding type declarations.2307Cannot find module '$lib/server/secrets.js' or its corresponding type declarations.
export const add = (a, b) => a + b;
Parameter 'a' implicitly has an 'any' type.
Parameter 'b' implicitly has an 'any' type.
7006
7006
Parameter 'a' implicitly has an 'any' type.
Parameter 'b' implicitly has an 'any' type.
src/routes/+page.svelte
<script>
	import { add } from './utils.js';
</script>

...SvelteKit 将报错

Cannot import $lib/server/secrets.js into public-facing code:
- src/routes/+page.svelte
	- src/routes/utils.js
		- $lib/server/secrets.js

即使面向公众的代码(src/routes/+page.svelte)仅使用 add 导出,而不使用秘密的 atlantisCoordinates 导出,但秘密代码最终可能会出现在浏览器下载的 JavaScript 中,因此导入链被认为不安全。

此功能还适用于动态导入,即使是插值导入,例如 await import(`./${foo}.js`),但有一个小警告:在开发期间,如果面向公众的代码和仅服务器模块之间有两个或更多动态导入,则在首次加载代码时将不会检测到非法导入。

像 Vitest 这样的单元测试框架不会区分仅服务器代码和面向公众的代码。因此,在运行测试时会禁用非法导入检测,如 process.env.TEST === 'true' 所决定。

延伸阅读

上一个 Service workers
下一个 Snapshots