前言

由于业务需求需要用到预渲染,vite+vue3没有找到好的库。

考虑使用prerender-spa-plugin这个插件满足需求。

以下是我的配置信息。

const PrerenderSpaPlugin = require("prerender-spa-plugin");
const Renderer = PrerenderSpaPlugin.PuppeteerRenderer
const path = require("path");

module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV !== "production") return;
    return {
        plugins: [
            new PrerenderSpaPlugin({
                staticDir: path.join(__dirname, 'dist'),
                routes: ['/', '/home', '/test', '/about'],
                renderer: new Renderer({
                    timeout: 0,
                    maxConcurrentRoutes: 1,
                    renderAfterTime: 5000,
                    headless: false
                })

            }),
        ]
    };
}
};

使用过程中诸多报错,但后续都以解决。

最终卡在这个条报错信息上。

Unable to prerender all routes!

在这里插入图片描述

查阅国内外论坛,查找到了了诸多解决方案。

方案一:修改源码

// node_modules/@prerenderer/renderer-puppeteer/es6/renderer.js
const navigationOptions = (options.navigationOptions) ? { waituntil: 'networkidle0', ...options.navigationOptions } : { waituntil: 'networkidle0' };

await page.goto(`${baseURL}${route}`, navigationOptions); // navigationOptions -> { waituntil: 'networkidle0'}

在\node_modules@prerenderer\renderer-puppeteer\es6\renderer.js中第113行

await page.goto(`${baseURL}${route}`, navigationOptions);

改为:

 await page.goto(`${baseURL}${route}`, {...navigationOptions, timeout:0} );
//或者 await page.goto(`${baseURL}${route}`, { waitUntil: 'domcontentloaded' });

方案二:prerender-spa-plugin-next

在找到prerender-spa-plugin-next之前,我一直在处理相同的错误输出。然后我注意到最新版本的prerender-spa-plugin是 4 年前发布的,并且 prerender-spa-plugin-next 正在不断更新。看起来 prerender-spa-plugin-nextprerender-spa-plugin 的新版本,具有相同的功能。所以我使用 prerender-spa-plugin-next 而不是 prerender-spa-plugin 然后一切正常!

vue.config.js

这里附上配置信息

// 预渲染插件
const PrerenderSPAPlugin = require("prerender-spa-plugin-next");
// 可选
const renderer = require("@prerenderer/renderer-puppeteer");  

//configureWebpack
configureWebpack: (config) => {
    if (process.env.NODE_ENV === "production") {
      // 为生产环境修改配置...
      config.mode = "production";
      config.performance = {
        //打包文件大小配置
        maxEntrypointSize: 10000000,
        maxAssetSize: 30000000,
      };
      // 移除console及注释
      config.plugins.push(
        new UglifyJsPlugin({
          uglifyOptions: {
            output: {
              comments: false, // 去掉注释
            },
            warnings: false,
            compress: {
              drop_console: true,
              drop_debugger: false,
              pure_funcs: ["console.log"], //移除console
            },
          },
          sourceMap: false,
          parallel: true,
        }),
        // new CompressionPlugin({
        //   test: /\.(js|css|html)?$/i, // 压缩文件格式
        //   //   filename: "[path].gz[query]",
        //   filename: "[path][base].gz", // 设置成这样就行了// 压缩后的文件名
        //   algorithm: "gzip", // 使用gzip压缩
        //   // 只有大小大于该值的资源会被处理。单位是 bytes。默认值是 0。
        //   // threshold: 10240,
        //   minRatio: 0.8, // 压缩率小于1才会压缩
        //   deleteOriginalAssets: true, // 是否删除原资源
        // }),
        new PrerenderSPAPlugin({
          routes: ["/", "/about"],
          rendererOptions: {
            // headless: false,
            renderAfterDocumentEvent: "render-event",
            inject: {},
            timeout: 10000,
          },
          // 可选
          renderer,
          //   postProcess(context) {
          //     context.outputPath = path.join(
          //       // 不要拼__dirname,最终会转成绝对路径,拼了反而出错。
          //       // PS: 为什么要加一层文件夹? 因为默认写入首页叫index.html, 不加会导致写入冲突 ——_——#
          //       "rerender",
          //       (context.route.replace("/", "") || "index") + ".html"
          //     );
          //     return context;
          //   },
          postProcess: function (context) {
            var titles = {
              "/": "Home",
              "/about": "Our Story",
              "/contact": "Contact Us",
            };
            context.html = context.html.replace(
              /<title>[^<]*<\/title>/i,
              "<title>" + titles[context.route] + "</title>"
            );
          },
          renderOptions: {
            renderAfterDocumentEvent: "prerender",
          },
        })
      );
打包后的效果图

在这里插入图片描述

方案三:vite+**vitesse**使用SSR渲染完成SEO

考虑稳定性,以及已经踩过坑的的游戏玩家数,最终采用了第二方案解决的项目中的痛点。

Logo

前往低代码交流专区

更多推荐