知識要求
babel
的基礎知識(推薦阮一峰的babel入門教程)- 充分理解
babel-plugin-transform-runtime
與babel-runtime
的作用(推薦github項目首頁) webpack2
基礎用法(https://webpack.js.org/)webpack2
中babel-loader
作用,import
異步加載
問題說明
webpack
+babel-loader
+transform-runtime
正常來講應該能實現在沒有原生支持Promise
的瀏覽器(如IE
)下正常運行,但是實際在IE11
下,還是提示Promise
未定義的錯誤。網上找了一圈,沒有切中要害的,於是干脆自己分析。
分析
首先確認babel
的transform-runtime
是否生效,在自己的js
代碼中編寫var promise = new Promise(resolve, reject)
的示例代碼,發現Promise
是有被替換的。所以問題的關鍵在於什么東西超出了babel
的控制?
我想到的是node_modules
與webpack
本身生成的代碼。
在使用babel
轉換ES6
之前, 通過node_modules
引用的第三方包都能正常使用,因此可以排除。
那么webpack
呢,在GOOGLE
中搜索webpack promise not defined
,還真找到了原因,如下圖所示:
圖片來源: https://webpack.js.org/guides/migrating/#require-ensure-and-amd-require-are-asynchronous
當使用了webpack
的異步加載時,webpack
要求原生支持Promise
,剛好我們的代碼有用到。至此,原因就找到了:
webpack
生成的new Promise
相關代碼, 超出babel
的transform-runtime
的控制范圍,只有導出全局的Promise
才能解決此問題。
解決方案1
- 引入
babel-polyfill
導出全局Promise
,這種方法並不好;不僅Promise
被導出,還拋出大量其他的全局對象,可能存在沖突風險,同時文件體積比較大。
解決方案2
在js
文件開頭添加window.Promise = Promise
這一句即可,示例代碼:
import 'jquery'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap'
// 將Promise拋出為全局對象
window.Promise = Promise
。。。
原理:當babel
檢查到js
的Promise
時,transform-runtime
會將Promise
做轉換,然后將其拋出為全局對象即可達到跟babel-polyfill
一樣的效果。