document.currentscript 在 ie 中完全不可用,需通过运行时检测、stack trace 解析或显式 data-path 属性 fallback;webpack 项目中它指向 bundle 而非源文件,推荐构建时写死路径。

document.currentScript 在 IE 中根本不可用
老项目大概率要兼容 IE9–11,而 document.currentScript 是 IE 完全不支持的 API(Edge 13+ 才开始支持)。直接使用会触发 TypeError: Cannot read property 'src' of null 或静默失败。别指望它在 IE 下返回任何东西——它就是 undefined。
实操建议:
- 先做运行时检测:
if ('currentScript' in document),否则立刻 fallback - 不要把它当默认方案,尤其在 webpack/vite 打包后的老项目里,
document.currentScript即使在 Chrome 中也可能指向内联<script></script>或模块加载器注入的 script,而非原始物理文件 - 若脚本是通过
document.write注入(常见于老旧统计代码),document.currentScript会失效——此时它指向的是写入它的那个 script,不是被写入的那个
兼容性 fallback:靠 stack trace 解析当前 script URL
在 IE 和部分低版本 Edge 中,唯一较可靠的路径获取方式是捕获错误堆栈,从中提取 script 标签的 src。原理是:在脚本顶层立即抛错并捕获 error.stack,Chrome/Firefox/IE10+ 都会在 stack 中包含调用位置的文件路径。
实操建议:
- 用立即执行的 try-catch 包裹一段带错误的代码,例如:
var __scriptUrl = (function() { try { throw new Error(); } catch (e) { var m = e.stack.match(/(?:http|https|file):\/\/[^\s)]+/); return m ? m[0] : ''; } })(); - 注意正则匹配要宽松:
file://协议、带 query 参数(如?v=1.2.3)、甚至带 fragment(#init)都得能提取出来 - 该方法在 strict 模式下依然有效,但若脚本被压缩且未保留 source map,stack 中可能只有
anonymous,此时 fallback 到空字符串比硬报错更安全
更稳妥的老项目方案:显式传入 script path
很多老项目其实已有约定:在全局挂载一个 __SCRIPT_PATH__ 变量,或在 script 标签上加自定义属性,例如:<script data-path="/js/widget.js" src="/js/widget.js"></script>。这比依赖运行时推断可靠得多。
实操建议:
- 在 script 标签加载前,用
document.getElementsByTagName('script')拿到最后一个(即当前执行的),再读它的getAttribute('data-path')或src - 如果脚本是动态插入的,插入时就同步设置:
var s = document.createElement('script'); s.setAttribute('data-path', '/js/legacy.js'); s.src = '/js/legacy.js'; document.head.appendChild(s); - 避免读
src属性后做字符串截断(比如去 query),因为相对路径(./util.js)需结合页面 base href 解析,应优先用new URL(s.src, document.baseURI).href(IE 不支持,所以仍需 fallback 到 data-path)
webpack 打包项目中 document.currentScript 的陷阱
即使项目已迁移到 webpack,但保留了旧版 HTML 直接引用打包后 script 的方式,document.currentScript 返回的往往是 bundle.js 的路径,而不是你期望的 widget.js 物理路径——因为源码已被合并,原始文件信息丢失。
实操建议:
- 不要在
import模块内部依赖document.currentScript;它只对<script src="..."></script>外链有效 - 若必须知道模块原始路径,改用 webpack 的
__filename(Node.js 环境)或import.meta.url(现代浏览器),但二者在老项目中均不可用 - 最务实的做法:构建时把入口文件名写死进 bundle,例如通过 DefinePlugin 注入
__ENTRY_NAME__ = 'widget',再拼出路径/js/${__ENTRY_NAME__}.js










