Vite+Vue3打包离线访问Html

358 阅读2分钟

众所周知,Vite打包后的静态html是不能直接访问的,因为esmodule的关系,导致访问html会出现文件跨域问题,因此我们采取@vitejs/plugin-legacy的方式适配打包为no module,然后通过插件进一步处理打包后的产物,通过大量测试,目前已经形成vite打包后的html支持使用file协议离线访问。

安装@vitejs/plugin-legacy

yarn add -D @vitejs/plugin-legacy

新增Vite插件

import type { Plugin } from 'vite';

import { parse } from 'node-html-parser';

const needBasePathArr = ['src', 'data-src'];

/**
 * 离线访问HTML插件
 * 删除html中script标签的module及nomodle属性
 * 配合@vitejs/plugin-legacy插件可以直接本地访问html
 * @returns
 */
function htmlPostBuildPlugin(base?: string): Plugin {
  return {
    name: 'html-post-build',
    enforce: 'post',
    apply: 'build',
    transformIndexHtml(html) {
      const root = parse(html);

      // 删除modulescript标签
      while (root.querySelector('script[type="module"]')) {
        const moduleScript = root.querySelector('script[type="module"]');
        moduleScript.remove();
      }
      // 删除modulepreload标签
      const prereloadScript = root.querySelector('link[rel="modulepreload"]');
      prereloadScript && prereloadScript.remove();
      const nomoduleScripts = root.querySelectorAll('script[nomodule]');
      for (let i in nomoduleScripts) {
        // 删除nomodule属性
        nomoduleScripts[i].removeAttribute('nomodule');
        nomoduleScripts[i].removeAttribute('crossorigin');
        // 由于legacy插件打包出来的script标签中的base不是相对路径(具体原因待查,可能是配置的问题,也有可能是依赖版本不兼容)
        // 如: <script id="vite-legacy-entry" data-src="js/top_n-legacy-b5355f86.js"> ,我们期望是./js/xxx
        // 这段代码大家如果没问题,可以不加,这里需要手动添加相对路径
        if (base) {
          needBasePathArr.forEach(attrName => {
            if (nomoduleScripts[i].hasAttribute(attrName)) {
              const value = nomoduleScripts[i].getAttribute(attrName);
              if (!value.startsWith(base)) {
                const fatmarttedValue = base + value;
                nomoduleScripts[i].setAttribute(attrName, fatmarttedValue);
              }
            }
          });
        }
      }

      return root.innerHTML;
    },
  };
}

export default htmlPostBuildPlugin;

vite.config.js文件中添加插件 其中,base 和 plugins 配置项

import legacy from '@vitejs/plugin-legacy';
const base = './';

export default defineConfig({
  base: base, // 正常情况配置为相对路径
  plugins:[
    vue(),
    // 配置以下两个插件
    legacy({
      targets:["defaults","not IE 11"],
    }),
    htmlPostBuildPlugin(base)
  ],
  // 报表项目打包时 @vitejs/plugin-legacy插件生成的script路径不正确,由这个配置来解决
  // 会将生成的script标签的src值由 '../../xxx/xxx' 改成 'xxx/xxx',
  // 再由插件 htmlPostBuildPlugin 将 'xxx/xxx' 改为  './xxx/xxx' 来获得正确的相对路径
  // 这段代码大家如果没问题,可以不加
  experimental: {
    renderBuiltUrl: url => {
      return url;
    },
  },
});

试着打下包,看看可不可行,毕竟每个项目的自身情况不同,碰到的问题也不一定一样