babel-loader 使用指南

莫得鹽發表於2019-05-28

本指南基於 babel 7

安裝

yarn add babel-loader @babel/core -D
複製程式碼

使用

{
  test: /\.js$/,
  loader: 'babel-loader',
  include: [
    path.resolve(__dirname, '../src')
  ]
}
複製程式碼

該配置指明瞭使用 babel 翻譯 js 檔案,但僅是這樣 babel 並不知道該如何翻譯、翻譯什麼,要讓它正真工作起來,還需要其他外掛支援。

預設

上文說到我們需要使用一些外掛,但搜尋和選擇外掛是一個很浪費時間的事,為了在短時間內解決問題,我們就需要使用預設

預設就是指外掛(及其配置)組成的陣列,它可以包含外掛和其他預設,例如:

yourPreset.js

module.exports = function() {
  return {
    presets: [
      require('@babel/preset-env'),
    ],
    plugins: [
      require('pluginA'),
      require('pluginB')
    ]
  }
}
複製程式碼

babel 提供幾個官方預設供使用者使用,這裡舉例講解最常用的 @babel/preset-env,除此之外還有:

@babel/preset-env 會根據你的環境配置,把 ES6+ 程式碼翻譯成環境能支援的 ES5 程式碼,所以我們只需要配置專案的目標環境,就能放心地使用新語法特性。

  1. 安裝

    yarn add @babel/preset-env -D
    複製程式碼
  2. 配置

    {
      test: /\.js$/,
      loader: 'babel-loader',
      include: [
        path.resolve(__dirname, '../src')
      ],
      // +++
      options: {
        presets: [
          [
            '@babel/preset-env',
            {
              targets: {
                chrome: '51',
                ie: '9'
              },
              modules: false,
              useBuiltIns: 'entry',
              corejs: 2
            }
          ]
        ]
      }
      // +++
    }
    複製程式碼

    useBuiltIns 值不為 false 時需要指明 corejs 版本,否則會有警告(雖然有預設值 2)

    corejs: 2 表示使用 @babel/preset-env/lib/polyfills/corejs2 來翻譯 / 填充程式碼

useBuiltIns 選項說明:

  • false 預設值,babel 不自動匯入 polyfill ,你需要手動在專案全域性環境中匯入
    • 缺點:每個語法都去找其對應的 polyfill 很麻煩,直接 import babel-polyfill 時同 useBuiltIns: entry
  • entry 需要你在入口檔案 import @babel/polyfill',它會依據環境設定,僅匯入環境不支援的 polyfill
    • 優點:只匯入環境不支援的 polyfill
    • 缺點:需要手動匯入 @babel/polyfill
  • usage 當每個檔案裡用到需要 polyfill 的特性時,在檔案中新增對應的 polyfill ,可以保證每個 polyfill 只 load 一次,縮小生產包體積
    • 優點:只匯入需要的 polyfill 並且是自動匯入
    • 缺點:實驗中的屬性

@babel/preset-env 使用起來非常方便,但遺憾的是它並不能覆蓋所有開發場景,因為它存在兩個缺點:

  • 重複填充: @babel/preset-env 會填充每一個檔案,所以 a.js / b.js 如果同時用到了 Promise,那麼翻譯後兩個檔案均存在 Promise 的填充
  • 全域性汙染: @babel/preset-env 會將 Promise 翻譯成全域性變數 var _Promise

如果你打包生成的是公共庫,就不能僅僅使用 @babel/preset-env,因為你不能控制這個包的使用環境,對全域性變數的汙染或許會製造一些問題。

transform-runtime

以上兩個問題我們可以藉助外掛 @babel/plugin-transform-runtime 來解決

This is where the @babel/plugin-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.

  1. 安裝
    yarn add @babel/plugin-transform-runtime -D // 開發依賴
    yarn add @babel/runtime-corejs2 // 生產依賴
    複製程式碼
  2. 配置
    {
      test: /\.js$/,
      loader: 'babel-loader',
      include: [
        path.resolve(__dirname, '../src')
      ],
      // +++
      options: {
        plugins: [
          [
            '@babel/plugin-transform-runtime',
            {
              'corejs': 2,
              'absoluteRuntime': false,
              'helpers': true,
              'regenerator': true,
              'useESModules': false
            }
          ]
        ]
      }
      // +++
    }
    複製程式碼
    'corejs': 2 表示使用 @babel/runtime-corejs2 來翻譯 / 填充程式碼,預設 false 表示自己引入 polyfill

需要注意的是, @babel/plugin-transform-runtime 由於其不汙染全域性變數的特性,無法翻譯物件的例項方法,比如 Array.includes / Array.from

如何選擇

如果專案是公共庫,使用 @babel/plugin-transform-runtime ,否則使用 @babel/preset-env

常用配置

yarn add babel-loader @babel/core @babel/preset-env @babel/plugin-syntax-dynamic-import -D
複製程式碼

在 .babelrc 中配置

.babelrc 放在專案根目錄

{
  test: /\.js$/,
  loader: 'babel-loader',
  include: [
    path.resolve(__dirname, '../src')
  ],
  options: {
    cacheDirectory: true
  }
}
複製程式碼

.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "useBuiltIns": "usage",
        "targets": {
          "chrome": "58"
        },
        "corejs": 2
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-syntax-dynamic-import"
  ]
}
複製程式碼

在 JS 中配置

yarn add babel-loader @babel/core @babel/plugin-transform-runtime @babel/plugin-syntax-dynamic-import -D
yarn add @babel/runtime-corejs2
複製程式碼
{
  test: /\.js$/,
  loader: 'babel-loader',
  include: [
    path.resolve(__dirname, '../src')
  ],
  options: {
    cacheDirectory: true,
    presets: [
      [
        '@babel/preset-env',
        {
          modules: false,
          useBuiltIns: 'usage',
          targets: {
            chrome: '58'
          },
          corejs: 2
        }
      ]
    ],
    plugins: [
      '@babel/plugin-syntax-dynamic-import'
    ]
  }
}
複製程式碼

參考文件