前言
我觉得事情不大对,好像我之前几篇,太长了,以后我尽量控制下长度
babel
官网:https://babeljs.io/
中文网(非官方):https://www.babeljs.cn/
babel是一个编译器,可以把不同标准书写的语言,编译为统一的、能被各种浏览器识别的语言
babel转化的方式和postcss差不多,都是本身只提供一些分析的功能,具体的转化依靠的是插件
安装babel
babel可以和构建工具联合使用,也可以独立使用
如果要独立的使用babel,需要安装下面两个库:
- @babel/core:babel核心库,提供了编译所需的所有api
- @babel/cli:提供一个命令行工具,调用核心库的api完成编译
1
| npm install @babel/core @babel/cli -D
|
@babel/cli
提供了一个命令babel
1 2 3 4 5
| # 按文件编译 babel 要编译的文件 -o 编辑结果文件
# 按目录编译 babel 要编译的整个目录 -d 编译结果放置的目录
|
比如说
1
| babel ./src/index.js -o ./src/script/index.js
|
但是现在没有插件,做不了什么,只是原样输出而已
配置文件
babel转化代码要依托于babel插件和babel预设来完成,那我们就需要一个配置文件来告诉babel使用哪些插件和预设,这个配置文件默认是.babelrc
新建.babelrc
1 2 3 4
| { "presets": [], "plugins": [] }
|
babel预设
babel有多种预设,最常见的预设是@babel/preset-env
@babel/preset-env
文档 https://www.babeljs.cn/docs/babel-preset-env#options
@babel/preset-env
可以让你使用最新的JS语法,而无需针对每种语法转换设置具体的插件
安装
1
| npm install @babel/preset-env -D
|
配置
1 2 3 4
| { "presets": ["@babel/preset-env"], "plugins": [] }
|
使用
转化后变成
1 2 3
| "use strict";
var a = Math.pow(3, 4);
|
但是只是这样还有一个问题,那就是现在只会对新语法进行处理,而不对新的API进行处理
比如说Promise是不会进行转化的
如果遇到没有Promise构造函数的旧版本浏览器,该代码就会报错
因此我们要进行一些配置
1 2 3 4 5 6 7 8 9 10
| { "presets": [ ["@babel/preset-env", { "useBuiltIns": "usage", "corejs": 3 } ] ], "plugins": [] }
|
而配置usebuiltins
可以在编译结果中注入这些新的API,它的值默认为false
,表示不注入任何新的API,可以将其设置为usage
,表示根据API的使用情况,按需导入API
重新执行babel
命令
从打包结果看出,我们还需要安装一个corejs
库
安装后就可以运行了
注意,配置usebuiltins
后,即使不安装core-js也可以转化成一样的打包结果,但是不安装core-js就无法运行
顺带一提,如果要转化async和await,需要再安装一个库regenerator-runtime
1
| npm install regenerator-runtime
|
加了后就可以了
另外,@babel/preset-env
需要根据兼容的浏览器范围来确定如何编译,和postcss一样,可以使用文件.browserslistrc
来描述浏览器的兼容范围
1 2 3
| last 3 version > 1% not ie <= 8
|
babel插件
通常情况下,@babel/preset-env
只转换那些已经形成正式标准的语法,对于某些处于早期阶段、还没有确定的语法不做转换。
如果要转换这些语法,就要单独使用插件,下面介绍一些插件
安装
1 2
| cnpm install @babel/plugin-proposal-class-properties @babel/plugin-proposal-function-bind @babel/plu gin-proposal-optional-chaining babel-plugin-transform-remove-console @babel/plugin-transform-runtime
|
1
| cnpm install --save @babel/runtime
|
配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| { "presets": [ ["@babel/preset-env", { "useBuiltIns": "usage", "corejs": 3 }] ], "plugins": [ ["@babel/proposal-class-properties", { "loose": true }], "@babel/proposal-function-bind", "@babel/proposal-optional-chaining", "transform-remove-console", "@babel/transform-runtime" ] }
|
@babel/plugin-proposal-class-properties
该插件可以让你在类中书写初始化字段
1 2 3 4 5 6
| class A { a = 1; constructor(){ this.b = 3; } }
|
@babel/plugin-proposal-function-bind
该插件可以让你轻松的为某个方法绑定this
1 2 3 4 5 6 7 8 9
| function Print() { console.log(this.loginId); }
const obj = { loginId: "abc" };
obj::Print();
|
@babel/plugin-proposal-optional-chaining
支持?.语法
1 2 3 4 5 6 7 8 9 10 11
| const obj = { foo: { bar: { baz: 42, }, }, };
const baz = obj?.foo?.bar?.baz;
const safe = obj?.qux?.baz;
|
babel-plugin-transform-remove-console
该插件会移除源码中的控制台输出语句
1 2
| console.log("foo"); console.error("bar");
|
编译后
@babel/plugin-transform-runtime
用于提供一些公共的API,比如下面的代码
1 2 3 4 5
| class A { constructor(name) { this.name = name; } }
|
转化后
1 2 3 4 5 6 7 8 9 10 11 12
| "use strict";
require("core-js/modules/es.function.name.js");
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var A = function A(name) { _classCallCheck(this, A);
this.name = name; };
|
如果使用了这个库
转化后
1 2 3 4 5 6 7 8 9 10 11 12
| "use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
require("core-js/modules/es.function.name.js");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var A = function A(name) { (0, _classCallCheck2.default)(this, A); this.name = name; };
|
可以看出来,需要的辅助函数都从外部引入了,这样就可以避免一些重复代码,比如如果你有10个类,不使用这个库的话,_classCallCheck这个函数是会重复出现在10个文件里的,就会影响打包后的代码大小
在webpack里使用
安装
1
| npm install --save-dev babel-loader @babel/core
|
如果你是在新项目里使用,必须要安装@babel/core
,因为babel-loader
要调用它
配置一波
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| const path = require("path"); const {CleanWebpackPlugin} = require("clean-webpack-plugin"); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const MiniCssExtractPlugin = require("mini-css-extract-plugin") const webpack = require("webpack"); const cssLoaderConfig = { loader: "css-loader", options: { modules : { localIdentName: "[local]-[hash:5]" } } }; module.exports = { entry: { index: "./index.js" }, mode: "development", output: { path: path.resolve(__dirname, "dist"), filename: "js/[name].[chunkhash:5].js", publicPath: "/" }, devServer: { contentBase: path.resolve(__dirname, 'dist'), port: 9000, open : true, }, context: path.resolve(__dirname, "src"), module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: { loader: "babel-loader" } }, { test: /\.s[ac]ss$/i, use: [ MiniCssExtractPlugin.loader, cssLoaderConfig, "postcss-loader", "sass-loader", ] }, { test: /\.less$/i, use: [ MiniCssExtractPlugin.loader, cssLoaderConfig, "postcss-loader", "less-loader", ] }, { test: /\.p?css$/i, use: [ MiniCssExtractPlugin.loader, cssLoaderConfig, "postcss-loader", ] }, { test: /\.(png)|(gif)|(jpg)$/, use: [{ loader: "url-loader", options: { limit: 10 * 1024, name: "imgs/[name].[contenthash:5].[ext]" } }] }], noParse: /jquery/ }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: "./public/index.html", filename: "html/index.html", chunks: ["index"] }), new CopyWebpackPlugin({ patterns: [ { from: "./assets", to: "./assets" }, ], }), new webpack.ProvidePlugin({ $ : 'jquery' }), new MiniCssExtractPlugin({ filename: "css/[name].[contenthash:5].css" }) ], resolve: { alias: { "@": path.resolve(__dirname, 'src') }}, externals: { jquery : "$" } }
|
好的,这样就可以让babel
处理我们在项目中的js文件了
后记
我没咕咕咕,耶