webpack - babel 篇

前言

基於個人上篇文章,webpack4.0 入門篇 - 構建前端開發的基本環境,補充對babel進行的一次探究。上篇文章講敘到的 webpack babel 時幾乎一筆帶過,因此這篇文章將進行補充說明.前端

Babel 是一個讓咱們可以使用 ES 新特性的 JS 編譯工具,咱們能夠在 webpack 中配置 Babel,以便使用 ES六、ES7 標準來編寫 JS 代碼。node

本文以當前最新版本的 babel - 7.10 爲例, 作 babel 的配置. 相關版本號以下webpack

{
  "devDependencies": {
    "@babel/core": "^7.1.6",
    "@babel/plugin-proposal-decorators": "^7.1.6",
    "@babel/plugin-transform-runtime": "^7.1.0",
    "@babel/preset-env": "^7.1.6",
    "@babel/runtime": "^7.1.5",
    "babel-loader": "^8.0.4",
    "webpack": "^4.26.1",
    "webpack-cli": "^3.1.2"
  }
}
複製代碼

babel-loader 和 @babel/core

創建基本的 webpack 配置文件git

mkdir webpack-babel => cd  webpack-babel => yarn init -y  // 初始化
npm i yarn -g // 安裝了yarn能夠忽略
yarn add webpack webpack-cli -D

// package.json 中添加:
"scripts": {
  "start": "webpack --mode development",
  "build": "webpack --mode production"
}

yarn add babel-loader @babel/core -D
複製代碼
  • yarn : 和 npm 幾乎同樣,本文使用 yarn 安裝...
  • babel-loader: 轉義 js 文件代碼的 loader
  • @babel/core:babel 核心庫

根目錄下添加 webpack.config.jses6

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[hash:8].js'
  },
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: { loader: 'babel-loader' } // options 在 .babelrc 定義
      }
    ]
  }
}
複製代碼

src/index.jsgithub

const func = () => {
  console.log('hello webpack')
}
func()

class User {
  constructor() {
    console.log('new User')
  }
}

const user = new User()
複製代碼

執行 yarn build 後就能夠打包成功,打包後的代碼是壓縮後的。而 yarn start 後的代碼是未壓縮的。爲了使代碼可讀性高一點,咱們能夠在webpack.config.js添加:web

module.exports = {
  //...
  devtool: true
}
複製代碼

@babel-preset-env

打包後咱們能夠發現箭頭函數並未轉化爲 ES5 語法!npm

查閱 babel plugins 文檔,若是要轉義箭頭函數,須要使用到 @babel/plugin-transform-arrow-functions 這個插件 同理轉義 class 須要使用 @babel/plugin-transform-classesjson

yarn add @babel/plugin-transform-arrow-functions @babel/plugin-transform-classes -D
複製代碼

根目錄下創建 .babelrc 文件:promise

{
  "plugins": [
    "@babel/plugin-transform-arrow-functions",
    "@babel/plugin-transform-classes"
  ]
}
複製代碼

yarn build 以後能夠看出 箭頭函數和類都被轉義了。

可是假如你再使用 async await 之類的 es6 語法,你還得一個個添加,這是不實際的。

@babel-preset-env 就整合了這些語法轉義插件:

Using plugins:
transform-template-literals {}
transform-literals {}
transform-function-name {}
transform-arrow-functions {}
transform-block-scoped-functions {}
transform-classes {}
transform-object-super {}
//...
複製代碼

使用以下:

yarn add @babel-preset-env -D
複製代碼

.babelrc

{
  "presets": ["@babel/preset-env"]
}
複製代碼

@babel/polyfill

Babel 默認只轉換新的 JavaScript 句法(syntax),而不轉換新的 API ,好比 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局對象,以及一些定義在全局對象上的方法(好比 Object.assign)都不會轉碼。

這樣就致使了一些新的 API 老版瀏覽器不兼容。如上述所說,對於新的 API,你可能須要引入 @babel-polyfill 來進行兼容

yarn add @babel-polyfill -D
複製代碼

修改 weboack.config.js

module.exports = {
  entry: ['@babel-polyfill', './src/index.js']
}
複製代碼

yarn build 發現文件體積大了不少,由於上面的代碼表示將 @babel-polyfill 的代碼也打包進去了。

固然這不是咱們但願的,如何按需編譯呢? 咱們能夠這麼作:

index.js

import '@babel/polyfill' // 引入

const func = () => {
  console.log('hello webpack')
}
func()

class User {
  constructor() {
    console.log('new User')
  }
}

const user = new User()

new Promise(resolve => console.log('promise'))

Array.from('foo')
複製代碼

還原 webpack.config.js

module.exports = {
  entry: './src/index.js'
}
複製代碼

修改 .babelrc

{
  "presets": [["@babel/preset-env", { "useBuiltIns": "usage" }]]
}
複製代碼

yarn build 後發現咱們的代碼體積就變得很小了!

@babel/runtime 和 @babel/plugin-transform-runtime

  • babel-polyfill 會污染全局做用域, 如引入 Array.prototype.includes 修改了 Array 的原型,除此外還有 String...
  • babel-polyfill 引入新的對象: PromiseWeakMap

這也不是咱們但願出現的。

  • @babel/runtime 的做用:
    • 提取輔助函數。ES6 轉碼時,babel 會須要一些輔助函數,例如 _extend。babel 默認會將這些輔助函數內聯到每個 js 文件裏, babel 提供了 transform-runtime 來將這些輔助函數「搬」到一個單獨的模塊 babel-runtime 中,這樣作能減少項目文件的大小。
    • 提供 polyfill:不會污染全局做用域,可是不支持實例方法如 Array.includes
  • @transform-runtime 的做用:
    • babel-runtime 更像是分散的 polyfill 模塊,須要在各自的模塊裏單獨引入,藉助 transform-runtime 插件來自動化處理這一切,也就是說你不要在文件開頭 import 相關的 polyfill,你只需使用,transform-runtime 會幫你引入。
yarn add  @babel/runtime-corejs2
yarn add @babel/plugin-transform-runtime -D
複製代碼

修改 .babelrc

{
  "presets": ["@babel/preset-env"],
  "plugins": [["@babel/plugin-transform-runtime", { "corejs": 2 }]]
}
複製代碼

index.js 移除 import '@babel/polyfill'

@babel/plugin-proposal-decorators

添加裝飾器模式的支持

yarn add @babel/plugin-proposal-decorators -D
複製代碼

index.js

function annotation(target) {
  target.annotated = true
}

@annotation
class User {
  constructor() {
    console.log('new User')
  }
}
//...
複製代碼

.babelrc

{
  "presets": ["@babel/preset-env"],
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }],
    ["@babel/plugin-transform-runtime", { "corejs": 2 }]
  ]
}

複製代碼

結尾

相關文章