跳转到主要内容

如何使用SvelteKit将利用服务器端渲染和Svelte的易用性的全栈应用程序连接在一起。

像Next.js和Gatsby这样的所谓元框架在过去几年里已经起飞了。本文将向您介绍最新的示例之一,SvelteKit的SvelteKit框架。与之前的Next.js一样,SvelteKit为构建反应式web应用程序提供了一个一体化的全栈平台。

SvelteKit是Sapper的继任者,Sapper是Svelte的上一代全栈预提交框架。

什么是SvelteKit?

SveltKit背后的理念是将前端和后端结合在一起,实现两全其美。除了实现简单的构建过程(因为整个堆栈是组合在一起的)外,SvelteKit还提供了以下开箱即用的好处:

【为什么Wasm是云计算的未来| WebAssembly的崛起】

  • 服务器端渲染
  • 代码拆分
  • 客户端路由
  • 简化的数据预取
  • 一个命令静态站点导出
  • 全栈热部署(开发模式)

这些好处的代价是更陡峭的学习曲线:您必须接受并吸收框架用于将应用程序的两个元素联系在一起的约定。然而,这些约定并不十分繁重,一旦掌握,开发就会以快速的步伐进行。


为了开始探索,我们将从默认的SvelteKit应用程序模板开始。(如果你想继续,这里提供了整个示例应用程序。)我们将使用Rollup模板(也提供Webpack)。在控制台中,键入

npm init svelte@next svelte-kit-intro

现在进入新创建的/svelte kit intro目录,运行npm install来安装Node.js模块。

现在,您可以使用npmrun-dev在开发模式下运行应用程序。如果您将浏览器打开到localhost:3000,您将看到应用程序正在运行,如图1所示。

 

图1. SveltKit入门应用程序

sveltekit welcome

SvelteKit中的路由是文件和文件夹

您的应用程序的每个页面都是一个Svelte组件。每个路由都映射到应用程序中的一个文件。

最重要的顶级目录是/src。您的大多数自定义代码都将存在于此。请注意/src/routes目录。这就是定义应用程序将支持的URL的地方。

文件夹对应于路径,文件对应于资源。应用程序的默认条目是/src/routes/index.svelte,它对应于根URL:localhost:3000/。每当文件夹路径有一个index.svelte文件时,该文件将作为空路径。

在您正在查看的入门应用程序的情况下,导航栏上的每个选项卡都对应于一条路线。单击“Todos”选项卡。查看来源:请注意,有一个/src/routes/Todos/index.svelte文件为该页面提供服务。

带下划线的非路由文件

您可以将JavaScript文件放在带有下划线的routes结构中的任何位置(例如,示例应用程序中的/src/routes/todos/_api.js文件)。这些文件可以用作共享的JS模块。

添加页面

这是客户端路由。SvelteKit将自动在服务器上为您预呈现这些页面,此时客户端的单页应用程序将接管。要了解它有多简单,让我们添加一个页面。创建一个/src/routes/infoworld.svelte页面,并将清单1中的内容放入其中。

清单1。新的InfoWorld页面

<main>
<img src="https://alt.idgesg.net/images/furniture/infoworld/infoworld-nameplate.svg" />
</main>
<style>
  main {
    background-color: #7f1231;
  }
  img {
    width: 500px;
  }
</style>

现在浏览到localhost:3000/infoworld,您将看到新页面。

SvelteKit中的布局

另一个重要的约定默认值是__layout.svelte文件(注意双下划线前缀)。此文件将自动定义应用于每个页面的布局。Svelte结合了槽的概念,__layout.Svelte利用这个想法来确定将内部内容放在哪里。清单2显示了布局当前的工作方式(为简洁起见,省略了样式)。

清单2__布局.svelte

<script>
        import Header from '$lib/header/Header.svelte';
        import '../app.css';
</script>
<Header />
<main>
        <slot />
</main>
<footer>
        <p>visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to learn SvelteKit</p>
</footer>
<style>
/* … */
</style>

除了插槽之外,布局还使用线段和页眉组件。segment是一个内置功能,它将用当前页面自动填充变量。这由Header组件用于确定要突出显示的菜单项。

现在,让我们为新的InfoWorld页面添加一个导航项目。打开src/lib/header/header.svelte文件。在无序列表(元素)中添加一个新的列表项,如清单3所示。请注意链接到InfoWorld页面的第四个新项目。

清单3。添加新菜单项

<ul>
  <li class:active={$page.path === '/'}><a sveltekit:prefetch href="/">Home</a></li>
  <li class:active={$page.path === '/about'}><a sveltekit:prefetch href="/about">About</a></li>
  <li class:active={$page.path === '/todos'}><a sveltekit:prefetch href="/todos">Todos</a></li>
  <li class:active={$page.path === '/infoworld'}><a sveltekit:prefetch href="/infoworld">Infoworld</a></li>
</ul>

现在,您将在浏览器中看到新的“信息世界”菜单项。请注意,我们使用从__layout传入的segment变量来突出显示基于页面名称的菜单项。

服务器端SvelteKit

现在让我们了解一下SvelteKit是如何将客户端与服务器集成在一起的。打开/src/routes/todos/index.svelte文件,并将其与您在localhost:3000/todos页面上看到的内容进行比较。请注意,该页面允许您创建新的todo,然后列出这些todo。SvelteKit是如何完成todo列表的?查看清单3中/src/routes/todos/index.svelte中的代码。

清单4。击中后端

<script context="module">
        import { enhance } from '$lib/form';
        // see https://kit.svelte.dev/docs#loading
        export const load = async ({ fetch }) => {
                const res = await fetch('/todos.json');
                if (res.ok) {
                        const todos = await res.json();
                        return {
                                props: { todos }
                        };
                }
                const { message } = await res.json();
                return {
                        error: new Error(message)
                };
        };
</script>

SvelteKit支持context=“module”属性。这会通知框架,应该在模块创建时而不是在组件实例化时评估里面的脚本。这意味着数据提取将立即发生。

现在考虑负载函数。它通过从一个相对的URL/todos.json获取数据来加载数据。SvelteKit在哪里可以找到这个资源?答案是SvelteKit使用了与客户端类似的映射约定。在这种情况下,URL将被转换为文件系统中的路径src/routes/todos/index.json.js。查看该文件,您将看到下面清单5中显示的代码。

处理请求

清单5从导入一个文件(_api.)开始;这只是在Node.JS中导入一个JS文件

清单5/src/routes/todos/index.json.js

import { api } from './_api';
// GET /todos.json
export const get = async (request) => {
        const response = await api(request, `todos/${request.locals.userid}`);
        if (response.status === 404) {              
          return { body: [] };
        }
        return response;
};
// POST /todos.json
export const post = async (request) => {
        const response = await api(request, `todos/${request.locals.userid}`, {              
          text: request.body.get('text')
        });
        return response;
};

清单5的其余部分涉及封送JSON,该JSON在后端rest请求和前端之间中介响应。我们导出一个get函数,该函数映射到我们从/src/todos/index.json.js中找到的get HTTP方法。并导出一个用于处理post todos的post函数。

请注意,这些端点函数类似于Express,但实际上并不是Express。请记住,SvelteKit的设计目的是最终在各种平台上运行,而不仅仅是Node.js,因此它是一个抽象的请求/响应API。

输出到特定的构建环境是通过适配器处理的。

URL路径参数

现在创建几个todo,然后编辑其中一个名称。更新todo名称是通过在src/routes/todos/index.svelte中提交到此URL来处理的:

“/todos/{todo.uid}.json?_method=patch”

请注意,{todo.uid}变量标记用于为URL路径提供ID。

这是由/src/routes/todos/[uid].json.js文件捕获的。

文件名中的方括号表示将填充URL参数的位置。这个标识符(“uid”)将提供给其中的代码。

打开[uid].js.js文件,查看在其中定义的PATCH方法,您将看到如何通过request.params.uid访问该路径参数,如清单6所示。

清单6。访问[uid].json.js中的路径参数

export const patch = async (request) => {

        return api(request, `todos/${request.locals.userid}/${request.params.uid}`, {

                text: request.body.get('text'),

                done: request.body.has('done') ? !!request.body.get('done') : undefined

        });

};

清单6还使用了前面看到的共享_api.js模块,该模块用于包装访问远程api的共享功能。

像Svelte一样简单

斯维尔特基特还有更多的秘密,但我们已经涵盖了基本内容。您已经了解了如何快速地将利用服务器端渲染的全栈应用程序连接在一起。你已经看到了Svelte如何让生活变得更轻松。

最后要注意的是,您可以使用服务器和客户端的npm运行构建创建生产构建,或者使用npm运行导出创建静态构建。