解决前端打包直接访问index.html发生的跨域报错
有的时候,项目打包后不想启用服务,又想直接本地访问打包后的index.html项目。
1.报错详情:
js
index.html:1 Access to script at 'file:///D:/codes/web-react/dist/assets/index-CxPD88b2.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: chrome-extension, chrome-untrusted, data, edge, http, https, isolated-app.
index-CxPD88b2.js:1
Failed to load resource: net::ERR_FAILED
index.html:1 Access to CSS stylesheet at 'file:///D:/codes/web-react/dist/assets/index-Bf4PHeBe.css' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: chrome-extension, chrome-untrusted, data, edge, http, https, isolated-app.
2. dist文件
index.html 内容
html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>X6 Flow Editor</title>
<script type="module" crossorigin src="./assets/index-CxPD88b2.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-Bf4PHeBe.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
3.错误原因
现代浏览器使用 ES 模块(ESM)加载 JavaScript 文件。ESM 要求 JavaScript 文件使用正确的协议(如 http 或 https),而不能使用 file:// 协议。
而这段代码使用了 file协议: <script type="module" crossorigin src="./assets/index-CxPD88b2.js"></script>
,当直接打开 index.html 文件时,使用的是 file:// 协议,这会导致:现代浏览器因为安全策略,限制了 file:// 协议下的 ESM 加载, 出现 CORS(跨域资源共享)错误 。
就是说现代的浏览器为了安全性,禁止了file协议的使用,所以访问直接打包后的项目会报错。
解决办法
这里使用vite工具通过配置@vitejs/plugin-legacy插件,自动处理模块加载的兼容性问题,避免了 file:// 协议下的 CORS 问题。
@vitejs/plugin-legacy 插件的作用
生成两个版本的代码:一个现代版本和一个兼容版本
使用传统的脚本加载方式(而不是 ESM)
自动处理模块加载的兼容性问题
避免了 file:// 协议下的 CORS 问题
安装
js
pnpm install @vitejs/plugin-legacy
使用
创建一个 legacy.ts 文件:
js
import legacy from '@vitejs/plugin-legacy';
export default legacy({
targets: ['ie>=11'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
});
在 vite.config.ts 文件中引入:
js
import { defineConfig } from "vite";
import * as path from "path";
import legacy from "./plugins/legacy";
export default defineConfig({
base:'./',
plugins:legacy,
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
server: {
host: "0.0.0.0", //ip地址
port: 8086, // 设置服务启动端口号
},
});
使用 @vitejs/plugin-legacy 打包之后的index.html文件:
js
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>X6 Flow Editor</title>
<script type="module" crossorigin src="./assets/index-CTxLVFoW.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-BJhNsWlE.css">
<script type="module">import.meta.url;import("_").catch(()=>1);(async function*(){})().next();if(location.protocol!="file:"){window.__vite_is_modern_browser=true}</script>
<script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script>
</head>
<body>
<div id="root"></div>
<script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
<script nomodule crossorigin id="vite-legacy-polyfill" src="./assets/polyfills-legacy-ByMQLnbB.js"></script>
<script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/index-legacy-BptH6DBt.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
</body>
</html>