史上最簡單的Babel入門教程

史上最簡單的Babel入門教程

在學習 Babel 之前,只知道它是一個 JS 編譯器,大概的功能就是幫助我們在舊的瀏覽器環境中將 ES6+ 的代碼轉換爲兼容低版本的 JS 代碼。但是,它是通過什麼實現的,具體是怎樣實現的就沒有深入瞭解了。

廢話不多說,直接進入主題。本文通過一個案例來打開 Babel 這個技能,所以先要準備一個小項目。

mkdir babel-basic && cd babel-basic
npm init -y
mkdir src && cd src
touch index.js

一頓操作以後,我們新建的項目目錄爲:

/babel-basic
 |- /src
   |- index.js
 |- package.json

然而,package.json 是最原始的配置,而 index.js 暫時沒有代碼:

{
  "name": "babel-basic",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {}
}

@babel/core

學習 Babel,首先要了解一個叫 @babel/core 的東西,它是 Babel 的核心模塊,所以首先要安裝:

npm i --save-dev @babel/core

安裝成功之後就可以在我們的代碼中使用了, 你可以採用CommonJS 的引用方式:

const babel = require('@babel/core');
babel.transform("code", options);

這裏的知識點有很多, 不過你不用急於的掌握它, 只需要知道它是Babel 的核心, 讓我們接着往下看。

@babel/cli

這是一個終端運行工具,內置的插件,運行你從終端使用 babel 的工具。同樣也需要安裝:

npm i --save-dev @babel/cli

接着,在 src/index.js 中寫一段簡單代碼:

const fn = () => 1; // 箭頭函數, 返回值爲1
console.log(fn());

用法一:命令行的形式

babel src --out-dir lib

這行代碼的意思是:它使用我們設置的解析方式來解釋 src 目錄下的所有 js 文件,並將轉換後的每個文件都輸出到 lib 目錄下。

但是,到目前爲止我們並沒有設置任何的解析方式,所以在執行這行代碼後,能看到項目中多了一個 lib 目錄,裏面的代碼和 src 目錄中的是一致的。至於如何設置解析方式,就涉及到後面講的 pluginspresets 了。

另外,還可以通過 npx babel src --out-dir lib 來代替上面的命令,兩者的結果是一致的。

用法二:給 package.json 中配置命令:

{
    "name": "babel-basic",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
+       "build": "babel src -d lib"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
+       "@babel/cli": "^7.8.4",
+       "@babel/core": "^7.8.4"
    }
}

運行 npm run build 效果也是一致的。上面的 -d--out--dir 的縮寫。

plugins

plugins 的本質是一個 js 程序,指示着 Babel 如何轉換代碼,如何解析代碼。

案例:
在上面的例子中,我們在 index.js 中寫了一個箭頭函數,然而箭頭函數在低版本瀏覽器是不兼容的,所以得進行代碼轉換,將箭頭函數轉換爲普通的函數,這裏就涉及到怎麼設置 babel 的代碼解析方式了。

官方提供了一個插件,用於將箭頭函數轉換爲普通的函數:

npm i --save-dev @babel/plugin-transform-arrow-functions

安裝完成後就可以通過命令行的方式來運行:

npx babel src --out-dir lib --plugins=@babel/plugin-transform-arrow-functions

結果在 lib 目錄中的代碼被轉換了:

const fn = function () {
  return 1;
}; // 箭頭函數, 返回值爲1


console.log(fn());

雖然已經實現了箭頭函數的轉換功能,但是其他的 ES6+ 語法還是不能進行轉換的,這是因爲我們使用的這個插件僅僅支持函數轉換。那麼問題來了,ES6+ 有那麼多語法,如果一個瀏覽器不支持 ES6+ ,那麼我們不就需要安裝很多這樣的插件嗎??

Presets

上面問題的答案顯然是否定的,Presets 正是用於解決這種問題的。它是一組插件的集合,可以使用官方的,也可以自己自定義。

@babel/preset-env

這是一個將 ES6+ 轉換爲低版本代碼的插件集合。
安裝:

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

比如:我們使用 ES7 的乘方運算符和函數參數支持尾部逗號:

const fn = () => 1; // ES6箭頭函數, 返回值爲1
let num = 3 ** 2; // ES7求冪運算符
let foo = function(a, b, c, ) { // ES7參數支持尾部逗號
    console.log('a:', a)
    console.log('b:', b)
    console.log('c:', c)
}
foo(1, 3, 4)
console.log(fn());
console.log(num);

命令行運行:

npx babel src --out-dir lib --presets=@babel/preset-env

結果,在 lib 目錄下的代碼進行了轉換:

"use strict";

var fn = function fn() {
  return 1;
}; // 箭頭函數, 返回值爲1


var num = Math.pow(3, 2);

var foo = function foo(a, b, c) {
  console.log('a:', a);
  console.log('b:', b);
  console.log('c:', c);
};

foo(1, 3, 4);
console.log(fn());
console.log(num);

好了,到目前爲止我們瞭解了 @babel/core@babel/clipluginspresets,但是你會發現一個問題,我們一直使用命令行的方式來執行代碼,這顯然不是簡潔的方式,所以,接下來我們需要將這些複雜的命令做成配置項。

配置

在項目中創建一個 babel.config.js 文件:

const presets = [
	[
    "@babel/env",
    {
      targets: {
        edge: "17",
        chrome: "64",
        firefox: "60",
        safari: "11.1"
      }
    }
  ]	
]

module.exports = { presets };

加上這個配置的作用是:

  • 使用了 env preset
  • env preset 只會爲目標瀏覽器中沒有的功能加載轉換插件

現在,我們只需要使用命令 npm run build 這個命令就可以進行代碼轉換了。然而,你會好奇 Babel 是如何找到這個配置文件的呢?答案是默認情況下它會去項目的根目錄找一個名爲 babel.config.js 的文件(或者 babelrc.js)作爲配置文件。

如何非得改這個配置文件的名稱,那麼我們的命令就需要帶上參數了:

{
	"scripts": {
		"build": "babel src -d lib --config-file ./babel.config.js"
	}
}

需要注意的還有一句話:只會爲目標瀏覽器中沒有的功能加載轉換插件。比如,上面的配置中,edge:"17",意思就是轉換之後的代碼支持到 edge17,如果代碼在 edge17 中本已支持,則不進行代碼轉換。

所以,你會發現執行 npm run build 命令後,lib 中的代碼沒有進行轉換。這是因爲那些目標瀏覽器本來就支持這些語法,如果將 edge:"17" 改爲 edge:"10" ,重新運行,結果就會轉換了。

Polyfill

在上面提到,plugins 是插件,比如將箭頭函數轉換爲普通函數的插件:@babel/plugin-transform-arrow-functions
presets 是一組插件的集合,比如上面使用的 env preset

然而,polyfill 是對執行環境或其他功能的補充。

比如,在 edge10 中使用 ES7 的語法 includes(),但是我們知道這個版本的瀏覽器環境是不支持這個方法的,如果強行使用並不能達到預期效果。

polyfill 這是解決這個問題的,如果環境不支持,那麼就幫你引用一個支持這種語法的環境!!

示例:

// 原來的代碼
var hasTwo = [1, 2, 3].includes(2);

// 加了polyfill之後的代碼
require("core-js/modules/es7.array.includes");
require("core-js/modules/es6.string.includes");
var hasTwo = [1, 2, 3].includes(2);

嘿嘿,到這裏知道 polyfill 的用處了吧。

@babel/polyfill

這是一個用於模擬 ES6+ 環境的 polyfill,也就是說,它支持 ES6+ 的語法。

安裝:

npm i --save @babel/polyfill

但是,由於我們使用的是 env preset ,這個配置中有一個 useBuiltIns 的選項,將此設置爲 "usage" 就只包括你需要的 polyfill

const presets = [
	[
		"@babel/env",
		{
			targets: {
				edge: "17",
				chrome: "64",
				firefox: "67",
				safari: '11.1'
			},
+			useBuiltIns: "usage"
		}
	]
]

module.exports = { presets }

安裝配置完成後,Babel 將檢查你的所有代碼,然後查詢目標環境中缺少的功能,並引入僅包含所需的 polyfill

示例:

在前面的例子中,我們使用一下 edge17 沒有的 Promise.prototype.finally

const fn = () => 1; // ES6箭頭函數, 返回值爲1
let num = 3 ** 2; // ES7求冪運算符
let hasTwo = [1, 2, 3].includes(2)
let foo = function(a, b, c, ) { // ES7參數支持尾部逗號
    console.log('a:', a)
    console.log('b:', b)
    console.log('c:', c)
}
foo(1, 3, 4)
Promise.resolve().finally();//edge17不支持
console.log(fn());
console.log(num);
console.log(hasTwo);

執行 npm run build,結果代碼沒有被轉換,而是 polyfill 幫我們引入了一個環境:

"use strict";

require("core-js/modules/es7.promise.finally");

const fn = () => 1; // ES6箭頭函數, 返回值爲1


let num = 3 ** 2; // ES7求冪運算符

let hasTwo = [1, 2, 3].includes(2);

let foo = function foo(a, b, c) {
  // ES7參數支持尾部逗號
  console.log('a:', a);
  console.log('b:', b);
  console.log('c:', c);
};

foo(1, 3, 4);
Promise.resolve().finally();
console.log(fn());
console.log(num);
console.log(hasTwo);

最後,你會發現這是一個被遺棄的 @babel/polyfill,而是推薦你使用 core-js@3 + @babel/preset-env

解決辦法:

安裝 core-js@3

npm i --save core-js@3

添加 corejs 選項:

const presets = [
[
  "@babel/env",
      {
        targets: {
        edge: "17",
        chrome: "64",
        firefox: "67",
        safari: '11.1'
      },
      useBuiltIns: "usage",
+     corejs: 3
    }
  ]
]

module.exports = { presets }

最後,npm run build 你就會發現警告沒有了,代碼也是正確的。

發佈了101 篇原創文章 · 獲贊 0 · 訪問量 5479
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章