如今JavaScript
代码主要采用ES6
编写,但并非全部浏览器都支持ES6
语法,所以,在其中须要某种转化机制,也就是将ES6+
语法转化为ES5
语法,babel7
能够帮助咱们作到这件事。
babel-loader
是一个webpack
的加载器,用于将ES6+
转译成ES5
,要开始使用babel-loader
,咱们须要安装一些依赖项,以babel7
为例,有这么一些依赖:javascript
下面细说如下这些依赖具备是干什么的:
@babel/core
这是babel编译库的核心包
@babel/preset-env
这个包是指编译时会自动按照最新的转译规则去编译,除了这个包外还有一些规则包,好比babel-preset-es2015
(将es6
的javascript
代码转化浏览器兼容javascript
代码), babel-preset-es2016
(将es7
的javascript
代码转化浏览器兼容javascript
代码), babel-preset-es2017
(将es8
的javascript
代码转化浏览器兼容javascript
代码)等。
@babel/polyfill
接下来咱们继续说babel/polyfill
是个什么东东。babel
官网上写了很明确一句话,babel
只负责对语法进行编译。当咱们写尖头函数,babel
会帮你把它编译成普通函数,这没有任何问题,可是,好比说咱们代码里使用了promise
,babel
打包出来的代码其实仍是promise
,在低版本浏览器里,promise
并不支持,可是babel
并不会帮你处理,由于这不是语法编译层面须要作的事情。不转换新的API
包括,好比Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise
等全局对象。
因而,若是咱们要让打包出来的代码能兼容低版本浏览器,还要考虑到promise,Set
这样的新语法低版本浏览器不兼容的问题,这时候babel/polyfill
就出场了。你只须要全局安装一下babel/polyfill
:java
npm install --save-dev @babel/polyfill
而后在项目中使用一下它,你的代码就不存在刚才提到的兼容性问题了。node
import '@babel/polyfill'
可是,直接用babel-polyfill
会有一些坑,第一个坑是污染全局环境,好比说低版本浏览器没有Set
,可是babel-polyfill
会在全局变量里加一个Set
。再一个问题是,会形成代码冗余,举个例子,多个模块用到Promise
,每一个模块里都有可能独立存在一个对Promise
作兼容性的代码。因此,使用babel-polyfill
能够解决兼容性问题,但并非最佳方案,因而,出现了babel-plugin-transform-runtime
,使用这个插件,就能够解决上面的问题了。webpack
@babel/plugin-transform-runtime
为了避免污染全局对象和内置的对象原型,可是又想体验使用新鲜语法的快感。就能够配合使用babel-runtime
和babel-plugin-transform-runtime
。 好比当前运行环境不支持promise
,能够经过引入babel-runtime/core-js/promise
来获取promise
, 或者经过babel-plugin-transform-runtime
自动重写你的promise
。也许有人会奇怪,为何会有两个runtime
插件,实际上是有历史缘由的:刚开始开始只有babel-runtime
插件,可是用起来很不方便,在代码中直接引入helper
函数,意味着不能共享,形成最终打包出来的文件里有不少重复的helper
代码。因此,Babel
又开发了babel-plugin-transform-runtime
,这个模块会将咱们的代码重写,如将Promise
重写成_Promise
(只是打比方),而后引入_Promise helper
函数。这样就避免了重复打包代码和手动引入模块的痛苦。git
在使用@babel/plugin-transform-runtime
以前须要安装@babel/runtime
,由于前者依赖后者。es6
用了babel-runtime
就能够不用 babel-polyfill
了,连接https://babeljs.io/docs/en/babel-plugin-transform-runtime/有说明github
① 安装依赖web
npm i @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime @babel/polyfill @babel/runtime--save-dev
② 在项目的根目录中建立名为 .babelrc 的新文件来配置 Babel:npm
{ "presets": ["@babel/preset-env"], "plugins": ["@babel/plugin-transform-runtime"] }
③ webpack 配置 loader(加载器)promise
module: { rules: [ { test: /\.js$/, // 使用正则来匹配 js 文件 exclude: /node_modules/, // 排除依赖包文件夹 use: { loader: 'babel-loader' // 使用 babel-loader } } ] }
webpack.config.js 最终配置:
const path = require('path') const { CleanWebpackPlugin } = require('clean-webpack-plugin') module.exports = { entry: './babel7转义ES6.js', output: { path: path.resolve(__dirname, 'build'), filename: 'bundle.js', publicPath: __dirname + '/build/' }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] }, plugins: [ new CleanWebpackPlugin() // 会删除上次构建的文件,而后从新构建 ] }
④ 在 app.js 全局引入 @babel/polyfill 并写入 ES6 语法,并执行 npm run build 打包
// 测试 ES6 语法是否经过 babel 转译 import '@babel/polyfill' const array = [1, 2, 3] const isES6 = () => console.log(...array) isES6() const arr = [new Promise(() => {}), new Promise(() => {})] arr.map(item => { console.log(item) })
全局引入 @babel/polyfill 的这种方式可能会导入代码中不须要的 polyfill,从而使打包体积更大
更改 .babelrc,只转译咱们使用到的
/** * babel配置文件 */ { "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage",// 按需引入 "corejs": "3.3.2" } ] ], "plugins": ["@babel/plugin-transform-runtime"] }
同时,将全局引入这段代码注释掉,再次打包
// 全局引入 // import '@babel/polyfill'
参考文章:
https://zhuanlan.zhihu.com/p/35378233
http://www.javashuo.com/article/p-ambqyqxk-ev.html
https://www.jianshu.com/p/7bc7b0fadfc2
https://github.com/SunshowerC/blog/issues/4