知識要求
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一樣的效果。
