浏览器动态执行含ES6模块导入的JS代码报路径错误如何解决?
错误原因
该报错本质是
data:协议不具备层级URL上下文,浏览器无法基于data URI解析相对路径的模块引用,即使写绝对路径,主流浏览器也对data URI内部的模块导入做了安全限制,无法正常解析ES模块规范的导入声明。
最优解决方案:替换data URI为Blob对象URL
这个方案改动最小,完全兼容ES6模块规范,不需要额外配置:
async function doIt() { let code = ""; code += "import { MyClass } from './MyClass.js' ;\n"; code += 'export default function hello() { console.log( "Hello World" ); console.log( MyClass.test() ); }'; // 用Blob生成符合当前页面上下文的JS资源URL const jsBlob = new Blob([code], { type: 'text/javascript' }); const moduleUrl = URL.createObjectURL(jsBlob); try { let module = await import(moduleUrl); console.log(module); // property default contains function hello now const myHello = module.default; myHello(); // 正常输出Hello World和42 } finally { // 手动释放Blob占用的内存,避免内存泄漏 URL.revokeObjectURL(moduleUrl); } }
Blob生成的Object URL的根上下文是当前页面的origin,相对路径./MyClass.js会正常按照当前页面路径解析,绝对路径导入也可以正常使用。
其他可行替代方案
- 如果你有多个模块需要统一管理,可以使用Import Maps提前配置模块映射:
首先在页面<head>中添加导入映射声明:
动态生成代码时直接使用裸导入符即可:<script type="importmap"> { "imports": { "my-class": "./MyClass.js" } } </script>code += "import { MyClass } from 'my-class' ;\n"; - 如果依赖模块固定,也可以提前导入依赖后注入到动态函数作用域,避免动态代码内的导入声明,适合极简场景:
import { MyClass } from './MyClass.js'; async function doIt() { let code = 'export default function hello(MyClass) { console.log( "Hello World" ); console.log( MyClass.test() ); }'; const jsBlob = new Blob([code], { type: 'text/javascript' }); const moduleUrl = URL.createObjectURL(jsBlob); try { let module = await import(moduleUrl); module.default(MyClass); } finally { URL.revokeObjectURL(moduleUrl); } }
内容的提问来源于stack exchange,提问作者FunctionPoint
相关产品推荐
相关产品推荐

