跳到主要内容
Deno 2.4 发布,带来 deno bundle、bytes/text 导入、稳定的 OTel 等功能
了解更多
Building a static site with Lume.

如何使用 Lume 构建静态站点

  • Óscar Otero

这是一篇由 Lume 创建者 Óscar Otero 撰写的客座博客。

Deno 是创建动态 Web 应用程序和 API 的绝佳选择,尤其是在与 Deno Deploy 结合使用以在边缘生成响应时。

但对于不需要服务器动态响应的用例,例如博客、文档和着陆页,静态站点(预构建的站点,包含要交付给浏览器的准确 HTML、CSS 和 JavaScript 文件)是一个更好、性能更高的替代方案。

在本教程中,我们将学习如何使用 Lume(发音为 /lume/)创建静态站点,Lume 是一个用 Deno 编写的快速、极其灵活、可组合且可扩展的静态站点生成器。

查看源代码在线演示.

设置

设置 Lume 项目的推荐方法是运行以下命令

deno run -Ar --unstable https://deno.land/x/lume/init.ts

回答几个问题后,您将在工作目录中看到 3 个新文件

  • _config.ts: Lume 的配置文件,用于自定义 Lume。
  • deno.json: Deno 配置文件,包含一些运行 Lume 的有用任务。
  • import_map.json: Deno 用于解析裸说明符的导入映射文件。

此外,如果您使用的是 VSCode,强烈建议使用 Deno 扩展。(了解如何配置 VSCode 与 Deno。

构建博客:简单方法

博客是静态站点生成器最常见的应用示例,Lume 当然可以为您构建一个。如果您不寻求过于复杂的功能,“Simple blog” 主题可能就足够了。您只需将其导入到 _config.ts 文件中并使用它。

import lume from "lume";
import blog from "https://deno.land/x/lume_theme_simple_blog@v0.2.1/mod.ts";

const site = lume().use(blog());

export default site;

然后将您的文章以 markdown + front matter 格式保存在 /posts/ 文件夹中。例如:

---
title: Static sites with Lume + Deno Deploy
date: 2022-11-05
author: Óscar Otero
tags:
  - Deno
  - Static site generators
---

Deno is always a great choice to create dynamic web applications and APIs,
especially when it's combined with Deno Deploy to generate responses at the
edge. ...

运行 deno task serve,您将在 localhost:3000 上看到您的新博客!

但我想要自己动手制作

好的,明白了!我们不使用现有主题,而是从头开始构建一些东西。

入门

Lume 不需要任何文件结构即可工作,但为了本演示,我们将所有文章文件保存在一个名为 /posts 的目录中。因此我们有以下结构:

|_ posts/
|  |_ my-first-post.md
|  |_ my-second-post.md
|_ config.ts
|_ deno.json
|_ import_map.json

运行 deno task servelocalhost:3000 查看站点。您将看到一个 404 错误页面,因为索引文件尚不存在。

Getting a 404 page not found

但您可以看到文章。默认情况下,文章的 URL 是根据源路径计算的。例如,文件 /posts/my-first-post.md 输出的 URL 是 https://:3000/posts/my-first-post/

My first post

布局

如您所见,页面仅显示渲染为 HTML 的 markdown 内容。让我们创建一个布局,将此内容封装到适当的 HTML 结构中。默认情况下,布局存储在特殊文件夹 _includes 中,因此我们需要创建此文件夹并在其中创建 post.njk 文件,其内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>
</head>
<body>
  <main>
    <article>
      <header>
        <h1>{{ title }}</h1>
        <p>By {{ author }}</p>
      </header>

      {{ content | safe }}
    </article>
  </main>
</body>
</html>

.njk 扩展名表示 Nunjucks,这是 Mozilla 创建的一种流行模板语言,Lume 默认支持。当然,您可以使用其他格式,如 JavaScript、TypeScript 甚至 JSX、Pug、Eta 等(使用插件),但现在让我们保持简单。

我们将在 posts 文件夹中创建一个 _data.yml 文件,内容如下:

layout: post.njk
type: post

此文件将这两个变量分配给此目录中的所有文章。

我们暂时忽略 type 变量。

layout 变量是一个特殊值,包含用于渲染页面的布局文件名。这意味着此目录中的所有页面都将使用 _includes/post.njk 文件作为布局。请注意,布局可以访问文章 front matter 的值,例如 titleauthor

我们的文章现在看起来好多了!

First post but with some style

列出所有文章

假设我们想在主页上显示所有文章的列表。为了这个例子,我将在 TypeScript 中创建主页,所以我们需要在根目录中创建 index.tmpl.ts 文件,代码如下:

import type { PageData } from "lume/core.ts";

export default function ({ search }: PageData) {
  const posts = search.pages("type=post");

  return `
    <h2>Posts</h2>
    <ul>
      ${
    posts.map((post) =>
      `<li><a href="${post.data.url}">${post.data.title}</a></li>`
    ).join("")
  }
    </ul>
  `;
}

使用 TypeScript 在 Lume 中构建页面很简单,我们只需要 export default 一个返回页面内容为 string 的函数。

此函数将页面上下文数据作为第一个参数,包括一些有趣的辅助函数,如 search,我们可以用它来查询并返回所有带有 type=post 变量的页面。(还记得我们之前在 posts/_data.yml 文件中插入的 type 值吗?它只是一个标志,方便在此处选择这些页面。)

我们的主页看起来像这样:

The index page

我可以在页面中包含完整的 HTML 代码,但我喜欢布局,所以我创建了以下 _includes/homepage.njk 布局文件:

---
title: The Óscar's blog
---

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>
</head>
<body>
  <main>
    <header>
      <h1>{{ title }}</h1>
    </header>

    {{ content | safe }}
  </main>
</body>
</html>

现在我们必须配置 index.tmpl.ts 文件来使用这个布局。TypeScript 文件没有 front matter 来存储数据,它们只是将值作为命名导出暴露出来:

import type { PageData } from "lume/core.ts";

export const layout = "homepage.njk";

export default function ({ search }: PageData) {
  const posts = search.pages("type=post");

  return `
    <h2>Posts</h2>
    <ul>
      ${
    posts.map((post) =>
      `<li><a href="${post.data.url}">${post.data.title}</a></li>`
    ).join("")
  }
    </ul>
  `;
}

主页现在看起来好多了

Styling the home page

添加样式

Lume 有大量插件可用于处理 JavaScript,支持 JSX、MDX 等格式。对于样式目的,有一些可用的插件可用于 SASS、PostCSS、WindiCSS 或 LightningCSS。

为了简化,本演示中我们将使用出色的 missing.css(顺便说一句,它的文档站点也是用 Lume 构建的)。这个 CSS 文件开箱即用地提供了一些不错的样式,无需修改我们的 HTML。为此,只需在我们刚创建的两个布局中包含 <link rel="stylesheet" href="https://the.missing.style/"> 这一行。

The home page but much better styled

准备部署

静态站点的众多优点之一是托管。您可以在任何地方托管您的站点,几乎没有服务器要求。

在本演示中,我们将使用 Deno Deploy 来提供站点服务。由于其设计,所有传入请求都由一个 JavaScript 文件处理,我们可以自定义您的站点文件将如何交付。

步骤 1:在 Deno Deploy 中创建项目

访问 Deno Deploy 并创建一个新项目。您将看到类似以下的屏幕:

Create a new project in Deno Deploy

选择分支时,重要的一点是使用 GitHub Action 模式。这是因为 Deno Deploy 没有用于构建站点的 CI,所以我们需要使用 GitHub Actions 工作流来构建并将静态站点上传到 Deno Deploy。

然后点击链接按钮,您将看到以下屏幕:

Get the GitHub Action for Deno Deploy

Deno Deploy 已生成配置 GitHub Actions 工作流所需的代码。复制此代码并将其保存到 .github/workflows/deploy.yml 中。

步骤 2:配置 GitHub Actions

我们刚刚创建的 GitHub Action 工作流文件需要进行一些修改,这些修改已标记为 #TODO 注释:

  • 设置构建步骤。在本例中,我们需要设置 Deno 并运行 deno task build
  • 更新入口点以使用 deno_stdfile_server.ts,其中 root 设置为 ./_site

请注意,如果您想使用 Lume 的中间件,例如用于缓存的 expires 或用于显示自定义 404 页面的 not_found,您需要创建一个新的 serve.ts 文件,添加您的中间件,并将其设置为 Deno Deploy 的 entrypoint

修改后,这是最终版本:

name: Deploy
on: [push]

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    permissions:
      id-token: write # Needed for auth with Deno Deploy
      contents: read # Needed to clone the repository

    steps:
      - name: Clone repository
        uses: actions/checkout@v3

      - name: Setup Deno environment
        uses: denoland/setup-deno@v1
        with:
          deno-version: v1.x

      - name: Build site
        run: deno task build

      - name: Upload to Deno Deploy
        uses: denoland/deployctl@v1
        with:
          project: oscarotero-lume-blog-demo
          entrypoint: https://deno.land/std@0.167.0/http/file_server.ts
          root: ./_site

将更改推送到 GitHub,您的站点将在几秒钟内构建并上传到 Deno Deploy。

Successful deployment on Deno Deploy

点击蓝色的查看按钮,您将在 *.deno.dev(如果您添加了自定义域名,则为不同域名)上看到您的新博客。

Oscars blog served from Deno Deploy

就是这样。这很容易,不是吗?请查看 Lume 文档站点,了解更多关于这个静态站点生成器的信息,并在 展示部分 查看真实示例。

卡住了?欢迎到 Deno 的 Discord 打个招呼!