在本指南中,我们将浏览adapter-static
的特性和怪癖,这在所有SvelteKit adapters中都是唯一的,因为它将其编译到HTML,CSS和JavaScript的文件夹中,而不是无服务器函数或Node.js Server。
许多人想知道这如何与Sveltekit的服务器侧向性质一起使用 - 让我们以实践示例深入研究。如果您想查看整个项目
本文分为多个主题,随时查看您可能对!
的目录从适配器静态
开始要开始使用静态适配器,我们首先将其安装到一个全新的Sveltekit项目中,作为DEV依赖性:
npm i -D @sveltejs/adapter-static
然后,我们通过替换适配器配置来更改svelte.config.js
文件以使用它:
- import adapter from '@sveltejs/adapter-auto';
+ import adapter from '@sveltejs/adapter-static';
现在,我们可以运行npm run build
来构建项目。输出将是一个名为build/
的文件夹,其中构成了我们的项目。
修复“所有路由必须完全可限制”错误
这是每个人使用的适配器静态遇到的错误。 解决错误的关键是了解动态路由的工作原理。
Sveltekit基本上有两种使用适配器静态时路由的模式。您可以路由到已知的,预先的路线或未知的动态路线。不同之处在于,已知的,预先的路由生成了代表该路由的HTML内容的关联的.html
文件。例如,如果我们有一个预先介绍的路线:
src/routes/prerendered/+page.svelte
src/routes/prerendered/+page.js # contains "export const prerender = true;"
使用prerendered.html
文件构建时,这将生成以下HTML结构。让我们看看构建后目录的样子:
tree build/ -L 1
build/
...
├── index.html
├── prerendered.html
相比
src/routes/dynamic/+page.svelte
src/routes/dynamic/+page.js # contains "export const prerender = false;"
...然后尝试构建应用程序,我们可以看到没有创建dynamic.html
文件:
tree build/ -L 1
build/
...
├── index.html
# No dynamic.html file!
Sveltekit的默认值是假设所有路线都是动态的,因此您要么需要在root +layout.js
中设置export const prerender = true
以摆脱消息(明确将所有路由设置为PRERENDERABLE),要么启用 fall> fallback < /strong>选项。
在我们谈论后备选项之前,您可能会想知道,如果输出不存在,动态路线如何工作?答案是他们使用客户端渲染和一些服务器端路由魔术。如果我们查看fallback option的官方文档,我们可以阅读“后备页面是由Sveltekit从您的页面模板(例如App.html)创建的HTML页面,该页面将加载您的应用程序并导航到正确的路由。”
为了了解预先读者与动态路线的行为,让我们看一下图:
正如我们看到的,动态路线通过与基础Web服务器合作来工作。 Web服务器看到一个404错误(Beause在文件系统上不存在动态路由),而是加载了Sveltekit使用 sholdback 选项生成的后备页面。然后,此特殊页面将客户端渲染浏览器中的正确路径。这意味着一旦我们配置了后备选项,我们就不再需要将所有路线设置为PREREDER。
对于最终用户,至关重要的要点是,可以使用静态适配器呈现 PRERENDER的路线,从而获得性能和SEO效益。动态路线可以使用,甚至可以为每个用户加载个性化和动态数据,但不能使用SSR 。
设置后备配置
可以在svelte.config.js
文件中完成Sveltekit中的后备设置:
- adapter: adapter(),
+ adapter: adapter({ fallback : '404.html' }),
现在,您需要告诉Web服务器遇到错误时加载404.html
。例如,在Apache中,您可以使用配置:
ErrorDocument 404 /404.html
在我们的同伴存储库中,我们使用http-server
NPM模块运行该项目,该项目默认为使用404.html
作为404页面后备。
trailingSlash: 'always'
选项将每个路由的构建输出的名称从/route-name.html
更改为/route-name/index.html
。对于某些服务器,这可以更好地工作,因为通常,如果您导航到/route-name/
,大多数Web服务器都会在/route-name
/文件夹中寻找index.html
文件。根据我的经验,您通常希望通过在src/routes/+layout.js
中设置以下内容来启用此问题:
export const trailingSlash = 'always';
使用Sveltekit作为传统水疗中心
将Sveltekit用作传统的单页应用程序(例如经典的“ Create React App”),我们需要Sveltekit到:
- 不要尝试prerender或ssr任何东西(即。
- 始终返回一个空的“ shell” html文件,该文件仅加载关联的JavaScript,然后处理所有繁重的举重。
为了实现这一目标,我们需要完全禁用SSR并完全预先启动。在src/routes/+layout.js
中,我们设置了:
export const prerender = false;
export const ssr = false;
现在,您的应用程序就像任何水疗中心一样。您甚至可以忽略一些Sveltekit约定(例如,您不必将仅限浏览器代码与if(browser)
包装,因为Sveltekit永远不会在服务器上运行您的组件)。但是,我不建议这样做,因为如果您想再次启用SSR,它可能会很快变得一团糟。
+server.js端点
在除静态一个适配器外,服务器端点将作为动态服务器端代码部署。在Vercel上,您将获得无服务器函数,在节点适配器上,您将在基于Polka的Express.js like服务器中获得一条路线。
但是,我们无法将动态服务器端端点编译到静态JavaScript文件中。 默认情况下,适配器静态将完全剥离 +server.js文件。
但是是一个用例,我们可能希望从+server.js
文件中生成静态输出,而Sveltekit通过export const prerender = true;
选项公开了这一点。通过在端点文件中设置此功能,Sveltekit将在端点的构建时间创建一个输出文件。让我们用一个示例说明。如果我们有一个称为src/routes/randomNumber.json/+server.js
的文件,看起来像这样:
import { json } from '@sveltejs/kit';
/** @type {import('./$types').RequestHandler} */
export function GET({ url }) {
const randomNumber = Math.random();
return json({
randomNumber
});
}
export const prerender = true;
构建应用程序并检查目录后,我们将看到创建一个randomNumber.json
文件:
# npm run build
# ...
# tree build/ -L 1
build/
├── _app
├── favicon.png
├── index.html
└── randomNumber.json
如果我们打开文件,我们将看到这正是我们的期望 - 在构建时间生成的随机数:
{
"randomNumber": 0.44040173838860297
}
虽然Prerender技术不允许我们个性化数据,但它对于在构建时间中从CMS或其他数据源进行预取数据仍然非常有用。每当基础数据更改时,我们都可以触发网站的重建以使用新数据进行更新。
在 +page.server.js
端点应该仅在服务器上运行,那么它如何与apapter static一起使用? 默认情况下,与+server.js
文件一样,服务器加载功能无法通过使用默认配置来工作。 +page.server.js
代码将被删除。这意味着,如果您使用这些功能,一旦构建应用程序,总是无法加载。不幸的是,Vite不了解这种限制(甚至我们正在使用的适配器),因此您无法使用npm run preview
测试这种行为。 ,您可以通过在独立的Web服务器上,构建站点然后运行npm run build && npx http-server ./build
来测试它。
但是,就像使用+server.js
Function一样,有一种方法可以将+page.server.js
加载函数与适配器静态使用,并且是相同的修复程序 - 您需要将它们设置为PRERENDERABLE。
PREREDERED负载功能将是什么样的?让我们进行实验。首先,让我们创建一个非常简单的组件,该组件显示来自src/routes/server-load/+page.svelte
下的服务器加载函数的随机数:
<script>
export let data;
</script>
<h1>
A (maybe?) random number: {data.number}
</h1>
和src/routes/server-load/+page.server.js
下的随附的负载功能。请注意,我们在此处使用prerender = true
,否则该功能将无法如前所述。
export const load = async () => {
return {
number: Math.random(),
};
};
export const prerender = true;
现在让我们构建网站并查看输出:
# npm run build
# tree build -L 2
build
├── ...
└── server-load
├── __data.json
└── index.html
除了生成的HTML文件外,我们还获得了一个__data.json
文件。这是我们内置的负载功能的实际内容!让我们看看它包含的内容:
{
"type": "data",
"nodes": [
null,
{
"type": "data",
"data": [
{
"number": 1
},
0.8636617558590938
],
"uses": {}
}
]
}
Sveltekit添加了一些样板,但我们可以毫无疑问地看到我们生成了一个数字。
此示例强调了使用适配器静态的服务器负载功能的局限性 - 构建后他们无法更新数据。以上功能将始终返回相同的数字:
这并不意味着服务器加载功能是没有用的 - 就像+server.js
端点一样,您可以使用它们来构建静态数据,例如您最新博客文章的列表,然后在内容更改后重建网站。
+page.js加载功能
+page.js
负载功能称为“通用”,因为它们在浏览器和服务器上都运行。在任何其他适配器中,这意味着通用负载函数将作为SSR的一部分在服务器上执行。如果执行任何获取调用,将在服务器和the results will be sent as serialized data to the client上执行这些调用。这样做是为了避免两次执行请求 - 一次在服务器上,一次在客户端上。
使用适配器静态构建时,+page.js
负载功能将无法正常工作,而是运行两次:
- 一次(在服务器上)构建网站时 - 如果启用了SSR,则将此功能的输出烘烤到生成的HTML中。
- 每次用户加载页面时(在客户端上)。
这意味着+page.js
负载功能是放置客户端逻辑的绝佳场所。例如,您可以使用它使用fetch
加载动态用户数据。请记住,它将在构建过程中运行一次。对于具有某种用户登录系统的大多数应用程序,这意味着它很可能会渲染“已登录状态”,因为在服务器构建过程中没有用户集cookie或localstorage值。
SSR如何与静态站点一起使用?
SSR的工作原理与+page.server.js
相似。在构建时间期间,Sveltekit将在+page.js
和+page.server.js
中调用负载功能,并根据此结果生成HTML输出。除非您重建项目,否则此HTML输出将永远不会改变。此功能非常强大,因为这意味着我们可以借助SSR获得SEO的好处(Google和其他搜索引擎更喜欢完全渲染的HTML站点),以及可以在全球范围内部署的完全静态站点的速度。 P>
有时我们不想要SSR。例如,如果您要构建一个客户端渲染的应用程序,该应用程序将处理复杂的逻辑客户端。在这种情况下,就像我们在“使用Sveltekit”作为传统水疗中心的章节中一样,将以下内容添加到您的src/routes/+layout.js
文件中最容易禁用SSR。
export const ssr = false;
这将做的是防止Sveltekit生成HTML输出。
假设我们在src/routes/ssr/+page.svelte
下有这样的基本路线
<h1>Hello world!</h1>
现在,让我们将输出与在src/routes/ssr/+page.js
中设置export const ssr = true;
开始进行比较。
# curl http://localhost:5173/ssr/
<!-- Some output omitted for brevity -->
<!DOCTYPE html>
<html lang="en">
<body data-sveltekit-preload-data="hover">
<div style="display: contents">
<h1 data-svelte-h="svelte-1vv3a6r">
Hello world!
</h1>
<script>
{
// SvelteKit hydration initialization
}
</script>
</div>
</body>
正如我们所看到的,<h1>Hello world!</h1>
是HTML输出的一部分。搜索引擎很高兴,因为他们可以轻松阅读内容,并且用户很高兴,因为浏览器会立即向其显示内容!
现在,让我们使用export const ssr = false;
禁用SSR并进行比较:
# curl http://localhost:5173/ssr/
<!-- Some output omitted for brevity -->
<!DOCTYPE html>
<html lang="en">
<body data-sveltekit-preload-data="hover">
<div style="display: contents">
<script>
{
// SvelteKit hydration initialization
}
</script>
</div>
</body>
</html>
看起来相似,但是现在完全缺少<h1>
标签!如果我们查看页面,它仍然会出现在浏览器中,但只有在Sveltekit为我们补充了页面。
预先登录(SSG)
让我们想象我们正在建立一个博客,该博客将部署在github页面等静态主机上。我们将使用{JSON}占位符API。首先,让我们编写+page.server.js
加载功能,该功能将加载我们的博客文章,in src/routes/+page.server.js
:
export async function load({ params }) {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await response.json();
const first10posts = posts.slice(0, 10);
return {
posts: first10posts,
};
}
export const prerender = true;
现在让我们在src/routes/+page.svelte
中添加前端:
<script>
export let data;
</script>
<h1>Blog posts</h1>
{#each data.posts as post}
<h2>{post.title}</h2>
<a href="/posts/{post.id}">Read more</a>
{/each}
这为我们提供了一个美丽的简约博客页面:
现在,让我们添加单个帖子的路线。在src/routes/posts/[id]/+page.server.js
中:
export async function load({ params }) {
const id = params.id;
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
const post = await response.json();
return {
post
};
}
export const prerender = true;
和src/routes/posts/[id]/+page.svelte
中的前端:
<script>
export let data;
</script>
<a href="/">Back</a>
<br/>
<h1>{data.post.title} </h1>
<p>{data.post.body}</p>
这是一个帖子页面的输出:
现在,当我们构建项目时, sveltekit将爬网我们的索引页面并找到所有单独的博客文章。因此,在我们的输出中,它实际上将在我们的10个博客文章中提供完整的SSR支持!让我们通过对构建输出进行刷子来证明这一点:
# npm run build
# tree build -L 3
build
├── # ...
├── posts
│ ├── 1
│ │ ├── __data.json
│ │ └── index.html
│ ├── 2 # All posts have an index.html!
│ ├── 3
│ ├── 4
│ ├── 5
│ ├── 6
│ ├── 7
│ ├── 8
│ └── 9
│ ├── 10
这是一个非常强大的功能,它使Sveltekit成为SSG网站的粉丝范围!
但是,有一个问题 - 如果没有与我们的动态内容的链接,该怎么办?为了解决此问题,Sveltekit为我们提供了两种不同的解决方案 - 选择最适合您的用例的解决方案:
- Export an koude57 function that can generate a list of all your content on a per-route basis.
- 在
svelte.config.js
中设置config.kit.prerender.entrie
s下的条目列表
dev模式上的注释
当我们使用npm run dev
时,Sveltekit并不是真正知道我们已经配置了适配器静态。因此,Sveltekit的行为就像我们有任何动态适配器一样。例如,加载函数中的数据将在每个页面加载上重新加载,而不仅仅是在启动时一次。这很方便,因为如果您每次要更新数据时都必须重新启动DEV服务器,这将变得非常烦人,但是它可以给出错误的印象,以了解该站点在构建后的运作方式。
结论
虽然适配器静态的作用与其他适配器的作用不同,但它允许我们使用Sveltekit的许多功能功能,例如服务器端渲染(SSG)以及渲染动态路线,从而使其与其他方法一样强大,例如使用自定义VITE设置。实际上,这甚至更容易,因为您可以访问Sveltekit中存在的出色客户端路由器和数据加载功能!如果您的问题是“我应该将Sveltekit用于静态和/或水疗站点?” - 答案是是一个响亮的是!
您喜欢博客文章吗?有什么不清楚的吗?在下面发表评论!
Kelly Sikkema在Unsplash < / p>上的横幅 /社交分享照片< / p>