静态网站生成 (SSG) 概述

静态网站生成,通常称为“SSG”,是将网站网页预渲染为静态 HTML 文件的过程。好处是,当访问者请求网页时,响应是一个预生成的 HTML 文件(静态文件),不需要网页的 HTML 在访问者的浏览器中“重建”,也不需要由您的服务器动态创建(稍后将详细介绍)。

此外,由于 Qwik 的底层架构,页面性能也受益于不需要 Javascript “水合”步骤,这可以显着降低性能并减慢用户交互速度。通过使用 SSG 预渲染静态 index.html 文件,并结合 Qwik 的 可恢复性,静态网站生成提供了比传统解决方案更多的性能优势。

SSG 与服务器端渲染 (SSR)

Qwik City 能够将 Qwik 应用程序(无论是“webapp”还是“website”)生成静态 HTML。一旦它被生成为 HTML,Qwik 能够通过使用 可恢复性 根本上跳过重建应用程序,因为应用程序已经作为 HTML 生成。静态网站生成 (SSG) 和服务器端渲染 (SSR) 使用相同的过程来生成 HTML。然而,SSG 和 SSR 之间的主要区别在于“何时”生成 HTML。

在传统设置中,SSG 在构建时预渲染每个网页,而 SSR 在每个 HTTP 请求时按需渲染每个网页。SSG 只需要在每次构建时生成一次 HTML,这对于多个访问者应该看到相同内容的网页来说非常棒。相比之下,SSR 非常适合网页内容可能因访问者而异的情况,并且需要为每个单独的 HTTP 请求渲染自定义 HTML。

例如,SSG 非常适合博客或文档网站,其中所有内容对于多个访问者来说应该都是相同的。虽然 SSR 可能适用于博客,但对于您的 HTTP 服务器来说,为每个访问者渲染博客内容可能是一种不必要的负担,即使他们最终都会看到相同的 HTML。

但是,帐户仪表板通常会为每个登录用户显示不同的内容。在这种设置中,每个用户都应该获得包含其帐户信息的自定义渲染的 HTML,而不是每个人都看到完全相同的内容。这就是 SSR 更受欢迎的地方。

理想情况下,您越能使用静态网站生成越好,因为这将减少服务器的成本并加快响应时间。

但是,使用 Qwik City,决定使用 SSG 还是 SSR 不必是二选一。相反,您自己的实现可以选择让某些路由路径使用 SSG,而其他页面使用 SSR。这完全取决于您和您的需求。

静态网站生成配置

静态网站生成是通过内置的适配器创建的,要创建适配器,请运行

npm run qwik add static

选择 适配器:静态网站(.html 文件)。完成!

更改

运行上述命令将对您的项目进行以下更改

  • 一个 build.server 脚本将自动添加到您的 package.json 文件中。
  • 将创建一个 adapters/static/vite.config.ts 文件。

您的构建文件将生成到 dist 文件夹中。

您可以使用以下命令构建您的静态网站

npm run build.server

SSG 配置

adapters/static/vite.config.ts 文件还包含 SSG 配置,这将针对每个实现进行自定义。

origin

URL origin,它是方案(协议)和主机名(域名)的组合。例如,https://qwik.node.org.cn 的协议为 https://,域名是 qwik.dev。但是,origin 包含 pathname

origin 用于在静态网站生成 (SSG) 期间提供完整的 URL,以及模拟完整的 URL 而不是仅 pathname。例如,为了渲染正确的规范标签 URL 或 sitemap.xml 中的 URL,必须提供 origin

如果网站还以 / 以外的路径名开头,请在 Vite 配置选项中使用 base 选项(Qwik City 配置选项中的 basePathname 选项已弃用)。

outDir

outDir 是一个文件系统输出目录,静态文件应该写入该目录。在上面的示例中,它使用 Node 的 fileURLToPath 来创建一个绝对文件系统路径,将静态 HTML 文件写入该路径。

Javascript 运行时

对于一个 JavaScript 项目,通常构建的运行时会基于 Node.js。然而,Qwik City 静态网站生成的内核并不局限于使用 Node.js,这就是为什么 qwikCityGenerate() 函数是从 @builder.io/qwik-city/static/node 导入的原因。通过将生成函数限定在特定运行时,例如 Node.js,这使得 Qwik City 能够在未来从其他运行时(例如 DenoBun)生成 SSG。

动态 SSG 路由

到目前为止,我们只讨论了如何为单个路由路径生成静态 HTML 文件。然而,在大多数情况下,您需要为具有动态参数的多个路由路径生成 HTML 文件。例如,一个产品网站可能为每个产品提供一个路由路径,例如 /product/:id。在这种情况下,您需要为每个产品页面生成 HTML 文件,这将需要为每个产品 ID 生成 HTML 文件。

import { component$ } from '@builder.io/qwik';
import { useLocation, type StaticGenerateHandler } from '@builder.io/qwik-city';
import { loadProductIds } from './load-product-ids';
 
export default component$(() => {
  const { params } = useLocation();
 
  return <p>Example: {params.id}</p>;
});
 
export const onStaticGenerate: StaticGenerateHandler = async ({ env }) => {
  // example of loading params for this use case
  // every implementation will be different
  const ids = await loadProductIds({
    apiKey: env.get('API_KEY'),
  });
 
  return {
    params: ids.map((id) => {
      return { id };
    }),
  };
};

在上面的示例中,onStaticGenerate() 函数通过请求一个 API(该 API 位于从环境变量中检索到的 API 密钥后面)来从 loadProductIds() 函数加载产品 ID。此函数将根据每个实现进行自定义,但总体思路是您需要加载每个产品 ID 的数据,然后为每个产品 ID 生成 HTML 文件。

onStaticGenerate 函数应该从模块的顶层导出,并应该返回一个包含 params 属性的对象。params 属性应该是一个对象数组,其中每个对象都是路由路径的一组参数。例如,如果路由路径是 /product/:id,那么 params 数组应该是一个包含 id 属性的对象数组。

此示例的目录结构如下:

src/
└── routes/
    └── product/
        └── [id]/
            └── index.tsx

请注意,index.tsx 文件位于名为 [id] 的目录中。这是一个特殊的目录名称,它告诉 Qwik City 为每个 id 参数生成 HTML 文件。index.tsx 文件是 Qwik City 在为路由路径生成 HTML 文件时使用的默认文件。

贡献者

感谢所有帮助改进本文档的贡献者!

  • adamdbradley
  • AnthonyPAlicea
  • mhevery
  • ibousfiha
  • Kocal
  • eric-burel
  • julianobrasil
  • mrhoodz
  • hamatoyogi