干貨 -Gulp打包支持await/async語法
簡短的概括:
1、使用 ES7 的 async/await 時報錯
在項目中,最近需要對node代碼進行混淆編譯,原來曾經解決過ES6打包混淆的問題,在使用的是gulp打包,為了提升代碼質量還有異步操作順序問題,使用了async/await語法,原來的gulpfile混淆又出問題了。
出現問題:
打包完后瀏覽器報錯gulp
- Uncaught ReferenceError: regeneratorRuntime is not defined
對 babel polyfill 的一些理解
一、babel 和 babel ployfill 的關系
1、先來理解下 babel 到底是做什么的?
簡單來講,babel解決語法層面的問題。用于將ES6+的高級語法轉為ES5。
2、babel polyfill 又是做什么的?
如果要解決API層面的問題,需要使用墊片。比如常見的有babel-polyfill、babel-runtime 和 babel-plugin-transform-runtime。
理清了他們之間的關系,那么再正式來講講有關polyfill的二三事。
二、polyfill 種類
babel polyfill 有三種
- * babel-polyfill
- * babel-runtime
- * babel-plugin-transform-runtime
1、babel-polyfill
babel-polyfill通過向全局對象和內置對象的prototype上添加方法來實現的。所以這會造成全局空間污染。
babel-polyfill使用的兩種方式
1) webpack.config.js 中:
配置webpack.config.js里的entry設置為entry: ['babel-polyfill',path.join(__dirname, 'index.js')]
2) 業務 js 中:
在webpack.config.js配置的主入口index.js文件的最頂層鍵入
- import 'babel-polyfill'
兩者打印出來的大小都是一樣的,打包后大小是280KB,如果沒有使用babel-polyfill,大小是3.43kb。兩則相差大概81.6倍。原因是webpack把babel-polyfill整體全部都打包進去了。而babel-polyfill肯定也實現了所有ES6新API,文件一定不會小。
那么有沒有一種辦法,根據實際代碼中用到的ES6新增API ,來使用對應的墊片,而不是全部加載進去呢?
是的,有的。那就是 babel-runtime & babel-plugin-transform-runtime,他們可以實現按需加載。
2、babel-runtime
簡單說 babel-runtime 更像是一種按需加載的實現,比如你哪里需要使用 Promise,只要在這個文件頭部
- import Promise from 'babel-runtime/core-js/promise'
不過如果你許多文件都要使用 Promise,難道每個文件都要 import 一下嗎?當然不是,Babel 官方已考慮這種情況,只需要使用 babel-plugin-transform-runtime 就可以解決手動 import 的苦惱了。
3、babel-plugin-transform-runtime
babel-plugin-transform-runtime 裝了就不需要裝 babel-runtime了,因為前者依賴后者。
總的來說,babel-plugin-transform-runtime 就是可以在我們使用新 API 時 自動 importbabel-runtime 里面的 polyfill,具體插件做了以下三件事情:
1) 當我們使用 async/await 時,自動引入 babel-runtime/regenerator;
2) 當我們使用 ES6 的靜態事件或內置對象時,自動引入 babel-runtime/core-js;
3) 移除內聯 babel helpers 并替換使用 babel-runtime/helpers 來替換;
babel-plugin-transform-runtime 優點:
1) 不會污染全局變量;
2) 多次使用只會打包一次;
3) 依賴統一按需引入,無重復引入,無多余引入;
4) 避免 babel 編譯的工具函數在每個模塊里重復出現,減小庫和工具包的體積;
使用方式
在 .babelrc 中配置:
- plugins:\["tranform-runtime"\]
打包后大小為 17.4kb,比之前的280kb要小很多。
gulp打包報錯 - 問題分析與解決方案
頁面 是用gulp起的服務,然后寫的代碼,這次是在js里用了es7的async/await,導致打包完之后報錯:
Uncaught ReferenceError: regeneratorRuntime is not defined
一、原因分析(regeneratorRuntime函數)
在程序中使用了 async/await ,經過@babel/preset-env 解析后會將代碼轉換為一個名為regeneratorRuntime的函數,但是轉換后的代碼僅僅存在這個函數的調用,并沒有具體的定義體現。
通過百度,好多人會告訴你讓你去裝一個叫做
- 'transform-runtime'
transform-runtime插件是運行在node服務器上的,所以即使你裝了,瀏覽器照樣不認識。
二、解決方案(babel-polyfill編譯)
需要的在gulp-babel給你編譯的時候,把regeneratorRuntime再轉換一次,這就用到了babel的babel-polyfill。
安裝完成以后,在node_modules里邊找到這個包,然后把dist下的polyfill.min.js這個js引入到頁面的head里邊去,這樣再一次打包的時候,_asyncToGenerator 這個東西就會返回一個函數了,函數瀏覽器是認識的,再運行一下項目就沒問題了。