跳到主要内容

构建和部署

Node 服务器

在 GitHub 上编辑此页面

要生成一个独立的 Node 服务器,请使用 adapter-node

用法

使用 npm i -D @sveltejs/adapter-node 安装,然后将适配器添加到你的 svelte.config.js

svelte.config.js
ts
import adapter from '@sveltejs/adapter-node';
Cannot find module '@sveltejs/adapter-node' or its corresponding type declarations.2307Cannot find module '@sveltejs/adapter-node' or its corresponding type declarations.
export default {
kit: {
adapter: adapter()
}
};

部署

首先,使用 npm run build 构建你的应用。这将在适配器选项中指定的输出目录(默认为 build)中创建生产服务器。

你需要输出目录、项目的 package.json 以及 node_modules 中的生产依赖项才能运行应用程序。生产依赖项可以通过复制 package.jsonpackage-lock.json 然后运行 npm ci --omit dev 来生成(如果你的应用没有任何依赖项,你可以跳过此步骤)。然后,你可以使用此命令启动你的应用

node build

开发依赖项将使用 Rollup 捆绑到你的应用中。若要控制给定包是捆绑还是外部化,请将其分别放在 package.json 中的 devDependenciesdependencies 中。

压缩响应

你通常希望压缩来自服务器的响应。如果你已经将你的服务器部署在反向代理之后以进行 SSL 或负载均衡,那么通常在该层也处理压缩可以获得更好的性能,因为 Node.js 是单线程的。

然而,如果你正在构建一个自定义服务器并想要添加一个压缩中间件,请注意,我们建议使用@polka/compression,因为 SvelteKit 会流式传输响应,而更流行的compression包不支持流式传输,并且在使用时可能会导致错误。

环境变量

devpreview中,SvelteKit 将从你的.env文件(或.env.local,或.env.[mode]由 Vite 决定)读取环境变量。

在生产中,不会自动加载.env文件。要做到这一点,在你的项目中安装dotenv...

npm install dotenv

...并在运行已构建的应用程序之前调用它

node build
node -r dotenv/config build

PORT、HOST 和 SOCKET_PATH

默认情况下,服务器将在端口 3000 上接受0.0.0.0上的连接。这些可以通过PORTHOST环境变量进行自定义

HOST=127.0.0.1 PORT=4000 node build

或者,可以将服务器配置为接受指定套接字路径上的连接。当使用SOCKET_PATH环境变量完成此操作时,将忽略HOSTPORT环境变量。

SOCKET_PATH=/tmp/socket node build

ORIGIN、PROTOCOL_HEADER、HOST_HEADER 和 PORT_HEADER

HTTP 没有给 SvelteKit 一个可靠的方法来了解当前正在请求的 URL。告诉 SvelteKit 应用程序在哪里提供服务的最快捷方法是设置ORIGIN环境变量

ORIGIN=https://my.site node build

# or e.g. for local previewing and testing
ORIGIN=https://127.0.0.1:3000 node build

有了这个,对/stuff路径名的请求将正确解析为https://my.site/stuff。或者,你可以指定告诉 SvelteKit 请求协议和主机的标头,从中可以构建原始 URL

PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host node build

x-forwarded-protox-forwarded-host是事实上的标准标头,如果你正在使用反向代理(想想负载均衡器和 CDN),它们会转发原始协议和主机。你应该只在你的服务器位于受信任的反向代理之后时设置这些变量;否则,客户端可能会欺骗这些标头。

如果你正在非标准端口上托管你的代理,并且你的反向代理支持x-forwarded-port,你还可以设置PORT_HEADER=x-forwarded-port

如果adapter-node无法正确确定你的部署的 URL,你可能会在使用表单操作时遇到此错误

禁止跨站点 POST 表单提交

ADDRESS_HEADER 和 XFF_DEPTH

传递给钩子和端点的 RequestEvent 对象包括一个 event.getClientAddress() 函数,该函数返回客户端的 IP 地址。默认情况下,这是连接的 remoteAddress。如果你的服务器位于一个或多个代理后面(例如负载均衡器),此值将包含最内层代理的 IP 地址,而不是客户端的 IP 地址,因此我们需要指定一个 ADDRESS_HEADER 来读取地址

ADDRESS_HEADER=True-Client-IP node build

标头很容易被欺骗。与 PROTOCOL_HEADERHOST_HEADER 一样,在设置这些标头之前,你应该 了解你在做什么

如果 ADDRESS_HEADERX-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

如果你需要改用读取最左边的地址(并且不关心欺骗)——例如,提供地理位置服务,其中 IP 地址是真实的受信任的更重要,你可以在你的应用中检查 x-forwarded-for 标头来实现此目的。

BODY_SIZE_LIMIT

接受的最大请求正文大小(以字节为单位),包括流式传输时。默认为 512kb。你可以使用 Infinity 值(在旧版本的适配器中为 0)禁用此选项,并在 handle 中实现自定义检查,如果你需要更高级的功能。

SHUTDOWN_TIMEOUT

在接收到 SIGTERMSIGINT 信号后强制关闭任何剩余连接之前等待的秒数。默认为 30。在内部,适配器调用 closeAllConnections。有关更多详细信息,请参阅 优雅关闭

IDLE_TIMEOUT

使用 systemd 套接字激活时,IDLE_TIMEOUT 指定在没有收到请求后自动使应用程序进入休眠状态的秒数。如果未设置,应用程序将持续运行。有关更多详细信息,请参见 套接字激活

选项

该适配器可以通过各种选项进行配置

svelte.config.js
ts
import adapter from '@sveltejs/adapter-node';
Cannot find module '@sveltejs/adapter-node' or its corresponding type declarations.2307Cannot find module '@sveltejs/adapter-node' or its corresponding type declarations.
export default {
kit: {
adapter: adapter({
// default options are shown
out: 'build',
precompress: true,
envPrefix: ''
})
}
};

out

用于构建服务器的目录。默认为 build — 即 node build 将在创建服务器后在本地启动服务器。

precompress

启用对资产和预渲染页面的 gzip 和 brotli 预压缩。默认为 true

envPrefix

如果您需要更改用于配置部署的环境变量的名称(例如,为了避免与您无法控制的环境变量发生冲突),您可以指定一个前缀

ts
envPrefix: 'MY_CUSTOM_';
MY_CUSTOM_HOST=127.0.0.1 \
MY_CUSTOM_PORT=4000 \
MY_CUSTOM_ORIGIN=https://my.site \
node build

优雅关闭

默认情况下,当收到 SIGTERMSIGINT 信号时,adapter-node 会优雅地关闭 HTTP 服务器。它将

  1. 拒绝新请求 (server.close)
  2. 等待已经发出但尚未收到响应的请求完成,并在它们变为闲置后关闭连接 (server.closeIdleConnections)
  3. 最后,在 SHUTDOWN_TIMEOUT 秒后关闭任何仍然处于活动状态的剩余连接。(server.closeAllConnections)

如果您想要自定义此行为,可以使用 自定义服务器

套接字激活

当今大多数 Linux 操作系统使用名为 systemd 的现代进程管理器来启动服务器并运行和管理服务。您可以配置服务器以分配套接字并按需启动和扩展您的应用程序。这称为 套接字激活。在这种情况下,操作系统会将两个环境变量传递给您的应用程序 — LISTEN_PIDLISTEN_FDS。然后,适配器将侦听文件描述符 3,该文件描述符引用您必须创建的 systemd 套接字单元。

您仍然可以在 systemd 套接字激活中使用 envPrefixLISTEN_PIDLISTEN_FDS 始终在没有前缀的情况下读取。

要利用套接字激活,请按照以下步骤操作。

  1. systemd 服务 的形式运行您的应用程序。它可以在主机系统上直接运行,也可以在容器中运行(例如,使用 Docker 或 systemd 便携式服务)。如果您还将 IDLE_TIMEOUT 环境变量传递给您的应用程序,那么如果在 IDLE_TIMEOUT 秒内没有请求,它将优雅地关闭。当有新请求时,systemd 将自动重新启动您的应用程序。
/etc/systemd/system/myapp.service
[Service]
Environment=NODE_ENV=production IDLE_TIMEOUT=60
ExecStart=/usr/bin/node /usr/bin/myapp/build
  1. 创建随附的 套接字单元。该适配器只接受一个套接字。
/etc/systemd/system/myapp.socket
[Socket]
ListenStream=3000

[Install]
WantedBy=sockets.target
  1. 通过运行 sudo systemctl daemon-reload 确保 systemd 已识别这两个单元。然后使用 sudo systemctl enable --now myapp.socket 在启动时启用套接字并立即启动它。然后,一旦对 localhost:3000 发出第一个请求,该应用将自动启动。

自定义服务器

该适配器在您的构建目录中创建两个文件——index.jshandler.js。运行 index.js — 例如,如果您使用默认构建目录,则运行 node build — 将在配置的端口上启动服务器。

或者,您可以导入 handler.js 文件,该文件导出了适合与 ExpressConnectPolka(甚至只是内置的 http.createServer)配合使用的处理程序,并设置您自己的服务器

my-server.js
ts
import { handler } from './build/handler.js';
Cannot find module './build/handler.js' or its corresponding type declarations.2307Cannot find module './build/handler.js' or its corresponding type declarations.
import express from 'express';
Cannot find module 'express' or its corresponding type declarations.2307Cannot find module 'express' or its corresponding type declarations.
const app = express();
// add a route that lives separately from the SvelteKit app
app.get('/healthcheck', (req, res) => {
Parameter 'req' implicitly has an 'any' type.
Parameter 'res' implicitly has an 'any' type.
7006
7006
Parameter 'req' implicitly has an 'any' type.
Parameter 'res' implicitly has an 'any' type.
res.end('ok');
});
// let SvelteKit handle everything else, including serving prerendered pages and static assets
app.use(handler);
app.listen(3000, () => {
console.log('listening on port 3000');
});
my-server.ts
ts
import { handler } from './build/handler.js';
Cannot find module './build/handler.js' or its corresponding type declarations.2307Cannot find module './build/handler.js' or its corresponding type declarations.
import express from 'express';
Cannot find module 'express' or its corresponding type declarations.2307Cannot find module 'express' or its corresponding type declarations.
const app = express();
// add a route that lives separately from the SvelteKit app
app.get('/healthcheck', (req, res) => {
Parameter 'req' implicitly has an 'any' type.
Parameter 'res' implicitly has an 'any' type.
7006
7006
Parameter 'req' implicitly has an 'any' type.
Parameter 'res' implicitly has an 'any' type.
res.end('ok');
});
// let SvelteKit handle everything else, including serving prerendered pages and static assets
app.use(handler);
app.listen(3000, () => {
console.log('listening on port 3000');
});

故障排除

在应用退出之前是否有清理挂钩?

SvelteKit 中没有针对此的内置内容,因为此类清理挂钩在很大程度上取决于您所在的执行环境。对于 Node,您可以使用其内置的 process.on(...) 来实现一个在应用退出之前运行的回调

ts
function shutdownGracefully() {
// anything you need to clean up manually goes in here
db.shutdown();
Cannot find name 'db'.2304Cannot find name 'db'.
}
process.on('exit', shutdownGracefully);