SSG
SSG 全称为 Static Site Generate,静态站点生成
在 SSR 中的一小节有提到,当不同的路由请求发送到 express 服务的时候,本质上命中的是通配符 *,然后根据不同的 url 渲染页面:
async function render(url, manifest) {
const { app, router } = createApp()
await router.push(url)
await router.isReady()
const ctx = {}
const html = renderToString(app, ctx)
}那么,如果每次返回的内容相对是静态的,我们似乎可以提前进行渲染,除了 index.html 之外,生成多个路由对应的 HTML 文件
假设我们的项目中有如下多个页面(例如使用了 vite-plugin-page 插件),如下面的 pages 文件夹:
pages
- home.vue
- about.vue
- external.vue
- foo.vue
- vite.config.ts
- package.json
我们就可以写一个 prerender.js 脚本:
const toAbsolute = p => path.resolve(__dirname, p)
const manifest = JSON.parse(
fs.readFileSync(toAbsolute('dist/static/.vite/ssr-manifest.json'), 'utf8'),
)
const template = fs.readFileSync(toAbsolute('dist/static/index.html'), 'utf8')
const { render } = await import('./dist/server/entry-server.js')
const routesToPrerender = fs
.readdirSync(toAbsolute('src/pages'))
.map(file => {
const name = file.replace(/\.vue/, '').toLowerCase()
return name === 'home' ? `/` : `/${name}`
})
;(async () => {
for(const url of routesToPrerender) {
const [appHtml, preloadLinks] = await render(url, manifest)
const html = template
.replace('<!--app-html-->', appHtml)
const filePath = `dist/static${url === '/' ? 'index.html/' : url}.html`
fs.writeFileSync(filePath, html)
}
fs.rmSync(toAbsolute('dist/static/.vite'), { recursive: true })
})()所以 SSG 的做法可以理解为,在 SSR 打包之后执行一个额外的生成脚本,进行预渲染
{
"scripts": {
"build:client": "vite build --ssrManifest .vite/ssr-manifest.json --outDir dist/client",
"build:static": "vite build --ssrManifest .vite/ssr-manifest.json --outDir dist/static",
"build:server": "vite build --ssr src/entry-server.js --outDir dist/server",
"ssr": "npm run build:client && npm run build:server",
"ssg": "npm run build:static && npm run build:server && node ./prerender.js"
}
}