动态使用URL.createObjectURL结合import()时根路径模块解析失败的问题求助
我最近碰到一个头疼的问题:当我用URL.createObjectURL生成Blob URL来动态导入模块时,没办法从网站根目录相对导入其他模块,但同样的根路径导入/some-path.js在静态导入里完全正常。
我的代码是这样的:
const fileContents = `import { test } from "/some-path.js"`; const blob = new Blob([fileContents], { type: "application/javascript" }); const moduleUrl = URL.createObjectURL(blob); try { const importedModule = await import(moduleUrl); } catch (err) { console.error(err); } finally { URL.revokeObjectURL(moduleUrl); }
运行这段代码后,会抛出这个错误:
TypeError: Failed to resolve module specifier "/some-path.js". Invalid relative url or base scheme isn't hierarchical.
我试了各种方法都没搞定,静态导入根路径完全没问题,有没有大佬能给我点建议怎么解决这个问题呀?
问题根源
其实这个问题的核心是Blob URL的解析基准和网站根目录不一样:通过URL.createObjectURL生成的URL是blob:协议开头的,它的解析基准是这个Blob自身的URL,而不是你的网站的http/https协议根目录。静态导入时浏览器会自动以当前网站的origin作为解析基准,所以根路径能正常工作,但动态Blob模块就不行了。
解决方案
这里给你两个简单可行的解决方法:
方法一:把根路径导入替换为基于网站origin的绝对路径
直接在生成Blob内容时,把根路径拼接上网站的origin,让导入路径变成完整的绝对URL:
const siteOrigin = window.location.origin; // 把根路径替换成带origin的绝对路径 const fileContents = `import { test } from "${siteOrigin}/some-path.js"`; const blob = new Blob([fileContents], { type: "application/javascript" }); const moduleUrl = URL.createObjectURL(blob); try { const importedModule = await import(moduleUrl); } catch (err) { console.error(err); } finally { URL.revokeObjectURL(moduleUrl); }
方法二:使用new URL()统一解析根路径(适合多个根路径导入的场景)
如果你的Blob模块里有多个根路径导入,可以在模块开头定义一个解析函数,批量处理路径转换:
const fileContents = ` // 定义根路径解析函数 const resolveRoot = (path) => new URL(path, window.location.origin).href; import { test } from resolveRoot("/some-path.js"); // 其他根路径导入也可以用这个函数 import { utils } from resolveRoot("/utils/helper.js"); `; // 后面的Blob和导入代码不变 const blob = new Blob([fileContents], { type: "application/javascript" }); const moduleUrl = URL.createObjectURL(blob); try { const importedModule = await import(moduleUrl); } catch (err) { console.error(err); } finally { URL.revokeObjectURL(moduleUrl); }
这样不管有多少个根路径导入,都可以用这个函数统一解析,避免重复拼接origin。
额外提示
如果你的项目使用了前端构建工具(比如Vite、Webpack),也可以考虑通过配置模块别名来处理,但这种方式更适合静态代码的场景,像你这种动态生成Blob的情况,还是上面两种方法更直接有效。
备注:内容来源于stack exchange,提问作者Bart Louwers

