SvelteKit 1.0 - 建立个人博客,显示您的 DEV 帖子

这篇文章的目的是提供最新版本的 SvelteKit 的简要介绍。我们将构建一个开发人员组合和博客网站,从您的 RSS 提要和 GitHub API 中获取数据。

内容


SvelteKit 简介

Svelte 很快就成为最受欢迎的 Web 框架[SO Survey]的头把交椅,随着最近发布的 SvelteKit 1.0,随着越来越多的项目采用它,您应该会看到对 Svelte + SvelteKit 开发人员的需求增加。

SvelteKit 之于 Svelte,有点像 Next.js 之于 React——它处理路由、布局、服务器端渲染、部署,并使开发高质量的网络应用程序更快、更容易、更有趣。

但为什么是 SvekteKit?... 你会看到的!启动和运行功能齐全的动态 Web 应用程序非常容易,所有质量指标通常需要几天甚至几周才能在传统框架中实现。想想出色的性能、简单的部署、简单的代码结构和甜蜜的开发体验。


我们要建造什么

我们大多数人都有博客,不管它是在 Dev.to 上还是在其他平台上。今天我们将为您构建和部署一个个人博客,它将您在其他平台上的所有帖子聚合到一个站点中。

由于我不知道您使用的是什么博客平台,因此我不想依赖个别 API。但值得庆幸的是,有一个简单的解决方案——RSS!几乎所有现代(和旧)提供商都支持 RSS,它可以让我们轻松地从一个 URL 获取您的所有帖子。(例如,在 DEV 上https://dev.to/feed/[your-username]:)。

这是一个现场演示:devolio.netlify.app/blog

这是完整的来源:@Lissy93/Devolio

Lissy93 / 恶魔

✨ 我们其他人的开发者组合网站!将您的所有项目、博客文章和统计信息汇总在一个地方

✨魔鬼


面向开发人员演示的聚合产品组合和博客站点

About

Intro

Devolio is a self-hosted developer homepage, where you can showcase your projects, blog posts, coding stats and more.

Data fetched from existing sources (GitHub, RSS, Dev.to etc), so there's no backend to manage.

It's easy to make it your own, with custom styles and a simple config file.

Pages

The app is split into several pages: Portfolio | Blog | Contact | About

Portfolio

投资组合页面显示您构建的项目。数据是从您的 GitHub 配置文件中获取的。

每个项目都可以包括:名称、描述、缩略图、语言、星号/分叉/问题数……

在 GitHub 上查看

要自己部署它 - 只需分叉它,使用您的 RSS 提要 URL 更新配置,并使用一键式部署选项之一。


让我们开始吧!

步骤 #0 - 先决条件

您需要安装Node.js(LTS 或最新版本)。还建议使用Git、代码编辑器(如VS Code)和访问终端。或者,您可以使用云服务,例如Codespaces


步骤 #1 - 项目设置

我们可以通过运行以下命令轻松创建我们的项目:

npm create svelte@latest dev-blog

出现提示时,选择 SvelteKit,然后决定你喜欢 TypeScript、ESLint、Prettier、Playwright、Vitest。

接下来,我们需要导航到我们的项目(使用cd dev-blog),并安装依赖项(使用npm install)。

要启动应用程序,并启用实时重新加载,请运行:

npm run dev

然后打开localhost:5173


步骤 #2 - 完成设置

为了避免 import 语句中典型的丑陋../../../,我们将在我们的svelte.config.js文件中添加一个别名。

alias这可以通过在 下添加对象来完成config.sveltekit。这是一个示例,我将在其中映射./src/$src.

importadapterfrom'@sveltejs/adapter-auto';import{vitePreprocess}from'@sveltejs/kit/vite';/** @type {import('@sveltejs/kit').Config} */constconfig={preprocess:vitePreprocess(),kit:{adapter:adapter(),alias:{'$src/*':'src/*',},},};exportdefaultconfig;

稍后我们可以回到 svelte.config 文件,因为它是我们放置适配器以部署到各种平台(如 Netlify)的地方。

如果您想使用自己的 Prettier、ESLint 或 TypeScript 配置,您可以分别更新.prettierrc,.eslintrc.cjspretttsconfig.json。运行npm run format以应用 Prettier 规则并npm run check进行验证。


步骤 #3 - 组件

在我们继续之前,我们需要了解组件的基础知识。

Svelte(和 SvelteKit)如此易于使用的原因之一是因为几乎所有东西都只是一个组件。组件的结构非常非常简单。这是一个例子:

<script>// All JavaScript logic and imports go here// Append lang="ts" to use TypeScript</script><!-- All markup goes here --><p>Example Component</p><style>//Allstylesgohere,andarescopedtothecurrentcomponent//Appendlang="scss"touseSCSS(oranotherpre-processor)p{color:hotpink;}</style>

这是一个真实世界的例子,我们正在制作一个可重复使用的标题组件,具有可选级别(h1、h2 等)、颜色、大小和字体。

<script lang="ts">// Parametersexportletlevel:'h1'|'h2'|'h3'|'h4'|'h5'|'h6'='h1';// The semantic heading levelexportletcolor:string|undefined=undefined;// An optional override color (defaults to accent)exportletsize:string|undefined=undefined;// An optional override size (default depends on level)exportletfont:string|undefined=undefined;// An optional override font (defaults to FiraCode)// Computed values, for reactivity$:computedColor=color?`--headingColor: ${color};`:'';$:computedSize=size?`--headingSize: ${size};`:'';$:computedFont=font?`--headingFont: ${font};`:'';$:computedStyles=`${computedColor} ${computedSize} ${computedFont}`;</script><svelte:elementthis={level}style={computedStyles}><slot></slot></svelte:element><style lang="scss">h1,h2,h3,h4,h5,h6{font-weight:700;transition:all.25sease-in-out;font-family:var(--headingFont);color:var(--headingColor);}h1,h2,h3{margin:1rem0;}h4,h5,h6{margin:0.5rem0;}h1{font-size:var(--headingSize,2.8rem);}h2{font-size:var(--headingSize,2rem);}h3{font-size:var(--headingSize,1.75rem);}h4{font-size:var(--headingSize,1.5rem);}h5{font-size:var(--headingSize,1.25rem);}h6{font-size:var(--headingSize,1rem);}</style>

需要注意的几件事:

  • 我们正在定义道具export let propName

  • 我们可以通过给它们一个默认值来使道具可选

  • 我们可以在我们的组件中访问这些变量中的任何一个,只需将它们括在大括号中{}

  • 如果我们需要属性是反应性的,我们使用$: variabeName语法

  • 我们可以指定使用什么类型的语义元素,用<svelte:element this="div">

  • 将样式从 JS 传递到 CSS 的一种方法是定义 CSS 变量,并将它们传递到 style prop

  • (这并不像听起来那么糟糕,因为所有样式的范围都仅限于当前组件!)


步骤 #4 - 创建路线

接下来,我们将创建一个博客页面,其中将显示我们所有的帖子。(这可以在主页上完成,在 中src/routes/+page.svelte,但这是解释路由的好机会)

SvelteKit 会根据routes目录内的目录结构自动创建路由。您只需要一个以路由名称命名的目录,其中包含一个 Svelte 文件名+page.svelte。因此,让我们创建该路由,其中:touch src/routes/blog/+page.svelte- 这个文件的内容将只是一个普通的 Svelte 组件,就像我们上面看到的那样。

<script lang="ts">lettitle='Blog Page';</script><svelte:head><title>{title}</title></svelte:head><h2>{title}</h2><style lang="scss">h2{color:hotpink;}</style>

我们还需要一个可以呈现单个帖子的路由,但我们希望该 URL 路径是动态的,可能基于帖子标题。为此,我们可以创建一个名为[slug]用户访问时将登陆的目录example.com/blog/example-post


步骤 #5 - 特殊路线

现在是时候提一下我们可以让我们的路由继承某些将出现在所有页面上的组件,比如导航栏和页脚。为此,我们可以创建一个布局文件,需要将其命名为+layout.svelte,因为我们希望在所有页面上都使用它,所以我们将把它放入src/routes.

用类似的东西填充它:

<script lang="ts">importNavBarfrom'$src/components/NavBar.svelte';importFooterfrom'$src/components/Footer.svelte';import{fade}from'svelte/transition';import{page}from'$app/stores';</script><svelte:head><title>{$page.url.pathname.replaceAll('-', ' ')}</title></svelte:head><NavBar/><mainin:fade><slot/></main><Footer/><style lang="scss">@import"$src/styles/color-palette.scss";@import"$src/styles/media-queries.scss";@import"$src/styles/typography.scss";@import"$src/styles/dimensions.scss";:global(html){scroll-behavior:smooth;}:global(::selection){background-color:var(--accent);color:var(--background);}</style>

这里有几点需要注意:

  • 主要站点内容将呈现在<slot />放置的位置

  • 我们正在添加一个页面过渡动画,通过导入svelte/transition和设置in:fade页面将改变的部分

  • page我们可以通过使用对象(从导入)获取有关当前页面(如路径)的信息$app/stores- 在它前面加上一个$以保持值更新

  • 如果我们需要在<head>我们可以使用的<svelte:head>范围内设置任何标签

  • 我们还可以弹出任何全局样式,如重置或导入 CSS 变量

  • 可以使用:global(body)(或您定位的任何选择器)应用全局样式 - 但请谨慎使用!

SvelteKit 中的另一个特殊路由是+error.svelte,如果在任何路由的函数中抛出错误,它将代替当前路由进行渲染load()

同样,让我们创建该文件src/routes/+error.svelte并用类似的内容填充它。(同样,我们可以获得有关当前路线的信息,包括来自$page对象的错误代码)

<script>import{page}from'$app/stores';constemojis={// TODO add the rest!404:'🧱',420:'🫠',500:'💥'};</script><h1>{$page.status} {$page.error.message}</h1><spanstyle="font-size: 10em">
    {emojis[$page.status] ?? emojis[500]}</span>

还值得注意的是,您可以创建特定于某些路由的布局和错误页面,方法是将它们嵌套在正确的路由目录中。如果您需要多个具有相同特征的布局页面,您可以将这些元素提取到它们自己的组件中,以提高它们的可重用性。

到目前为止,我们的路由目录结构应该如下所示:

src/routes
├── +error.svelte
├── +layout.svelte
├── +page.svelte
├── about
│  └── +page.svelte
└── blog
   ├── +page.svelte
   ├── +page.ts
   └── [slug]
      ├── +page.svelte
      └── +page.ts

步骤 #6 - 获取数据

现在是进入好东西的时候了!我们将从用户的 RSS 提要中获取博客文章列表。

现在是时候提一下,在每个路由的路径目录中,我们还可以有一个+page.js/+page.ts文件(与+page.svelte. 这是我们进行数据获取的地方。

为了简单起见,我们将使用fast-xml-parserXML 响应解析为 JSON。

以下脚本只是从给定的 XML RSS 提要中获取和解析提要。

import{XMLParser}from'fast-xml-parser';constparseXml=(rawRssData)=>{constparser=newXMLParser();returnparser.parse(rawRssData);};/** @type {import('./$types').PageLoad} */exportconstload=()=>{constRSS_URL=`https://notes.aliciasykes.com/feed`;constposts=fetch(RSS_URL).then((response)=>response.text()).then((rawXml)=>parseXml(rawXml).rss.channel.item);return{posts};};

步骤 #7 - 渲染结果

从返回的数据中渲染结果真的很容易。在blog/+page.svelte组件中(文件旁边+page.ts),只需包含export let data- 这将是我们的获取函数返回的结果。我们现在可以在标记中引用此数据。

<script lang="ts">/** @type {import('./$types').PageData} */exportletdata;</script>
Blog
{#each data.posts as post}<li><atarget="_blank"href={post.link}rel="noreferrer">
      {post.title}</a></li>
{/each}

您会注意到我们正在使用{#each data.posts as post}- 这只是一个 for 循环,因为返回的数据是一个数组。

这是 Svelte模板语法的一部分。还有其他属性,例如{#if expression}...{/if}条件或{#await expression}...{:then name}...{/await}承诺,以及许多其他有用的功能。


步骤 #8 - 服务器端

到目前为止,我们所做的一切都很好,但我们可能会遇到一些问题:

  • 加载时间——RSS 提要很大,每次加载时在客户端获取它们效率不高

  • SEO - 动态加载的内容不会被大多数搜索引擎机器人抓取

  • CORS - 一些 RSS 提要不允许来自跨源主机的客户端请求

值得庆幸的是,有一个简单的解决方法。重命名+page.ts+page.server.ts将导致它呈现在服务器端,而不是在用户浏览器上。这应该可以解决这些问题,并且不需要更改任何代码。

请注意,对于服务器端代码,我们不能使用任何浏览器 API。由于我们的许多代码都能够同时在服务器端和客户端运行,因此我们需要在尝试使用之前检查某些功能是否可用。我们可以这样做,通过browser从导入$app/environment,然后使用if (browser) { /* Can access browser API here */ }


第 9 步 - 构建帖子页面

最后,当用户点击帖子时,我们要渲染它。这非常直截了当,因为 RSS 响应已经是 HTML 格式,所以这只是使用指令@html然后对其进行样式设置的一个例子。

<mainclass="article-content">
  {@html content}</main>

第 10 步 - 部署!

现在,让我们开始部署设置。这是 SvelteKit 如此出色的另一个原因,因为部署到几乎任何提供商都非常简单!

  1. 为您想要的供应商安装适配器

  • 我为 Netlify:npm i --save-dev @sveltejs/adapter-netlify

  1. svelte.config.js在您的文件 中导入所述适配器

  • 例如import netlifyAdapter from '@sveltejs/adapter-netlify';

  1. 在配置对象中启动适配器,在kit

  • 成套工具:{ adapter: netlifyAdapter() }

  1. 部署!现在只需前往您的 Netlify 仪表板,然后导入项目

如果你想在 VPS 上运行你的项目,我们可以使用@sveltejs/adapter-node. 重复上面的过程,然后运行yarn build,通过运行启动节点服务器node build/index.js

我们可能希望使用多个适配器,以便我们的项目与多个不同的托管服务提供商兼容。这是我的配置文件的一个例子,它就是这样做的:

importautoAdapterfrom'@sveltejs/adapter-auto';importnetlifyAdapterfrom'@sveltejs/adapter-netlify';importvercelAdapterfrom'@sveltejs/adapter-vercel';importnodeAdapterfrom'@sveltejs/adapter-node';import{vitePreprocess}from'@sveltejs/kit/vite';constmultiAdapter=(adapters)=>{return{asyncadapt(argument){awaitPromise.all(adapters.map(item=>Promise.resolve(item).then(resolved=>resolved.adapt(argument))))}};};/** @type {import('@sveltejs/kit').Config} */constconfig={preprocess:vitePreprocess(),kit:{adapter:multiAdapter([autoAdapter(),netlifyAdapter(),vercelAdapter(),nodeAdapter()]),alias:{'$src/*':'src/*',},},};exportdefaultconfig;

(在使用之前不要忘记 npm i 任何适配器!)

最后说一下Docker。Dockerfile由于这是一种流行的部署方法,这里是我编写的多体系结构,具有构建阶段、部署阶段和一些健康检查。

它还发布到 DockerHub(位于lissy93/devolio下),因此您应该能够将它与docker run -p 3000:80 lissy93/devolio- 一起使用,或者将其用作docker-compose.yml您自己的容器的模板。


该项目

为了简洁起见,我不得不跳过一些细节,但所有代码都可以在 GitHub 上找到,因此应该可以清除任何尚无意义的内容 - 如果仍然没有,请随时在下面提问: )

我还添加了一些额外的功能:

  • 将所有数据提取到一个配置文件中,以便于使用,并使用自定义颜色和主题使其具有样式

  • 添加了加载和组合多个 RSS 提要以及排序和过滤结果的功能

  • 我构建了一个页面来展示您的项目,其中包含通过他们的 API 从您的 GitHub 获取的数据

  • 还有一个联系页面,包含电子邮件表格、社交媒体链接和 GPG 密钥

  • 添加了更多用于部署到各种云服务的适配器,并编写了一个 Dockerfile

这是一些屏幕截图(只有普通主题)

博客页面(从 RSS 中获取)

动图

项目页面(从 GitHub 获取)

动图

社交媒体链接(从 API 获取的统计数据)

动图

我确实计划扩展该项目,添加一些功能并将其变成一个易于配置、主题化的开发人员组合网站,任何人都可以轻松使用。如果您想查看更新,请在 GitHub 上为 repo 加星 :)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

产品大道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值