使用sveltekit开发一个服务端渲染(SSR)项目

上篇简单介绍了sapper和sveltekit的发展,目前sveltekit还只是Beta版本,有很多不确定因素存在,有可能会有大的变更,所以还不推荐在生产环境中使用,不过在个人项目和小项目中可以大胆尝试。

今天我们就正式使用sveltekit开发一个web项目。

第一步:创建项目

mkdir my-app

cd my-app

npm init svelte@next

npm install

npm run dev

这样就可以创建一个简陋的项目了,不过和我们真实需求还有些差距,既然是使用sveltekit,那么最重要的原因是其支持服务端渲染了。这就需要从服务端获取数据,接下来就实现这样的需求。

第二步:路由 和sapper一样,sveltekit也是基于文件系统的的路由器,这就需要我们来合理的组织目录结构。路由的核心目录是src/routes,当然,这个也是可配置的,按照自己的需求修改svelte.config.cjs,参考文档:https://kit.svelte.dev/docs#configuration

我们以一个博客系统为例,在scr/routes下创建blog目录,光有目录还不行,如果想要访问/blog路由,还需要创建index.svelte文件,内容如下:

<script context="module">
    /**
	 * @type {import('@sveltejs/kit').Load}
	 */
	export async function load({ page, fetch, session, context }) {
		return fetch(`blog.json`)// index.json.js = blog.json或blog/blog.json
			.then((r) => r.json())
			.then((posts) => {
				console.log(posts);
				return {
					props: {
						posts
					}
				};
			});
	}
</script>

<script>
	export let posts;
</script>

<svelte:head>
	<title>Blog</title>
</svelte:head>

<h1>Recent posts</h1>

<ul>
	{#each posts as post}
		<!-- we're using the non-standard `rel=prefetch` attribute to
				tell Sapper to load the data for the page as soon as
				the user hovers over the link or taps it, instead of
				waiting for the 'click' event -->
		<li><a rel="prefetch" href="blog/{post.slug}">{post.title}</a></li>
	{/each}
</ul>

<style lang="less">
	ul {
		margin: 0 0 1em 0;
		line-height: 1.5;
	}
</style>

index.svelte中load函数是一个关键函数,它接收四个参数: - page - fetch - session - contenxt

page

page是一个对象,包含{ host, path, params, query },用户获取请求参数。

fetch

fetch是用于服务端,客户端发送请求。

session

session是用户会话,用于从服务端传递与当前请求相关的数据。

context

上下文从布局组件传递到子布局和页面组件。为了根$layout.svelte组件,它等于{},但如果该组件的加载函数返回一个具有上下文属性的对象,则该对象将可供后续加载函数使用。

有输入,也有输出,load函数输出以下数据:

status

http状态码,如果返回错误,则必须是4xx或5xx。重定向是3xx,默认是200。

error

如果在加载过程中出错,则返回一个错误对象或描述错误的字符串以及4xx或5xx状态代码。

redirect

如果该页应该重定向(因为该页已被弃用,或者用户需要登录,或者其他原因),则返回一个字符串,其中包含应重定向到的位置以及3xx状态码。

maxage

要使页面被缓存,请返回一个数字,该数字描述页面的最大使用时间(以秒为单位)。如果在呈现页面时涉及到用户数据(通过会话,或者因为在加载函数中进行了认证获取),则生成的缓存头将包括private,否则将包括public,以便cdn可以缓存它。

这只适用于页面组件,而不适用于布局组件。

props

如果load函数返回一个props对象,则在呈现时props将传递给组件。

context

这将与任何现有上下文合并,并传递给后续布局和页面组件的加载函数。 这只适用于布局组件,而不适用于页面组件。

index.svelte中请求了一个url:blog.json,所以需要创建index.json.js,此处可能稍微难以理解,主要你理解了blog目录和index.svelte文件的关系也就解释的通了。

// index.json.js
import db from '$lib/database';

export function get() {
	return {
		body: db.list()
	};
}
//src/lib/database.js
import posts from './posts';

const lookup = new Map();
posts.forEach(post => {
    lookup.set(post.slug, JSON.stringify(post));
});

export default {

    get(slug) {
        return lookup.get(slug);
    },

    has(slug) {
        return lookup.has(slug);
    },

    list() {
        const contents = JSON.stringify(posts.map(post => {
            return {
                title: post.title,
                slug: post.slug
            };
        }));
        return contents;
    },
}

// src/lib/posts.js
const posts = [
	{
		title: 'What is Sapper?',
		slug: 'what-is-sapper',
		html: `
			<p>First, you have to know what <a href='https://svelte.dev'>Svelte</a> is. Svelte is a UI framework with a bold new idea: rather than providing a library that you write code with (like React or Vue, for example), it's a compiler that turns your components into highly optimized vanilla JavaScript. If you haven't already read the <a href='https://svelte.dev/blog/frameworks-without-the-framework'>introductory blog post</a>, you should!</p>
<p>Sapper is a Next.js-style framework (<a href='blog/how-is-sapper-different-from-next'>more on that here</a>) built around Svelte. It makes it embarrassingly easy to create extremely high performance web apps. Out of the box, you get:</p>
<ul>
<li>Code-splitting, dynamic imports and hot module replacement, powered by webpack</li>
<li>Server-side rendering (SSR) with client-side hydration</li>
<li>Service worker for offline support, and all the PWA bells and whistles</li>
<li>The nicest development experience you've ever had, or your money back</li>
</ul>
<p>It's implemented as Express middleware. Everything is set up and waiting for you to get started, but you keep complete control over the server, service worker, webpack config and everything else, so it's as flexible as you need it to be.</p>
`
	}
];

posts.forEach(post => {
	post.html = post.html.replace(/^\t{3}/gm, '');
});

export default posts;

最终src目录是这样:

src
├─lib
│      database.js
│      posts.js
│
└─routes
    │  $error.svelte
    │  $layout.svelte
    │  about.svelte
    │  index.svelte
    │
    └─blog
            index.json.js
            index.svelte
            [slug].json.js
            [slug].svelte

以上就完成了一个可以从数据库中获取数据并通过服务端渲染的web项目。

完整项目:https://gitee.com/hpgt/sveltekit-app

原文:https://www.yuedun.wang/blogdetail/606d512c54277a10496a38ae