跳到主要内容

构建静态站

Analog 在构建部署时支持静态站点生成。这包括将提供的路由预渲染到静态 HTML 以及客户端应用。

静态站点生成

从路由列表

要预渲染页面,请使用 prerender 属性来配置在构建时的要渲染的路由。预渲染的路由也可以通过异步的方式提供。

import { defineConfig } from 'vite';
import analog from '@analogjs/platform';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
plugins: [
analog({
prerender: {
routes: async () => [
'/',
'/about',
'/blog',
'/blog/posts/2023-02-01-my-first-post',
],
},
}),
],
}));

从内容目录

也许你想将所有的内容目录的路由都进行预渲染。 例如你有一个博客并且所有的文章都是位于 contents 目录的 Markdown 文件。 在这种情况下,你可以在 routes 配置里添加一个对象来渲染一个目录下的所有内容。 请注意,目录结构可能不会完全跟应用的路径完全匹配。 因此,您必须传递一个将文件路径映射到 URL 的 transform 函数。 返回的字符串应该是应用中的 URL 路径 transform 函数还可以通过返回 false 的方式过滤掉一些不想预渲染的路由。 例如在前言部分被标记为 draft 的文件将不会被进行预渲染处理 配置对象的 contentDir 值可以是一个 glob 范式,也可以只是一个目录。

import { defineConfig } from 'vite';
import analog, { type PrerenderContentFile } from '@analogjs/platform';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
plugins: [
analog({
prerender: {
routes: async () => [
'/',
'/blog',
{
contentDir: 'src/content/blog',
transform: (file: PrerenderContentFile) => {
// do not include files marked as draft in frontmatter
if (file.attributes.draft) {
return false;
}
// use the slug from frontmatter if defined, otherwise use the files basename
const slug = file.attributes.slug || file.name;
return `/blog/${slug}`;
},
},
],
},
}),
],
}));

仅渲染静态页

要只渲染静态页,使用 static: true 标记。

import { defineConfig } from 'vite';
import analog from '@analogjs/platform';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
plugins: [
analog({
static: true,
prerender: {
routes: async () => [
'/',
'/about',
'/blog',
'/blog/posts/2023-02-01-my-first-post',
],
},
}),
],
}));

静态页可以从 dist/analog/public 目录来部署。

网站地图生成

Analog 同样支持自动的网站地图生成。如果指定了网站地图配置,生成的网站地图位于 dist/analog/public目录。

import { defineConfig } from 'vite';
import analog from '@analogjs/platform';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
plugins: [
analog({
prerender: {
routes: async () => ['/', '/blog'],
sitemap: {
host: 'https://analogjs.org/',
},
},
}),
],
}));

只要提供了路由,Analog 会生成包含页面的 <loc><lastmod> 属性的 sitemap.xml 文件。

<?xml version="1.0" encoding="UTF-8"?>
<urlset...>
<!--This file was automatically generated by Analog.-->
<url>
<loc>https://analogjs.org/</loc>
<lastmod>2023-07-01</lastmod>
</url>
<url>
<loc>https://analogjs.org/blog</loc>
<lastmod>2023-07-01</lastmod>
</url>
</urlset...>

Post-rendering 钩子

Ananlog 支持预渲染处理过程中的 post-rendering 钩子。通过 post-rendering 钩子可以用来在 HTML 文件里执行内联关键 CSS,添加/删除脚本等操作。

下面的例子展示了如何在代码中使用 postRenderingHooks

import analog from '@analogjs/platform';
import { defineConfig } from 'vite';
import { PrerenderRoute } from 'nitropack';

// https://vitejs.dev/config/
export default defineConfig(() => {
return {
publicDir: 'src/public',
build: {
target: ['es2020'],
},
plugins: [
analog({
static: true,
prerender: {
routes: async () => [],
postRenderingHooks: [
async (route: PrerenderRoute) => console.log(route),
],
},
}),
],
};
});

PrerenderRoute 提供了关于 routecontentsdata以及fileName的信息,这些信息对于在预渲染阶段更改内容很有用。

下面是一个小例子,我们可以使用 postRenderingHooks 在预渲染过程中附加一个脚本来包含 Google Analytics:

/// <reference types="vitest" />

import analog from '@analogjs/platform';
import { defineConfig, splitVendorChunkPlugin } from 'vite';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
import { PrerenderRoute } from 'nitropack';

// https://vitejs.dev/config/
export default defineConfig(() => {
return {
publicDir: 'src/public',
build: {
target: ['es2020'],
},
plugins: [
analog({
static: true,
prerender: {
routes: async () => ['/', '/aboutus'],
postRenderingHooks: [
async (route: PrerenderRoute) => {
const gTag = `<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-xxxxxx-1', 'auto');
ga('send', 'pageview');
</script>`;
if (route.route === '/aboutus') {
route.contents = route.contents?.concat(gTag);
}
},
],
},
}),
],
};
});