Vite 打包后支持本地预览
让vite + vue3的项目,执行npm run build后得到的产物无需经服务器部署,在本地通过双击index.html即可运行。
让 VIte+Vue3打包后的项目,在本地通过双击 index.html 即可运行预览
前言:
因项目需要,要求项目打包后的产物能和以前的项目一样直接在本地进行预览,不需要行经服务代理,经过一番查询,仍然踩了很多坑,再加上最近忙于项目和其它事情,也有一段时间没更新了,遂在此记录,喜欢能对各位有所帮助,减少踩坑。
问题分析:
修改index.html文件,删除script标签中带有nomodule、crossorigin的属性,修改data-src为src,link同理,所有引入资源的路径前缀都应该是./开头即相对路径而非绝对路径。
截图:

原因详解:
打包后的index.html无法直接打开的原因在于以下几点:
script标签:
src:打包后的资源引入是通过”data-src“引入的,而data-src是一个自定义数据属性,不是标准 HTML 属性,它通常用于存储额外的自定义数据,所以它不会被浏览器自动处理或执行。这就意味着js脚本不会被游览器自动识别和加载。
nomodule:它的用途主要是用于提供游览器兼容性的,标识一个脚本只应在不支持 ES6 模块的浏览器中执行,而现代浏览器支持 ES6 模块,不会执行带有 nomodule 的脚本。
crossorigin:用于控制跨源请求的安全策略,对于从其他域加载的脚本,如果不设置正确的 CORS 头,浏览器可能会拒绝加载脚本或限制某些功能。
src:加载的路径为绝对路径,即以/开头的路径,导致找不到资源
Link标签:
crossorigin:用于控制跨源请求的安全策略,对于从其他域加载的脚本,如果不设置正确的 CORS 头,浏览器可能会拒绝加载脚本或限制某些功能。
href:加载的路径为绝对路径,即以/开头的路径,导致找不到资源
解决办法:
一. 修改路径
在vite.config.ts文件中修改base配置为相对路径。
export default defineConfig({
plugins: [],
base: "./",
// 其它配置
})二. 修改路由模式
修改路由模式为has模式,不然你可能打开会看见一片空白。
在此处需要注意的是,如果访问的地址需要携带额外前缀如:http://custom/index.html中的custom,需要在路由创建地方进行配置。
import {createRouter, createWebHashHistory} from "vue-router";
const router = createRouter({
history: createWebHashHistory("/custom"), // 如果不需要配置前缀,不传递任何参数即可
routes,
});三:安装插件
npm i @vitejs/plugin-legacy -D插件安装完成后在vite.config.ts中使用该插件。
import legacy from "@vitejs/plugin-legacy";
export default defineConfig(() => ({
base: "./",
plugins: [
vue(),
legacy({
targets: ["defaults", "not IE 11"]
}),
]
})四. 创建脚本并执行
1. 在任意磁盘目录下新建一个文件夹,文件夹名称为英文避免使用中文,创建完成后,在文件路径处输入cmd,进入cmd控制台。

2. 在cmd中输入npm init,然后一路回车,然后在目录中会多出一个package.json。
3. 在安装一个用于解析dom的库。
npm i jsdom -D4. 新建一个文本文档,把以下内容复制进去,然后修改文件名和后缀名为build.js。
const fs = require("fs");
const { JSDOM } = require("jsdom");
function loadFile() {
try {
console.log("文件读取中...");
const dom = new JSDOM(fs.readFileSync("./dist/index.html"));
console.log("文件读取成功");
replaceScript(dom);
} catch {
console.error("未找到文件!");
}
}
function replaceScript(dom) {
console.log('文件编译中...');
const tags = dom.window.document.querySelectorAll("*[type=\"module\"]");
for(var i = 0 ; i < tags.length; i++) {
const tag = tags[i];
if (tag) tag.parentElement.removeChild(tag);
}
const nomoduleTags = dom.window.document.querySelectorAll("script");
for(var i = 0 ; i < nomoduleTags.length; i++) {
const tag = nomoduleTags[i];
if (!tag) return;
tag.removeAttribute("nomodule");
tag.removeAttribute("crossorigin");
if (tag.getAttribute("data-src") || tag.getAttribute("src")) {
const src = tag.getAttribute("data-src") || tag.getAttribute("src");
tag.removeAttribute("data-src");
if (src && src.indexOf(".") !== 0) {
tag.setAttribute("src", "." + src);
} else {
tag.setAttribute("src", src);
}
}
}
const linkTags = dom.window.document.querySelectorAll("link");
for(var i = 0 ; i < tags.length; i++) {
const tag = tags[i];
if (!tag) return;
tag.removeAttribute("crossorigin");
const href = tag.getAttribute("href");
if (href && href.indexOf(".") !== 0) tag.setAttribute("href", "." + href);
}
const html = "<!DOCTYPE html>\r\n" + dom.window.document.documentElement.outerHTML;
fs.writeFileSync("./dist/index.html", html);
console.log('文件编译成功');
}
loadFile();5. 把打包好的dist文件拷贝至该目录,此时内容应是如下结构

6. 在cmd中执行node build.js,提示编译成功,此时双击index.html即可正常预览。

7. 脚本解释:
该脚本主要执行了,查找dist目录下的index.html文件,然后解析它,在查找对应的属性和标签进行移除或修改。
如果感觉本文对您有所帮组的话点个赞在走把~,如您有任何疑问或见解欢迎您在下方评论区留言讨论
