众所周知,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;
},
},
});
试着打下包,看看可不可行,毕竟每个项目的自身情况不同,碰到的问题也不一定一样