我有个同事,叫小美,脑回路有时候挺清奇的。今天她突然蹦过来,一脸严肃地问:“哎,咱们有没有什么工具能把 Vue3 项目直接转成 HTML 啊?客户想本地双击 index.html 就能打开项目。”
我还没来得及说话,她接着说:“打包后的项目一打开就是空白,还报什么跨域问题……你说,是不是要重写成纯 HTML 啊?”
我愣了三秒,差点没忍住笑出声:“等一下,小美,客户一句话,你就准备重写整个项目了?你觉得这有必要吗?”
她满脸困惑地看着我:“不是嘛?那我们怎么办啊?打包后的项目不能用呀,客户都急了。”
我翻了个白眼,拍了拍她的肩膀:“小美,这根本不是重写代码的事儿啊!你打包后文件路径不对,浏览器在本地用 file:// 协议的时候,默认不允许 ES Module 跨域加载。所以,你看到页面空白和跨域报错,这都正常。”
小美挠挠头:“啊?那咋办啊?你说得那么复杂,是不是还得折腾半天啊?”
我笑得差点岔气:“哪儿复杂了?你就改一下配置,把路径改成相对的,再加个插件处理 ES Module 就行了,分分钟搞定。还重写?你要真重写,估计客户等得头发都白了!”
小美瞪大眼睛:“哦!这么简单啊……那早说嘛!我还以为要干一大票活呢!”
核心问题分析:
- 文件路径不对:通常,Vite 或 Webpack 默认配置根目录为 /,这是一个绝对路径。当我们通过 Web 服务启动时,资源路径是通过域名来解析的,所以它能够正确加载。而本地打开时,file:// 协议并不具备跨域的定义,因此会遇到资源加载失败的问题。
解决方案:
为了在本地成功访问打包后的项目,需要做几步配置调整:
- 调整资源路径为相对路径
- Vue 2.x 项目:修改 webpack 配置中的 publicPath 为 "./" 即可。
- Vue 3.x 项目:使用 Vite 时,修改 vite.config.js 中的 base 为 "./"。
// vite.config.js
export default defineConfig({
base: './', // 设置为相对路径,确保本地打开文件时能找到资源
});
- 解决 ES Module 跨域问题
Vite 在打包时默认启用了 ES Module,跨模块加载时浏览器会认为存在跨域问题。file:// 协议不具备跨域处理能力,因此还需要安装一个 Vite 插件来解决这个问题。
- 安装 Vite 插件 @vitejs/plugin-legacy,它可以为旧浏览器和本地文件系统提供兼容性。
npm install @vitejs/plugin-legacy -D
- 修改 vite.config.js 配置,引入 legacy 插件:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import legacy from '@vitejs/plugin-legacy';
export default defineConfig({
base: './',
plugins: [
vue(),
legacy({
targets: ['ie>=11'], // 支持旧版浏览器
additionalLegacyPolyfills: ['regenerator-runtime/runtime']
})
]
});
- 使用 Hash 模式路由
如果项目使用了 Vue Router 并且在本地打开时,history 模式的路由可能会失效,因为本地文件系统不支持 URL 重写。为了解决这个问题,可以将路由模式改为 hash 模式:
import { createRouter, createWebHashHistory } from 'vue-router';
const router = createRouter({
history: createWebHashHistory(), // 使用 Hash 模式
routes: [
// 你的路由配置
]
});
- 打包并测试
完成上述配置后,重新打包项目:
npm run build
打包完成后,进入生成的 dist 目录,双击 index.html 文件。此时,你应该能够在本地通过双击打开文件并预览整个项目,而不会再遇到跨域问题。
总结
通过这些简单的配置调整,你可以让 Vue3 项目在本地环境中无需启动 Web 服务而直接打开。虽然最开始看起来像是一个必须重构的问题,但实际上通过修改 Vite 配置和引入插件,我们可以轻松解决跨域和资源路径的问题,让打包后的文件直接在本地打开运行。
这也提醒我们,遇到问题时不必急于重写代码,而应该先弄清楚问题的本质,找到最有效率的解决方案。
如果有接口访问, 后端开放 cors 也可以访问