Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webpack 4 与 Babel/preset-env 升级不完全指南 #14

Open
ch1oechao opened this issue May 6, 2018 · 0 comments
Open

Webpack 4 与 Babel/preset-env 升级不完全指南 #14

ch1oechao opened this issue May 6, 2018 · 0 comments
Labels

Comments

@ch1oechao
Copy link
Owner

根据项目开发经验整理的一些笔记。

使用 @babel/preset-env 而不是 babel-preset-env

最新的 babel/preset-env 换仓库了:@babel/preset-env Github Repo
用法稍有不同,具体看 .babelrc 配置。

安装

npm install @babel/preset-env --save-dev

NPM 安装后,使用版本为 7.0.0-beta.x

配置 .babelrc

{
  "presets": [
    ["@babel/preset-env", {
      "targets": {
        "browsers": ["Android >= 4.0", "ios >= 7"]
      },
      "useBuiltIns": "entry",
      "debug": true,
    }],
  ],
  "plugins": [...],
}
  • presets 设置从原来的 env 换成了 @babel/preset-env,配置目标使用 target 字段配置,包含 ES Modules、Node、Browsers 等。

其中浏览器配置支持 Browserslist 配置,即配置 .browserslistrc 文件。还可以在 package.json 里配置,不过建议单独创建 .browserslistrc,因为一些编译工具如 autoprefixer 也会用到。

  • 此外,useBuiltIns 配置也有考究,默认为 false,可以使用的值有 usageentry

usage 表示明确使用到的 polyfill 引用。在一些 ES2015+ 语法不支持的环境下,每个需要用到 polyfill 的引用时,会自动加上。

原始文件:

// a.js
var a = new Promise();

// b.js
var b = new Map();

根据当前环境是否支持后,编译成:

import "core-js/modules/es6.promise";
var a = new Promise();

import "core-js/modules/es6.map";
var b = new Map();

entry 表示替换 import "@babel/polyfill"; 的全局声明,转换成当前文件下需要使用到的对应 polyfill 语法工具。

原始状态:

import "@babel/polyfill";

根据当前不同环境编译成:

import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";

同样适用于 core-js 的直接引用 (import "core-js"; or require('core-js’);)。

Babel polyfill 与 runtime 的区别

Polyfill 官网介绍如下:

Babel includes a polyfill that includes a custom regenerator runtime and core-js.

This will emulate a full ES2015+ environment and is intended to be used in an application rather than a library/tool. This polyfill is automatically loaded when using babel-node.

This means you can use new built-ins like Promise or WeakMap, static methods like Array.from or Object.assign, instance methods like Array.prototype.includes, and generator functions (provided you use the regenerator plugin). The polyfill adds to the global scope as well as native prototypes like String in order to do this.

取自 Polyfill · Babel

翻译一下:

一些 ES3015+ 的新语法,如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign、Array.from)都需要用 babel-polyfill 进行转译,为当前 [应用开发] 环境铺好路,而不是库或是工具。

Runtime transform 官网介绍如下:

This plugin is recommended in a library/tool.

Babel uses very small helpers for common functions such as _extend. By default this will be added to every file that requires it. This duplication is sometimes unnecessary, especially when your application is spread out over multiple files.

This is where the transform-runtime plugin comes in: all of the helpers will reference the module babel-runtime to avoid duplication across your compiled output. The runtime will be compiled into your build.

Another purpose of this transformer is to create a sandboxed environment for your code. If you use babel-polyfill and the built-ins it provides such as Promise, Set and Map, those will pollute the global scope. While this might be ok for an app or a command line tool, it becomes a problem if your code is a library which you intend to publish for others to use or if you can’t exactly control the environment in which your code will run.

The transformer will alias these built-ins to core-js so you can use them seamlessly without having to require the polyfill.

取自 Runtime transform · Babel

简单翻译一下:

Runtime transform 更适用于 库/脚本 开发,它提供编译模块复用工具函数,将不同文件中用到的辅助函数如 _extend 统一打包在一块,避免重复出现导致的体积变大。另外一个目的是,在 库/脚本工具开发中不需要直接引用 polyfill,因为会造成实际应用开发中,一些全局变量名污染,比如 Promise、Map 等。Runtime 会自动应用 Polyfill,而不需要再单独引用。

当然也可以配置 Runtime 不自动应用 Polyfill,参看自 transform-runtime 会自动应用 polyfill,即便没有使用 babel-polyfill

{
  "plugins": [
    ["transform-runtime", {
      "polyfill": false,
      "regenerator": true
    }]
  ]
}

关于两者的区别更细致的解释可以查看:javascript - babel的polyfill和runtime的区别 - SegmentFault 思否

使用 Browserslist

Browserslist 的目的是在不同的前端工具中,统一浏览器的支持程度,比如 autoprefixer、ESLint、 @babel/preset-env 等等。

GitHub - browserslist/browserslist

.browserslistrc 配置示例如下,可支持不同环境下的配置:

# Browsers that we support

[production staging]
> 1%
last 4 version
Android >= 4.0
iOS >= 7

[development]
> 1%
last 4 version

使用 babel-eslint

babel-eslint 是一款语法验证工具,可以在 ESLint 配置中允许所有有效的 Babel 支持的语法。比如 Decorator 的语法使用,普通的 ESLint 配置验证不会通过,加上 babel-eslint 配置后即可。

.eslintrc 配置如下,可以支持一些实验性质的 ES2015+ 语法:

{
  "parser": "babel-eslint",
  "rules": {
    "strict": 0,
    "no-undef": 0,
    "no-unused-vars": 0
  }
}

使用插件

Decorator 语法

想要在应用中使用 Decorator,需要使用到 Babel 插件:babel-plugin-transform-decorators-legacy,安装后,在 .babelrc 中配置即可。PS. 如果项目中使用了 ESLint 还要加上 babel-eslint 配置,才能编译通过。

{
  "presets": [...],
  "plugins": [
    "transform-decorators-legacy",
  ]
}

Async / Await 语法

尝试过 Babel 自带的 Runtime-Transform 进行编译,不过编译后的问题体积巨大,打包了很多不需要的代码。最终找到了 Facebook 出的 regenerator-runtime 工具。

文档介绍说

Standalone runtime for Regenerator-compiled generator and async functions.

也就是这个工具专门为转义 Async funtion 语法而生,大大减少了编译后的体积,很赞~ 另外引用也非常简单,只要在应用的入口文件中加入引用即可:

import 'regenerator-runtime/runtime';

Sass 与 CSS Module 混搭

  • 将 Sass 版本升级至最新版,目前使用 1.0.0-beta.x ( 版本太低的话会导致 CSS Modules 开启无效,躺过坑…
  • 使用 extract-text-webpack-plugin 单独打包 CSS
  • 使用 css-loader 配置 modules: true 开启 CSS Modules
  • 使用 postcss-loader 中的插件 autoprefixer 处理前缀,解决兼容性问题
  • autoprefixer 的浏览器支持程度配置,同样取自 .browserslistrc

Webpack 的样式配置举例如下:

{
  test: /\.(sass|scss)$/,
  use: ExtractTextPlugin.extract({
    fallback: 'style-loader',
    use: [{
        loader: 'css-loader',
        options: {
          camelCase: true,
          modules: true,
        },
      },
      {
        loader: 'postcss-loader',
        options: {
          sourceMap: true,
          plugins: () => [autoprefixer()],
        },
      },
      {
        loader: 'sass-loader',
      }
    ],
  }),
},

Webpack 4 升级

在项目升级中,遇到的明显的两个变化是:

  • mode 是 webpack 4 中新增加的参数选项,不可缺省,需要二选一:production 和 development
  • 如果要使用 webpack cli 命令,需要单独再安装 webpack-cli

其余的变化因为项目配置需要有限,因此没有太多体验。更详细的升级指南可以查看 Webpack 4 不完全迁移指北

END.

@ch1oechao ch1oechao changed the title Webpack 与 Babel 升级不完全指南 Webpack 4 与 Babel/preset-env 升级不完全指南 May 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant