---
title: 静态站点生成（SSG）
---

# 静态站点生成（SSG）

SSG（Static Site Generation）是一种基于数据与模板，在构建时渲染完整静态网页的技术解决方案。这意味着在生产环境中，页面默认就是有内容的，并且可以被 CDN 缓存。对于无需数据的页面，SSG 可以提供更好的性能和更高的安全性。

## 启用 SSG

我们首先需要执行 `pnpm run new` 启用 SSG 功能：

```bash
? 请选择你想要的操作 启用可选功能
? 请选择功能名称 启用「SSG」功能
```

执行命令后，在 `modern.config.ts` 中注册 SSG 插件：

```ts title="modern.config.ts"
import { ssgPlugin } from '@modern-js/plugin-ssg';

export default defineConfig({
  output: {
    ssg: true,
  },
  plugins: [..., ssgPlugin()],
});
```

## 开发环境调试

SSG 也是在 Node.js 环境渲染页面，因此我们可以在**开发阶段开启 SSR**，提前暴露代码问题，验证 SSG 渲染效果：

```ts title="modern.config.ts"
export default defineConfig({
  server: {
    ssr: process.env.NODE_ENV === 'development',
  }
}
```

## 在约定式路由中使用

**约定式路由**中，Modern.js 根据入口下的文件结构生成路由，因此框架能够收集完整的路由信息。

### 基本用法

例如，以下是一个使用约定式路由的项目目录结构：

```bash
.
└── routes
    ├── layout.tsx
    ├── page.tsx
    └── user
        ├── layout.tsx
        ├── page.tsx
        └── profile
            └── page.tsx
```

上述文件目录将会生成以下三条路由：

- `/`
- `/user`
- `/user/profile`

:::tip
如果还不了解约定式路由的规则，可以先查看[路由方案](/guides/basic-features/routes)。

:::

在 `src/routes/page.tsx` 中添加组件代码：

```jsx title="src/routes/page.tsx"
export default () => {
  return <div>Index Page</div>;
};
```

在项目根路径下执行 `pnpm run dev` 命令，查看 `dist/` 目录，此时只生成一个 HTML 文件 `main/index.html`。

在项目根路径下执行 `pnpm run build` 命令，构建完成后，查看 `dist/` 目录，此时生成 `main/index.html`、`main/user/index.html` 和 `main/user/profile/index.html` 三个 HTML 文件，内容分别对应上述三条路由。

**约定式路由**中的每一条路由，都会生成一个单独的 HTML 文件。查看 `main/index.html`，可以发现包含 `Index Page` 的文本内容，这正是 SSG 的效果。

执行 `pnpm run serve` 启动项目后，访问页面，在浏览器我们工具的 Network 窗口，查看请求返回的文档，文档包含组件渲染后的完整页面内容。

### 阻止默认行为

默认情况下，**约定式路由**的路由会全部开启 SSG。Modern.js 提供了另一个字段，用来阻止默认的 SSG 行为。

例如以下目录结构，`/`、`/user`、`/user/profle` 三条路由都开启 SSG：

```bash
.
├── src
│   └── routes
│       ├── layout.tsx
│       ├── page.tsx
│       └── user
│           ├── layout.tsx
│           ├── page.tsx
│           └── profile
│               └── page.tsx
```

可以通过配置 `preventDefault` 来禁用某些路由的默认行为。进行下面配置后，最终只会生成 `/`、`/user/profle` 两条路由的 SSG 页面：

```js
export default defineConfig({
  output: {
    ssg: {
      preventDefault: ['/user'],
    },
  },
});
```

## 在自控式路由中使用

**自控式路由**是通过组件代码定义路由，需要应用运行起来才能获取准确的路由信息。因此，无法开箱即用的使用 SSG 功能。开发者需要通过配置告知 Modern.js 框架，哪些路由需要开启 SSG 功能。

例如有以下代码，包含多条路由，设置 `output.ssg` 为 `true` 时，默认只会渲染入口路由即 `/`：

import SelfRouteExample from '@site-docs/components/self-route-example';

<SelfRouteExample />

如果我们希望同时开启 `/about` 的 SSG 功能，可以配置 `output.ssg`：

```ts title="modern.config.ts"
export default defineConfig({
  output: {
    ssg: {
      routes: ['/', '/about'],
    },
  },
});
```

执行 `pnpm run build` 后，可以看到 `dist/` 目录中，新增了一个 `main/about/index.html` 文件。

执行 `pnpm run serve` 启动项目后，访问页面，在浏览器我们工具的 Network 窗口，查看请求返回的文档，文档包含组件渲染后的完整页面内容。

:::info
以上仅介绍了单入口的情况，更多相关内容可以查看 [API 文档](/configure/app/output/ssg)。
:::

## 添加路由参数

在 Modern.js 中，部分路由可能是动态的，例如自控式路由中的 `/user/:id` 或是约定式路由中 `user/[id]/page.tsx` 文件生成的路由。

可以在 `output.ssg` 中配置具体的参数，渲染指定参数的路由，例如：

```js
export default defineConfig({
  output: {
    ssg: {
      routes: [
        {
          url: '/user/:id',
          params: [{
            id: 'modernjs',
          }],
        },
      ],
    },
  },
});
```

此时，`/user/modernjs` 路由会被渲染，并且在渲染时，会将 `id` 参数传递给组件。当配置多个值时，对应会生成多张页面。

:::note
动态路由和 SSG 的组合，在根据 CMS 系统数据变更，实时生成静态页面时非常有用。
:::


## 配置渲染请求头

Modern.js 支持为具体入口或路由配置请求头，例如：

```js
export default defineConfig({
  output: {
    ssg: {
      headers: {
        "x-tt-env": "ppe_modernjs"
      },
      routes: [
        '/',
        {
          url: '/about',
          headers: {
            "from": "modern-website"
          },
        },
      ],
    },
  },
});
```

上述配置中，为所有路由设置了 `x-tt-env` 请求头，单独为 `/about` 路由设置了 `from` 请求头。

:::tip
路由中设置的 `headers` 会覆盖入口中设置的 `headers`。
:::