npm 6.14 + Babel 7 使用
Babel github :https://github.com/babel/babel/tree/master/packages
Babel 在线转化:https://www.babeljs.cn/repl
Babel 是干嘛的
用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。下面列出的是 Babel 能为你做的事情:
- 语法转换
- 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块)
- 源码转换 (codemods)
npx
在Babel使用之前先介绍一下npx,因为后面用到npx,注意不是npm
npx是啥
npx是一种在npm中安装工具,也可以被单独的下载使用
在npm 5.2.0 的时候发现会买一送一,自动安装了npx。
也就是说 npm5.2之后,会自动安装
npx是解决什么问题的
再也不需全局安装任何工具只需要npx <commang>
为什么使用npx
全局安装劣势:
-
占用本机空间
npm会在machine上创建一个目录(mac是
/usr/local/lib/node_modules
)存放所有global安装的包, 其实node_module占用的空间比较大的 -
版本问题:
假如一个项目中的某一个dependency是全局安装的,也就意味着不同的开发人员使用的这个dependency版本完全基于本地的版本,也就会导致不同的开发人员使用不同的版本
使用npx的优势也就凸显出来了:
-
当在执行
npx <command>
的时候,npx会做什么事情?
- 帮你在本地(可以是项目中的也可以是本机的)寻找这个 command
- 找到了: 就用本地的版本
- 没找到: 直接下载最新版本,完成命令要求
- 使用完之后不会在你的本机或者项目留下任何东西
- 帮你在本地(可以是项目中的也可以是本机的)寻找这个 command
因此优势总结:
- 不会污染本机
- 永远使用最新版本的dependency
Babel使用
配置Node项目环境
执行
npm init -y
然后项目目录下就会创建一个package.json,如
下载相应的包的命令
npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill
或者简写:
npm install -D @babel/core @babel/cli @babel/preset-env
npm install @babel/polyfill
(--save-dev(简写-D)表示该版本只适用于开发环境中,命令会自动帮你写在package.json的devDependencies中
--save(或者不写)则表示该版本适用于生产环境中,命令会自动帮你写在package.json的dependencies中 )
如:
使用Babel前要下载的包的意义和用法
@babel/core
Babel 的核心功能在 @babel/core模块,如果某些代码需要调用Babel的API进行转码,则就需要此模块。
用法如下
var babel = require('@babel/core');
// 字符串转码
babel.transform('code();', options);
// => { code, map, ast }
// 文件转码(异步)
babel.transformFile('filename.js', options, function(err, result) {
result; // => { code, map, ast }
});
// 文件转码(同步)
babel.transformFileSync('filename.js', options);
// => { code, map, ast }
// Babel AST转码
babel.transformFromAst(ast, code, options);
// => { code, map, ast }
@babel/polyfill
模块包括core-js和自定义regenerator runtime 来模拟完整的 ES2015+ 环境。
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign
)都不会转码。
举例来说,ES6在Array
对象上新增了Array.from
方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill
,为当前环境提供一个垫片
@babel/preset-env
根据你需要支持的环境(配合targets中的浏览器信息)自动决定适合你的 Babel 插件
@babel/cli
@babel/cli是一个允许你从终端使用 babel 的工具。即用于命令行转码
全局安装命令
npm install -D @babel/cli -g
基本用法如下。
# 转码结果输出到标准输出(字符串形式输出)
$ babel example.js
# 转码结果写入一个文件
# --out-file 或 -o 参数指定输出文件
$ babel example.js --out-file compiled.js
# 或者
$ babel example.js -o compiled.js
# 整个目录转码
# --out-dir 或 -d 参数指定输出目录
$ babel src --out-dir lib
# 或者
$ babel src -d lib
# -s 参数生成source map文件
$ babel src -d lib -s
创建配置文件
使用以下内容在项目的根目录中创建名为 babel.config.js 的配置文件:(配置文件很重要)
module.exports = function(api){
api.cache(true)
const presets = [
["@babel/env", {
targets: {
ie:"10",
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
useBuiltIns: "usage"
}]
];
const plugins = [];
return {
presets,
plugins
}
}
//target表示你想要支持的浏览器的最低型号
// useBuiltIns: "usage" ——由于polyfill包很臃肿,Babel 的此设置将检查你的所有代码,以查找目标环境中缺少的功能,并仅包含所需的 polyfill。
开始使用
创建src文件夹,再在里面创建index.js文件,并输入
(x => x * 2)(1)
在命令行中输入
//表示src整个目录转码到dist目录下
npx babel src -d dist
结果如下
可以看到已经被成功编译
es6相关特性编译问题
class 不支持
上面安装了@babel/polyfill
包 编译Promise等全局对对象没问题,但是你会发现class类 这个特性编译不了
如
这是因为还缺少一个插件@babel/plugin-proposal-class-properties
安装
npm install @babel/plugin-proposal-class-properties -D
在配置文件中加入插件配置
const plugins = [
'@babel/plugin-proposal-class-properties'
];
此时的babel.config.js
module.exports = function(api){
api.cache(true)
const presets = [
["@babel/env", {
targets: {
ie:"10",
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
useBuiltIns: "usage"
}]
];
const plugins = [
'@babel/plugin-proposal-class-properties'
];
return {
presets,
plugins
}
}
执行编译
npx babel src -d dist
编译结果
class 编译之后出现 require()
如果你的类比较复杂,如
class A {
constructor() {
console.log('A构造方法');
}
}
class B extends A{
constructor() {
super();
console.log('B构造方法')
}
}
你运行编译命令之后,你会发现,编译完成的文件是这样的
npx babel src -d dist
你会发现居然出现了require(),这不是node的吗,为什么编译之后会出现这个?并且你会发现直接注释掉也可以引入运行,如
找不到require()里面的相关文件
你顺着它引入的文件去模块里面去找,你会发现这些文件你都找不到,这是为什么,怎么解决?
这时候你再用Babel编译一次,你会发现
npx babel src -d dist
编译有个警告
大概意思就是没有指定corejs的版本,就是这个的原因
首先安装corejs
npm install --save core-js@3
然后在配置文件babel.config.js中加入corejs : 3
的设置选项
这时候配置文件是这样的
module.exports = function(api){
api.cache(true)
const presets = [
["@babel/env", {
targets: {
ie:"10",
edge: "17",
firefox: "60",
chrome: "60",
safari: "11.1"
},
useBuiltIns: "usage",
corejs : 3
}]
];
const plugins = [
'@babel/plugin-proposal-class-properties',
];
return {
presets,
plugins
}
}
再次执行Babel编译命令
npx babel src -d dist
没有警告了
再次打开,发现可以找到相关文件了
但是require()还是有,浏览器不可能支持require()。babel 是怎么编译es6的模块的,怎么会出现require()?
其实就一句话:
babel 统一将 js 模块化语法转为 commonJS 风格。
从Babel 6.0开始,不再直接提供浏览器版本,需要配合webpack等构建工具使用。如果你的项目相当简单,并不需要使用构建工具,而你又想在Web项目中使用ES6的语法,Babel+Browserify可以满足你的需求。
安装Browserify
github:https://github.com/browserify/browserify
npm install browserify -D
执行Browserify编译
npx browserify ./dist/testClass.js -o test.js
结果如下
编译是编译完了,还是有require(),但是好像自己实现了,那html页面引入怎么用呢?
看了下生成的结构
这是自调用的闭包,页面直接引入不可能可以调用的,那怎么在html直接引入调用呢?出现这种情况是为什么呢?这是因为
默认情况下,Browserify不允许从浏览器序列化代码之外访问模块。如果要调用浏览器序列化模块中的代码,则应该将代码与模块一起浏览
参考:https://cloud.tencent.com/developer/ask/109752
npx browserify ./dist/testClass.js --standalone Main -o testClass.js
设置导出到全局的模块
来到我们使用Babel编译后的文件
加入模块导出语句
例:
module.exports = B;
执行编译
其实就是将我们导出的模块挂载到window对象下,使我们页面能够直接访问
#npx browserify [Babel编译后的文件路径] --standalone 导出的模块名 -o 导出的文件位置
npx browserify ./dist/testClass.js --standalone B -o testClass.js
页面引入执行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--<script src="./dist/testClass.js"></script>-->
<script src="testClass.js"></script>
</head>
<body>
<script>
console.log(B);
</script>
</body>
</html>
运行结果