Webpack & Babel学习

Webpack & Babel学习

初始化


mkdir webpack-study && cd webpack-study    //创建并进入项目文件夹

Babel

概念

Babel 是一个 JavaScript 编译器,主要用于把 ECMAScript 2015+ 版本语法的代码转换为 ECMAScript 5 及以下版本的语法,以便运行在当前和旧版本浏览器或其他环境中(node)

一般编译器编译过程分为 4 个阶段输入、解析、转换和输出。Babel 本身不参与解析和转换阶段,这两个阶段需要 Plugins(插件)Presets(预设)来实现

Plugins(插件) 用来告诉 babel 如何解析/转换代码。Presets(预设)用来告诉 babel 转换代码时要使用那些新语法特性,它的本质就是一组 Plugin的集合。

Babel 插件分为两类:

  • 转换插件
  • 语法插件
    解析(parse)为特定类型的语法

plugins/presets 路径
如果插件用 npm 安装,那可以直接写插件的名称,babel 会自动检查 node_modules 目录里是否安装

{
    "plugins":["babel-plugin-myPlugin"]
}

也可以指定插件的相对/绝对路径

{
  "plugins": ["./myPlugin"]
}

还可以使用短名称

{
  "plugins": [
    "myPlugin",
    "babel-plugin-myPlugin", // 两个插件实际是同一个
    "@org/babel-plugin-name",
    "@org/name" // 两个插件实际是同一个
  ]
}

plugins/presets 执行顺序:
插件执行的顺序是按照书写顺序依次执行的

  • Plugin(插件)在 Presets 前运行
  • Plugin(插件)顺序从前往后
  • Preset 顺序是颠倒的(从后往前)
{
  "plugins": ["transform-decorators-legacy", "transform-class-properties"]
}

如上所示,先执行 transform-decorators-legacy,再执行 transform-class-properties
presets的顺序是颠倒的

{
  "presets": ["es2015", "react", "stage-2"]
}

先执行 stage-2react然后是 es2015

插件参数:
插件参数由插件名和参数对象组成一个数组,可以在配置文件(.babelrc/babel.config.js)中设置

如果不指定参数,下面这几种形式都是一样的:

{
  "plugins": ["pluginA", ["pluginA"], ["pluginA", {}]]
}

如果指定参数,则传递一个对象

{
  "plugins": [
    [
      "transform-async-to-module-method",
      {
        "module": "blubird"
      }
    ]
  ],
  "presets": [
    [
      "env",
      {
        "modules": false
      }
    ]
  ]
}

安装 Babel

npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill
# 可选
npm install --save @babel/runtime
npm install --save-dev @babel/plugin-transform-runtime
  • @babel/core
    babel 的核心,必选
  • @babel/cli
    babel 命令行工具,执行 babel 编译
  • @babel/preset-env
    官方用于转换 ECMAScript 2015+语法的插件集合,可根据配置来按需加载插件 (向下支持维度)
  • @babel/polyfill
    官方用来创建一个当前和旧版本浏览器能支持 ECMAScript 2015+语法的环境,比如让 IE8 支持Promise。(向上支持维度)
  • @babel/runtime 和 @babel/plugin-transform-runtime
    有时候语法的转换相对复杂,可能会需要额外的辅助函数,比如转换 ECMA 2015 的class
/* 源文件 */
class Person {}

/* 编译后文件 */
function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var Person = function Person() {
  _classCallCheck(this, Person);
};

上面的转换需要一个_classCallCheck 辅助函数,试想假如我们多个文件中使用了class,那么每个文件都需要定义一遍
_classCallCheck 函数,这样不止代码冗余,也会增加文件大小。假如将这些辅助函数抽离到一个包当中,由所有文件共同引用那该多好,而 @babel/runtime 就是做这件事的。
我们已经知道 @babel/runtime 提供了各式各样的辅助函数,但是我们如何知道该引用那个辅助函数呢? Babel 提供了@babel/plugin-transform-runtime插件帮我们做这件事情
同时@babel/plugin-transform-runtime插件还为我们提供了一个沙箱环境(sandboxed environment),创建一个自己的内部作用域,防止污染全局变量,这在编写一些类库等公共设施代码的时候尤为重要。
需要注意的是:
1、两个包引入的范围不一样:一个在运行时引入,一个在开发时引入
2、plugin-transform-runtime 已经默认包括了 @babel/polyfill,因此不用在独立引入。

Babel 配置

Babel的配置文件有两种格式 .babelrcbabel.config.js
.babelrcbable.config.js 区别是 babel.config.js 通过编程的方式来创建配置的,.babelrc就是一个配置文件, 相比 bable.config.js来说是静态的
推荐使用 babel.config.js 来配置 Babel

  • @babel/preset-env
    指定运行环境,只有 IE8 及以上版本浏览器不支持的让ECMAScript 2015+语法才会被转换
{
  "presets": [
    "@babel/preset-env",
    {
      "targets": {
        "browsers": "ie >= 8"
      },
      "modules": false // 将ES 2015模块转换为其他模块规范,可选 "amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false 默认是 "auto"
    }
  ]
}
  • @babel/polyfill
    按需 polyfill 用useBuiltIns配置项来实现。
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "useBuiltIns": "entry",
        "targets": {
          "browsers": "ie >= 8"
        }
      }
    ]
  ]
}

useBuiltIns的值可以是entryusage
entry:会在入口处把所有 IE8 及以上浏览器不支持 ECMAScript 2015 的特性 polyfill 引入进来。
usage:会扫描要转换的代码,只有代码中用到哪个新特性,它才会引入响应的 polyfill

  • @babel/runtime 和 @babel/plugin-transform-runtime
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "targets": {
          "browsers": "ie >= 8"
        }
      }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": 2
      }
    ]
  ]
}

注意:
上面corejs的值可以设置为false2。为什么这样?
大家都知道 corejs 是给低版本浏览器提供接口的库,如 Promise,map,set 等。在 Babel 中你设置为 false 或者不设置,就是引入 corjs 中的库,而且是全局引入,会污染全局变量。如果不想全局引入,不要让引入的库影响全局,那就需要把 corejs 的值设为 2
还要注意一点,如果 corejs 值设为 2,那就需要再引入一个库

npm install --save core-js@2
npm install --save-dev @babel/runtime-corejs2

执行 Babel 编译命令

npx babel 源文件路径 --out-dir 编译后文件路径

webpack

概念

webpack 是一个 JavaScript 应用程序的静态模块打包器(module bundler)。
当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

entry(入口)

entry 指示 webpack 应该使用哪个模块来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点的依赖(直接和间接)。每个依赖项随机被处理,最后输出到称之为 bundules 的文件中
入口点可以有一个或多个,默认值为 ./src

output(出口)

output 指示 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist
注意,即使有多个 entry ,但只能有一个 output

loader(加载器)

loader 使 webpack 拥有处理那些非 JavaScript 文件的能力。loader 可以将所有类型的文件转换为 webpack 能够处理的模块,然后你就可以在 webpack 中处理这些模块

plugins(插件)

loader 被用于转换某些类型的模块,而 plugins 则可以用于执行范围更广的任务

mode(模式)

模式有两种,developmentproduction

modules(模块)
substitutions(文件名占位符)

安装 webpack


npm install --save-dev webpack
npm install --save-dev webpack-cli    //webpack命令行工具

webpack 配置

webpack 通过 webpack.config.js 文件来进行配置

// webpack。config.js

module.exports = {};
entry 配置

entry 的值可以接受字符串、对象、字符串数组
当值为字符串或对象(只有一个 key)或字符串数组时表示单个入口,如下所示

// 字符串
module.exports = {
  entry: "./src/index.js",
};
// 对象
module.exports = {
  entry: {
    main: "./scr/index.js",
  },
};
// 字符串数组
module.exports = {
  entry: ["./src/polyfill.js", "./src/index.js"],
};

entry 值为数组表示数组中的文件一般是没有相互依赖关系的,但是又处于某些原因需要将它们打包在一起,如上面的 polyfill.jsindex.js 会打包到一起

多个入口

实现多个入口配置只需要让 entry 属性值为对象就行了,一般会有两个应用场景

  1. 分离应用(app)和第三方库
module.exports = {
  entry: {
    app: "./src/index.js",
    vendors: "./scr/lib/jquery.js",
  },
};

分离第三方库不推荐上面的方法,可以使用 webpack 的 DllPlugin 插件

  1. 多页面应用(app)
module.exports = {
    entry:{
        pageOne:'./src/pageOne/index.js',
        pageTwo:'./src/pageTwo/index.js'.
        pageThree:'./src/pageThree/index.js'
    }
}
output 配置

output 的值是一个对象,里面有

未完待续……

Babel 与 webpack 结合

npm install babel-loader  -D

未完待续……

上一篇:babel配置文件加载顺序


下一篇:ECMAScript6的历史和前景展望