迁移至Vite后栈式脚本执行时机异常导致函数未定义
Vite迁移后脚本调用报错的本质原因解析
核心差异:Vite与Webpack的脚本加载机制不同
Webpack打包后的脚本是同步执行的——浏览器解析到Webpack输出的<script>标签时,会立刻执行里面的代码,window.myfoo会被同步挂载到全局对象上,后续@push的脚本执行时,全局函数已经存在,自然能正常调用。
但Vite用的是原生ES模块加载,它生成的app.js脚本标签自带type="module"属性:
<script type="module" src="/assets/app.xxxx.js"></script>
浏览器对type="module"的脚本会异步加载执行,哪怕这个脚本标签写在@push脚本的前面,它的执行时机也可能晚于后面的同步脚本。这就导致@push里直接调用myfoo()时,app.js里的代码还没跑完,window.myfoo还没被挂载,所以抛出"未定义"的错误。
为什么控制台/setTimeout调用能正常工作?
- 控制台调用时,Vite的模块脚本已经加载执行完毕,
window.myfoo已经存在于全局。 setTimeout会把函数调用放到任务队列,等当前同步代码全部执行完后再触发,此时Vite的模块脚本基本已经执行完成,所以能找到myfoo。
DOMContentLoaded能解决的原因
DOMContentLoaded事件会在页面DOM结构加载完成后触发,此时所有脚本(包括Vite的模块脚本)都已经加载执行完毕,window.myfoo已经挂载到全局,调用自然不会报错。
直观验证方法
查看页面最终渲染的HTML源码,你会发现Vite生成的app.js脚本标签带有type="module",而Webpack打包的脚本没有这个属性——这就是两者加载行为差异的直接体现。
内容的提问来源于stack exchange,提问作者Jeremy Belolo
相关产品推荐
相关产品推荐

