非type="module"脚本中如何实现import.meta.url的相对路径获取?
传统脚本中获取当前脚本路径的可靠方案(不受 标签影响)
在未使用type="module"的传统脚本里,直接用document.currentScript.src获取路径会被页面的<base href>标签干扰,导致拿到的路径不符合预期。下面提供两种全面的解决方案,覆盖不同场景:
方法一:利用URL对象解析(推荐,兼容性好)
通过URL构造函数结合document.currentScript和document.baseURI,可以自动修正<base>标签带来的路径偏移,准确获取脚本的绝对路径,再按需转换为相对路径。
// 获取当前脚本的各类路径 const getCurrentScriptPaths = () => { const currentScript = document.currentScript; if (!currentScript) return null; // 仅在脚本同步执行时有效,异步/动态插入脚本可能取不到 // 解析出不受<base>影响的绝对URL const absoluteScriptUrl = new URL(currentScript.src, document.baseURI); // 计算相对于当前页面URL的相对路径 const pageUrl = new URL(window.location.href); const relativeToPage = absoluteScriptUrl.pathname.replace(pageUrl.pathname, '') || './'; return { absoluteUrl: absoluteScriptUrl.href, // 完整绝对路径 relativeToPage: relativeToPage, // 相对于当前页面的路径 relativeToRoot: absoluteScriptUrl.pathname // 相对于网站根目录的路径 }; }; // 使用示例 const paths = getCurrentScriptPaths(); console.log('绝对路径:', paths?.absoluteUrl); console.log('相对页面路径:', paths?.relativeToPage);
原理说明
URL构造函数的第二个参数会作为解析基准,传入document.baseURI(即页面<base>标签指定的路径,无base标签时等于当前页面URL),能精准还原脚本的实际加载地址,避免<base>的干扰。
方法二:通过Error堆栈获取(适配动态/异步脚本)
如果脚本是动态插入或带有async/defer属性,document.currentScript可能返回null,此时可以利用Error对象的堆栈信息提取脚本路径:
const getCurrentScriptPathFromStack = () => { try { throw new Error(); } catch (error) { const stackLines = error.stack.split('\n'); let scriptUrl = null; // 适配不同浏览器的堆栈格式 for (const line of stackLines) { // Chrome/Edge格式:"at ... (http://xxx.js:xx:xx)" const chromeMatch = line.match(/\((https?:\/\/[^)]+)\)/); // Firefox格式:"@ http://xxx.js:xx:xx" const firefoxMatch = line.match(/@(https?:\/\/[^:]+)/); if (chromeMatch) { scriptUrl = chromeMatch[1]; break; } else if (firefoxMatch) { scriptUrl = firefoxMatch[1]; break; } } if (scriptUrl) { return new URL(scriptUrl, document.baseURI).href; } return null; } }; // 使用示例 const scriptPath = getCurrentScriptPathFromStack(); console.log('脚本路径:', scriptPath);
注意事项
- 不同浏览器的堆栈格式存在差异,需要做兼容性适配;
- 部分生产环境的代码压缩工具可能会移除堆栈信息,需提前测试。
额外场景:手动标记路径
如果上述方法都不适用,可以在脚本标签中添加自定义data-*属性手动指定路径,虽然不够自动化,但稳定性最高:
<script src="./scripts/foo.js" data-script-path="./scripts/foo.js"></script>
在脚本中读取:
const currentScript = document.currentScript; const relativePath = currentScript?.dataset.scriptPath;
内容的提问来源于stack exchange,提问作者David Alsh
相关产品推荐
相关产品推荐

