SSG(Static Site Generation)是一种基于数据与模板,在构建时渲染完整静态网页的技术解决方案。这意味着在生产环境中,页面默认就是有内容的,并且可以被 CDN 缓存。对于无需数据的页面,SSG 可以提供更好的性能和更高的安全性。
要在 Modern.js 项目中启用 SSG 功能,请按照以下步骤修改代码:
如果项目尚未安装 SSG 插件,请先安装:
pnpm add @modern-js/plugin-ssg请确保 @modern-js/plugin-ssg 的版本与项目中 @modern-js/app-tools 的版本保持一致。Modern.js 的所有官方包使用统一版本号发布,版本不一致可能导致兼容性问题。
请先查看 @modern-js/app-tools 的版本,然后安装相同版本的 @modern-js/plugin-ssg:
# 查看当前 @modern-js/app-tools 的版本
pnpm list @modern-js/app-tools
# 安装相同版本的 @modern-js/plugin-ssg
pnpm add @modern-js/plugin-ssg@<版本号>在 modern.config.[tj]s 文件中导入并添加 SSG 插件,同时配置 output.ssg:
import { defineConfig, appTools } from '@modern-js/app-tools';
import { ssgPlugin } from '@modern-js/plugin-ssg';
export default defineConfig({
plugins: [appTools(), ssgPlugin()],
output: {
ssg: true,
},
});output.ssg。output.ssgByEntries。output.ssg: true 且未配置 output.ssgByEntries 时,所有入口下的所有路由都会作为 SSG 路由处理。SSG 也是在 Node.js 环境渲染页面,因此我们可以在开发阶段开启 SSR,提前暴露代码问题,验证 SSG 渲染效果:
export default defineConfig({
server: {
ssr: process.env.NODE_ENV === 'development',
}
}约定式路由中,Modern.js 根据入口下的文件结构生成路由,因此框架能够收集完整的路由信息。
例如,以下是一个使用约定式路由的项目目录结构:
.
└── routes
├── layout.tsx
├── page.tsx
└── user
├── layout.tsx
├── page.tsx
└── profile
└── page.tsx上述文件目录将会生成以下三条路由:
//user/user/profile如果还不了解约定式路由的规则,可以先查看路由方案。
在 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 功能。
例如有以下代码,包含多条路由,设置 output.ssg 为 true 时,默认只会渲染入口路由即 /:
import { BrowserRouter, Route, Routes } from '@modern-js/runtime/router';
import { StaticRouter } from '@modern-js/runtime/router/server';
import { use } from 'react';
import { RuntimeContext } from '@modern-js/runtime';
const Router = typeof window === 'undefined' ? StaticRouter : BrowserRouter;
export default () => {
const context = use(RuntimeContext);
const pathname = context?.request?.pathname;
return (
<Router location={pathname}>
<Routes>
<Route index element={<div>index</div>} />
<Route path="about" element={<div>about</div>} />
</Routes>
</Router>
);
};如果我们希望同时开启 /about 的 SSG 功能,可以配置 output.ssg:
export default defineConfig({
output: {
ssg: {
routes: ['/', '/about'],
},
},
});执行 pnpm run build 后,可以看到 dist/ 目录中,新增了一个 main/about/index.html 文件。
执行 pnpm run serve 启动项目后,访问页面,在浏览器我们工具的 Network 窗口,查看请求返回的文档,文档包含组件渲染后的完整页面内容。
以上仅介绍了单入口的情况,更多相关内容可以查看 API 文档。
在自控式路由或包含动态段的约定式路由(如 /user/[id])中,直接在 routes 中写入具体路径。
export default defineConfig({
output: {
ssg: {
routes: ['/', '/about', '/user/modernjs'],
},
},
});多入口应用请通过 output.ssgByEntries 按入口分别配置:
export default defineConfig({
output: {
ssgByEntries: {
home: {
routes: ['/', '/about', '/user/modernjs'],
},
admin: false,
},
},
});详细配置请参考:output.ssgByEntries
Modern.js 支持为具体入口或路由配置请求头,例如:
export default defineConfig({
output: {
ssg: {
headers: {
'x-tt-env': 'ppe_modernjs',
},
routes: [
'/',
{
url: '/about',
headers: {
from: 'modern-website',
},
},
],
},
},
});上述配置中,为所有路由设置了 x-tt-env 请求头,单独为 /about 路由设置了 from 请求头。
路由中设置的 headers 会覆盖入口中设置的 headers。