前言
Svelte,一个语法简洁、入门容易,面向未来的前端框架。
从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1:
Svelte 以其独特的编译时优化机制著称,具有轻量级、高性能、易上手等特性,非常适合构建轻量级 Web 项目。
为了帮助大家学习 Svelte,我同时搭建了 Svelte 最新的中文文档站点。
如果需要进阶学习,也可以入手我的小册《Svelte 开发指南》,语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!
欢迎围观我的“网页版朋友圈”、加入“冴羽·成长陪伴社群”,踏上“前端大佬成长之路”。
Node 服务端
要生成独立的 Node 服务端,请使用 adapter-node
。
使用方法
使用 npm i -D @sveltejs/adapter-node
安装,然后将适配器添加到您的 svelte.config.js
:
// @errors: 2307
/// file: svelte.config.js
import adapter from '@sveltejs/adapter-node';export default {kit: {adapter: adapter()}
};
部署
首先,使用 npm run build
构建您的应用。这将在适配器选项中指定的输出目录(默认为 build
)中创建生产服务端。
要运行应用程序,您需要输出目录、项目的 package.json
和 node_modules
中的生产依赖项。生产依赖项可以通过复制 package.json
和 package-lock.json
然后运行 npm ci --omit dev
来生成(如果您的应用没有任何依赖项,可以跳过此步骤)。然后您可以使用以下命令启动您的应用:
node build
开发依赖项将使用 Rollup 打包到您的应用中。要控制某个包是打包还是外部化,请将其分别放在 package.json
的 devDependencies
或 dependencies
中。
压缩响应
通常您会希望压缩来自服务端的响应。如果您已经在为 SSL 或负载均衡部署了反向代理服务端,那么在该层处理压缩通常会带来更好的性能,因为 Node.js 是单线程的。
但是,如果您正在构建自定义服务端并确实想在那里添加压缩中间件,请注意我们建议使用 @polka/compression
,因为 SvelteKit 会流式传输响应,而更流行的 compression
包不支持流式传输,使用时可能会导致错误。
环境变量
在 dev
和 preview
模式下,SvelteKit 将从您的 .env
文件(或 .env.local
,或 .env.[mode]
,由 Vite 决定)中读取环境变量。
在生产环境中,不会自动加载 .env
文件。要做到这一点,请在您的项目中安装 dotenv
...
npm install dotenv
...并在运行构建的应用之前调用它:
node +++-r dotenv/config+++ build
如果您使用的是 Node.js v20.6+,您可以使用 --env-file
标志代替:
node +++--env-file=.env+++ build
PORT
, HOST
和 SOCKET_PATH
默认情况下,服务端将使用 0.0.0.0
并在端口 3000 上接受连接。可以使用 PORT
和 HOST
环境变量对其进行自定义:
HOST=127.0.0.1 PORT=4000 node build
或者,还可以配置服务端在指定的 socket 路径上接受连接。如果您使用 SOCKET_PATH
环境变量来执行此操作,则会忽略 HOST
和 PORT
环境变量。
SOCKET_PATH=/tmp/socket node build
ORIGIN
, PROTOCOL_HEADER
, HOST_HEADER
和 PORT_HEADER
HTTP 并不会为 SvelteKit 提供一种可靠的方法来获取当前请求的 URL。最简单的方式是设置 ORIGIN
环境变量来告诉 SvelteKit 应用在哪里被提供服务:
ORIGIN=https://my.site node build# 或者,例如本地预览和测试
ORIGIN=http://localhost:3000 node build
这样,当请求 /stuff
路径名时,就能正确解析到 https://my.site/stuff
。或者,您可以指定用于告诉 SvelteKit 关于请求协议和主机的标头,由此 SvelteKit 可以构建 origin URL:
PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host node build
[!NOTE]
x-forwarded-proto
和x-forwarded-host
是事实上的标准请求头,用于在使用反向代理(如负载均衡器和 CDN)时转发原始协议和主机。只有在您的服务端位于受信任的反向代理之后时,才应设置这些变量;否则,客户端可能会伪造这些标头。
如果您在非标准端口托管代理,并且您的反向代理支持x-forwarded-port
,您也可以设置PORT_HEADER=x-forwarded-port
。
如果 adapter-node
无法正确确定您的部署的 URL,在使用 表单 actions 时可能会出现以下错误:
[!NOTE] Cross-site POST form submissions are forbidden
ADDRESS_HEADER
和 XFF_DEPTH
传递给 hooks 和端点的 RequestEvent 对象包含一个 event.getClientAddress()
函数,用于返回客户端的 IP 地址。默认情况下,这是发起连接的 remoteAddress
。如果您的服务器位于一个或多个代理(如负载均衡器)之后,这个值将包含最内部代理的 IP 地址,而不是客户端的 IP 地址,因此我们需要指定一个 ADDRESS_HEADER
读取地址:
ADDRESS_HEADER=True-Client-IP node build
[!NOTE] 标头很容易被伪造。与
PROTOCOL_HEADER
和HOST_HEADER
一样,只有在您了解相关风险的情况下才应设置这些变量。
如果 ADDRESS_HEADER
是 X-Forwarded-For
,其值会包含用逗号分隔的 IP 地址列表。此时应通过 XFF_DEPTH
环境变量指定在您的服务器前有多少个受信任的代理。例如,如果有三个受信任的代理,代理 3 会转发客户端原始连接和前两个代理的地址:
<client address>, <proxy 1 address>, <proxy 2 address>
有些指南会告诉您读取最左边的地址,但这样会容易被伪造:
<spoofed address>, <client address>, <proxy 1 address>, <proxy 2 address>
因此,我们从右侧读取,并依据受信任的代理数量进行处理。在这个示例里,我们会使用 XFF_DEPTH=3
。
[!NOTE] 如果您确实需要读取最左侧的地址(并且不在意被伪造)——例如提供地理位置服务,在此情况下,IP 地址“真实性”比“可信度”更重要,您可以在应用中自行检查
x-forwarded-for
标头来实现这一点。
BODY_SIZE_LIMIT
接受的最大请求体大小,以字节为单位(包括流式传输时)。
请求体大小也可以使用单位后缀指定,包括千字节(K)、兆字节(M)或千兆字节(G)。例如 512K
或 1M
。默认值为 512kb。
您可以设置值为 Infinity
(在适配器的旧版本中为 0)来禁用此选项,如果需要更高级的功能,可以在 handle
中自行实现更高级的检查逻辑。
SHUTDOWN_TIMEOUT
接收到 SIGTERM
或 SIGINT
信号后,在强制关闭任何剩余连接之前等待的秒数。默认值是 30
。在内部,适配器会调用 closeAllConnections
。更多细节请参见 优雅关闭。
IDLE_TIMEOUT
在使用 systemd 套接字激活时,IDLE_TIMEOUT
用于指定当应用在没有请求的情况下经过多少秒会自动休眠。如果未设置,则应用会一直运行。详见 套接字激活 获取更多信息。
Options
该适配器可以通过多种选项进行配置:
// @errors: 2307
/// file: svelte.config.js
import adapter from '@sveltejs/adapter-node';export default {kit: {adapter: adapter({// 以下为默认选项out: 'build',precompress: true,envPrefix: ''})}
};
out
构建服务端输出的目录,默认为 build
—— 也就是说,如果您使用默认目录,执行 node build
将在本地启动服务端。
precompress
使用 gzip 和 brotli 对资源和预渲染页面进行预压缩。默认值为 true
。
envPrefix
如果您需要更改用于配置部署的环境变量名称(例如,与您无法控制的环境变量冲突),可以指定一个前缀:
envPrefix: 'MY_CUSTOM_';
MY_CUSTOM_HOST=127.0.0.1 \
MY_CUSTOM_PORT=4000 \
MY_CUSTOM_ORIGIN=https://my.site \
node build
优雅关闭
默认情况下,当接收到 SIGTERM
或 SIGINT
信号时,adapter-node
会优雅地关闭 HTTP 服务器。它将:
- 拒绝新的请求(
server.close
) - 等待已经发出的请求但尚未收到响应的请求完成,并在连接变为空闲后关闭连接(
server.closeIdleConnections
) - 最后,在超过
SHUTDOWN_TIMEOUT
秒后强制关闭所有仍处于活动状态的连接(server.closeAllConnections
)。
[!NOTE] 如果您想自定义这一行为,您可以使用自定义服务端。
您还可以监听 sveltekit:shutdown
事件,该事件会在 HTTP 服务器关闭全部连接后触发。与 Node 的 exit
事件不同,sveltekit:shutdown
事件支持异步操作,并且无论服务器是否有未完成的任务(如未关闭的数据库连接),在所有连接都关闭后都会被触发:
// @errors: 2304
process.on('sveltekit:shutdown', async (reason) => {await jobs.stop();await db.close();
});
参数 reason
的可能取值包括:
SIGINT
- 关机由SIGINT
信号触发SIGTERM
- 关机由SIGTERM
信号触发IDLE
- 关机由IDLE_TIMEOUT
触发
套接字激活
当今大多数 Linux 操作系统都使用名为 systemd 的现代进程管理器来启动、运行和管理服务。您可以配置服务器来分配一个套接字,并在需要时按需启动应用。这被称为 套接字激活。在这种情况下,操作系统会向您的应用传递两个环境变量:LISTEN_PID
和 LISTEN_FDS
。然后,适配器会在文件描述符 3 上进行监听,该描述符对应您创建的 systemd 套接字单元。
[!NOTE] 您仍然可以在 systemd 套接字激活中使用
envPrefix
。LISTEN_PID
和LISTEN_FDS
始终无需前缀即可读取。
要利用套接字激活,请按以下步骤操作:
- 让您的应用作为一个 systemd 服务 运行。它既可以直接运行在主机系统上,也可以在容器内(例如使用 Docker 或 systemd 可移植服务)运行。
如果您额外向应用传递一个 IDLE_TIMEOUT
环境变量,它将在没有请求持续 IDLE_TIMEOUT
秒时,优雅地关闭。之后如果有新的请求到来,systemd 将自动重新启动您的应用。
/// file: /etc/systemd/system/myapp.service
[Service]
Environment=NODE_ENV=production IDLE_TIMEOUT=60
ExecStart=/usr/bin/node /usr/bin/myapp/build
- 创建一个配套的 socket 单元。适配器仅接受单个 socket。
/// file: /etc/systemd/system/myapp.socket
[Socket]
ListenStream=3000[Install]
WantedBy=sockets.target
- 通过运行
sudo systemctl daemon-reload
确保 systemd 识别了这两个单元。然后使用sudo systemctl enable --now myapp.socket
在启动时启用该 socket 并立即启动它。这样当第一个请求到达localhost:3000
时,应用将自动启动。
自定义服务端
该适配器会在您的构建目录中创建两个文件——index.js
和 handler.js
。运行 index.js
(例如,如果您使用默认 build
目录,那么执行 node build
)将会在指定端口上启动服务器。
或者,您可以导入 handler.js
文件,它导出一个兼容 Express、Connect 或 Polka (甚至是内置的 http.createServer
)的处理程序,并且设置你自己的服务器:
// @errors: 2307 7006
/// file: my-server.js
import { handler } from './build/handler.js';
import express from 'express';const app = express();// 添加一个独立于 SvelteKit 应用的路由
app.get('/healthcheck', (req, res) => {res.end('ok');
});// 让 SvelteKit 处理其他所有内容,包括提供预渲染页面和静态资源
app.use(handler);app.listen(3000, () => {console.log('listening on port 3000');
});
Svelte 中文文档
点击查看中文文档 - SvelteKit Node 服务端。
系统学习 Svelte,欢迎入手小册《Svelte 开发指南》。语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!
此外我还写过 JavaScript 系列、TypeScript 系列、React 系列、Next.js 系列、冴羽答读者问等 14 个系列文章, 全系列文章目录:https://github.com/mqyqingfeng/Blog
欢迎围观我的“网页版朋友圈”、加入“冴羽·成长陪伴社群”,踏上“前端大佬成长之路”。