Skip to content

babel 相关的一些配置 #18

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

Open
wlsyne opened this issue Jul 25, 2022 · 0 comments
Open

babel 相关的一些配置 #18

wlsyne opened this issue Jul 25, 2022 · 0 comments

Comments

@wlsyne
Copy link
Owner

wlsyne commented Jul 25, 2022

babel 相关的一些配置

@babel/preset-env

@babel/preset-env is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s). This both makes your life easier and JavaScript bundles smaller!

  • 转换所有语法至 ES5
  • 根据 environment 打上 polyfill

targets

简单讲,该参数决定了我们项目需要适配到的环境,比如可以申明适配到的浏览器版本,这样 babel 会根据浏览器的支持情况自动引入所需要的 polyfill

通常情况下我们会使用.browserslistrc来声明需要适配的浏览器版本

useBuiltIns

这个 option 用来配置@babel/preset-env 如何来处理 polyfills 的引入

false

默认值
不会引入 polyfill,你需要再文件入口处显示的引入@babel/polyfill,但是这种方式在[email protected]后被废弃了,官方推荐使用 core-js 配合 corejs 选项来使用 polyfill

entry

在入口文件处引入 corejs,babel 会根据 targets 或者 browserslistrc 来引入所有的需要的 corejs 的 polyfill

import 'core-js';
import "core-js/modules/es.symbol.js";
import "core-js/modules/es.symbol.description.js";
import "core-js/modules/es.symbol.async-iterator.js";
import "core-js/modules/es.symbol.has-instance.js";
import "core-js/modules/es.symbol.is-concat-spreadable.js";
import "core-js/modules/es.symbol.iterator.js";
import "core-js/modules/es.symbol.match.js";
import "core-js/modules/es.symbol.replace.js";
import "core-js/modules/es.symbol.search.js";

......

上面这种情况import 'core-js',会引入所有的 polyfill(不管你有没有使用),当然你也可以根据自己的需要单独引入一些 corejs 的 polyfill

import 'core-js/stable/promise';
import 'core-js/modules/es.object.to-string.js';
import 'core-js/modules/es.promise.js';
import 'core-js/modules/es.promise.finally.js';
import 'core-js/modules/es.string.iterator.js';
import 'core-js/modules/web.dom-collections.iterator.js';

usage

针对文件使用的 API 和 target 或者 browserslistrc 来注入 polyfill

const pro = () => {
  return new Promise((resolve, reject) => {
    resolve(222);
  });
};

const test = async () => {
  const a = await pro();
  console.log(a);
};

test();
import 'regenerator-runtime/runtime.js';

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);
    var value = info.value;
  } catch (error) {
    reject(error);
    return;
  }
  if (info.done) {
    resolve(value);
  } else {
    Promise.resolve(value).then(_next, _throw);
  }
}

function _asyncToGenerator(fn) {
  return function () {
    var self = this,
      args = arguments;
    return new Promise(function (resolve, reject) {
      var gen = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
      }
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
      }
      _next(undefined);
    });
  };
}

import 'core-js/modules/es.object.to-string.js';
import 'core-js/modules/es.promise.js';

var pro = function pro() {
  return new Promise(function (resolve, reject) {
    resolve(222);
  });
};

var test = /*#__PURE__*/ (function () {
  var _ref = _asyncToGenerator(
    /*#__PURE__*/ regeneratorRuntime.mark(function _callee() {
      var a;
      return regeneratorRuntime.wrap(function _callee$(_context) {
        while (1) {
          switch ((_context.prev = _context.next)) {
            case 0:
              _context.next = 2;
              return pro();

            case 2:
              a = _context.sent;
              console.log(a);

            case 4:
            case 'end':
              return _context.stop();
          }
        }
      }, _callee);
    }),
  );

  return function test() {
    return _ref.apply(this, arguments);
  };
})();

test();

corejs

支持两种配置方法

{
  "corejs": "version",
  "corejs": {
    "version": "string",
    "proposals": "boolean"
  }
}

默认情况下,只会为 stable 的 ECMAScript 打上 polyfill,如果需要为 proposals 阶段的 api 打上 polyfill 则需要配置 proposals 为 true,corejs-api
对于 useBuiltIns 的值为 entry 的情况下,可以手动引入 proposals 的 corejs,针对 useBuiltIns 的值为 usage 的情况将 proposals 配置为 true 即可

console.log(globalThis);

proposals 为 true

import 'core-js/modules/esnext.global-this.js';
console.log(globalThis);

proposals 为 false

console.log(globalThis);

总结一下@babel/preset-env 的配置

  • 通过@babel/preset-env 引入的 polyfill 会污染全局环境,因为是在入口处引入的
  • 如果要使用@babel/preset-env 引入的 polyfill,可以使用useBuiltIns:usage,来减轻引入的 polyfill 的体积
  • 如果使用 webpack,需要 tree-shaking 的话需要将 module 配置为 false,避免 babel 生成 commonjs 的文件导致 tree-shaking 失效

@babel/preset-react

runtime

当开启时会引入工具函数,有两个值classicautomatic,默认值为 classic

classic

render(
  /*#__PURE__*/ React.createElement(App, null),
  document.getElementById('app'),
);

automatic

import { jsx as _jsx } from 'react/jsx-runtime';
render(/*#__PURE__*/ _jsx(App, {}), document.getElementById('app'));

通篇看了一下文档,感觉用默认配置就行了

@babel/plugin-transform-runtime

A plugin that enables the re-use of Babel's injected helper code to save on codesize

可以解决什么问题

  • 用以解决 helper 函数的注入问题,所有直接注入的 helper 函数都将改为对@babel/runtime 的引用
  • 使用@babel/preset-env注入的 polyfill 会污染全局环境,在开发 web 应用时无伤大雅,但是在开发第三方库时,却有可能污染使用方的全局环境,配置@babel/plugin-transform-runtime 的 corejs 这个 option 后,会将 corejs 的 polyfill 替换为具有作用域的 polyfill
const pro = () => {
  return new Promise((resolve, reject) => {
    resolve(111);
  });
};

const test = async () => {
  const a = await pro();
};

当未使用@babel/plugin-transform-runtime 时

import 'core-js/modules/es.object.to-string.js';
import 'core-js/modules/es.promise.js';
import 'regenerator-runtime/runtime.js';

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
......
}

function _asyncToGenerator(fn) {
......
}

......

当使用@babel/plugin-transform-runtime 时

import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _regeneratorRuntime from "@babel/runtime/regenerator";
import "core-js/modules/es.object.to-string.js";
import "core-js/modules/es.promise.js";

......

corejs

配置是否开启 polyfill

  • 值为 false,需要安装依赖npm install --save @babel/runtime
  • 值为 2,需要安装依赖npm install --save @babel/runtime-corejs2
  • 值为 3,需要安装依赖npm install --save @babel/runtime-corejs3

未配置 corejs

import _asyncToGenerator from '@babel/runtime/helpers/asyncToGenerator';
import _regeneratorRuntime from '@babel/runtime/regenerator';
import 'core-js/modules/es.object.to-string.js';
import 'core-js/modules/es.promise.js';

配置 corejs

import _asyncToGenerator from '@babel/runtime-corejs3/helpers/asyncToGenerator';
import _regeneratorRuntime from '@babel/runtime-corejs3/regenerator';
import _Promise from '@babel/runtime-corejs3/core-js-stable/promise';
// @babel/runtime-corejs3/helpers/asyncToGenerator
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  ......
}

function _asyncToGenerator(fn) {
  ......
}

module.exports = _asyncToGenerator;

// @babel/runtime/regenerator
module.exports = require("regenerator-runtime");

可以看出使用了@babel/plugin-transform-runtime 时

  • 会将 helper 的 inject 转为引入 helper,有效的减少了包的体积
  • 如果使用了 corejs 配置,那么会使用@babel/runtime-corejs 中的 polyfill,而不是使用 preset-env 中的 corejs 的 polyfill
  • @babel/runtime-corejs 中的 polyfill 创建沙盒环境不会污染全局环境,但是体积更大

babel-plugin-react-css-modules

在编译阶段将 react 中的 styleName 属性替换为 className

当我们在 react 中使用 css-modules 时有如下问题

  • 使用时使用驼峰命名<div className={Styles.appTitle}/>或者<div className={Styles["app_title"]}/>
  • 必须使用 Styles 这个对象
  • 使用全局 css 和 css-modules 很繁琐,<div className={\globalcls\ ${{Styles.appTitle}}}/>
  • 当引用一个未定义的类名返回 undefined 而不是报错

使用 babel-plugin-react-css-modules 就解决了这个问题<div className='global-css' styleName='local-module'></div>

支持 less

安装 postcss-less 后增加配置,postcss-less 只是用来支持 less 语法而不会将 less 编译为 css,编译的工作还是会交给 less-loader 来做

{
  "filetypes": {
    ".less": {
      "syntax": "postcss-less"
    }
  }
}

generateScopedName

用以生成 css-modules 的 ident 标识,如果使用了这个字段,则需要配置相应的 css-loader 的 option 以保证 css-loader 生成的 ident 标识和 babel-plugin-react-css-modules 生成的 ident 标识保持一致

  • babel-plugin-react-css-modules 生成 ident 是交给 postcss-modules 来处理的,而 postcss-modules 使用的是generic-names来生成标识
  • 而 css-loader 使用的是自己的 function 来生成 ident
  • 所以在 css-loader 中需要配置 getLocalIdent 来解决生成 ident 的方法不统一的问题

详情请查看这个issue

autoResolveMultipleImports

如果 styleName 使用的类名是非重复的的则允许多个匿名引入,默认是 false

当开启这个配置

import './styles/app.less';
import './styles/app2.less';

export interface AppProps {}

const App: React.FC<AppProps> = () => {
  return (
    <div>
      <h1 className="title" styleName="app_title">
        Hello! It's Alan
      </h1>
    </div>
  );
};

export { App };

当 app.less 和 app2.less 没有同时包含app_title这个类名时不会报错,而当同时包含时则会报错

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant