摘要:歸納總結(jié)在前端的發(fā)展過程中,的兼容性,一直是前端頭痛的問題,在以前的一些有些項目中,為解決瀏覽器兼容而花費的時間甚至還要多余實際的業(yè)務(wù)邏輯開發(fā)時間,就是其中處理兼容的轉(zhuǎn)譯工具或者叫平臺。初稿完成初步規(guī)范。完成將被添加到下一年度發(fā)布。
github: babel歸納總結(jié)
在前端的發(fā)展過程中,javascript的兼容性,一直是前端頭痛的問題,在以前的一些有些項目中,為解決瀏覽器兼容而花費的時間甚至還要多余實際的業(yè)務(wù)邏輯開發(fā)時間,babel就是其中處理兼容的轉(zhuǎn)譯工具(或者叫平臺)。
babel是什么javascript在不斷發(fā)展,新的提案標(biāo)準(zhǔn)每年都會有,在得到廣泛普及之前,Babel 把用最新標(biāo)準(zhǔn)編寫的 JavaScript 代碼向下編譯成可以在今天隨處可用的版本
babel的編譯過程分為3步,解析(parse),轉(zhuǎn)換(transform),生成(generate),對應(yīng)的三個插件分別是Babylon、babel-traverse、babel-generator。
babylon將源碼轉(zhuǎn)換為抽象語法樹(AST);babel-traverse通過AST生成一個便于操作、轉(zhuǎn)換的path對象,供我們的babel插件處理;babel-generator讀取AST并將其轉(zhuǎn)換為代碼和源碼映射。這些過程不是本文的關(guān)注點,我們關(guān)注的是結(jié)果,哪些插件與我們的生產(chǎn)息息相關(guān),我們?nèi)绾稳ナ褂胋abel的插件。
vue腳手架生成的項目在.babelrc文件中的配置:
{ "presets": [ ["env", { "modules": false, "targets": { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] } }], "stage-2" ], "plugins": ["transform-vue-jsx", "transform-runtime"] }plugin配置項
babel插件推崇的是功能的單一性,就是每個插件的功能盡可能的單一,比如我要使用es6的箭頭函數(shù),那就可以裝一個轉(zhuǎn)換插件npm i -D @babel/plugin-transform-arrow-functions,將其寫進(jìn).babelrc文件里就行了:詳情
{ "presets": [], "plugins": ["@babel/plugin-transform-arrow-functions"] }
這樣,我們寫的:
(a) => [...a]
會被該插件轉(zhuǎn)換為:
function (a) { return [...a] }
這個插件也只解決箭頭函數(shù)的轉(zhuǎn)換,就算函數(shù)內(nèi)部用了其它新語法也不管,這個好處是很明顯的,就跟咱寫項目推崇組件的細(xì)膩度一個道理
presets配置項然而呢,js發(fā)展有點快,想一下那個es2015(es6)一下加了多少東西,我們要使用還得一個一個的npm i -D xxx,這個有點小麻煩,所以就可以采用presets配置項。npm i -D babel-preset-es2015,然后配置.babelrc。詳情
為了承接上文,這里暫時先用babel6的寫法,babel7里也可以用babel-preset-es2015,但是文檔里去掉了,es2015、es2016、es2017(2018年的東西直接寫在env里了,7月份2019年的新標(biāo)準(zhǔn)就要來羅@_@)等都被放在env里面了,以后這幾個preset會不會砍掉就不知道咯
{ "presets": ["es2015"], "plugins": [] }
這樣我們就可以使用包括箭頭函數(shù)在內(nèi)的es6的新語法而不用去擔(dān)心兼容問題。這下這兩個的關(guān)系也就清晰了,presets里面配置的是一些plugins集合
在babel 7.3.0里面,presets -- 對應(yīng)插件有這些:
env -- @babel/preset-env
stage-0 -- @babel/preset-stage-0
stage-1 -- @babel/preset-stage-1
stage-2 -- @babel/preset-stage-2
stage-3 -- @babel/preset-stage-3
flow -- @babel/preset-flow
react -- @babel/preset-react
minify -- babel-preset-minify
typescript -- @babel/preset-typescript
env在presets配置里面,我們看到了:
["env", { "modules": false, "targets": { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] } }]
這個env是@babel/preset-env這個集合插件配置項,這里的配置項:
modules:"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false, defaults to "auto".
意思就是讓babel把es6 模塊轉(zhuǎn)化為其它模塊化類型。如果選擇 false 就不進(jìn)行模塊化轉(zhuǎn),我們的目標(biāo)是瀏覽器,es6以前js是沒有模塊化的,commonjs、amd等只是社區(qū)方案,沒有瀏覽器支持的,所以我們設(shè)置為false,如果我們寫node上運行的代碼,就要設(shè)置為"commonjs"
target:就是告訴babel你的js要兼容哪些環(huán)境,它會幫你將你寫的js轉(zhuǎn)譯成目標(biāo)環(huán)境兼容的js語法,這個具體配置可以看browserslist
那就是說,js無論用什么新玩意,@babel/preset-env都能跟我兼容到我想要的環(huán)境?帶著問題,我們再看看官網(wǎng)的介紹,What is Babel:
Transform syntax(轉(zhuǎn)換語法)
Polyfill features that are missing in your target environment (Ployfill新特性--也就是Api)
Source code transformations(源碼轉(zhuǎn)換)
And more!
再看看通過env轉(zhuǎn)換的幾個demo:
a => a // 轉(zhuǎn)為 function (a) {return a} function func (b = false) {return false} // 轉(zhuǎn)為 function func (b) { b = b || false return b }
比較明顯,上面的都屬于轉(zhuǎn)換語法,所以應(yīng)該說“js無論用什么新語法,@babel/preset-env都能幫你兼容到目標(biāo)環(huán)境”。
@babel/preset-env具體可以幫我們轉(zhuǎn)化哪些呢?看這兒JavaScript新特性和Babel插件的映射關(guān)系,這個是@babel/preset-env集合插件所包含的插件列表,每個插件對應(yīng)轉(zhuǎn)換一個新特性,至于沒有的,比如promise、Array.from等,請往下看。
stage-2在上面的配置中,我們看到env下面有個stage-2。stage-x,這里面包含的都是當(dāng)年最新規(guī)范的草案,每年更新。細(xì)分為如下幾步
Stage 0 - 稻草人: 只是一個想法,經(jīng)過 TC39 成員提出即可。
Stage 1 - 提案: 初步嘗試。
Stage 2 - 初稿: 完成初步規(guī)范。
Stage 3 - 候選: 完成規(guī)范和瀏覽器初步實現(xiàn)。
Stage 4 - 完成: 將被添加到下一年度發(fā)布。
官網(wǎng)里有一句話It is important to note that @babel/preset-env does not support stage-x plugins.,就是說@babel/preset-env中不包含在草案階段的新屬性的轉(zhuǎn)換插件
其實我們通過plugin-features,以及proposals/finished-proposals(其中2019就是今年的stage-4),可以發(fā)現(xiàn)@babel/preset-env是包含了stage-4階段的plugins的。
比如寫react的同學(xué)比較熟悉的decorators目前就處于stage-2階段,我們要用這些處于草案階段的新屬性,可以安裝npm i -D @babel/preset-stage-2,然后在presets里寫上stage-2,babel就會通過那些處于草案階段的新屬性的插件將我們代碼中的用到的新屬性轉(zhuǎn)譯成為es5
此外,低一級的 stage 會包含所有高級 stage 的內(nèi)容,例如 stage-2 會包含 stage-2, stage-3 的所有內(nèi)容。
babel-ployfillBabel 幾乎可以編譯所有時新的 JavaScript 語法,但對于 APIs 來說卻并非如此。比如說:Promise、WeakMap、Array.from 、Object.assign、Array.prototype.includes、generator等。為了解決這個問題,我們使用一種叫做 Polyfill(代碼填充,也可譯作兼容性補丁) 的技術(shù)。能讓你提前使用還不可用的 APIs。
引入它很簡單,我們npm i -S @babel/polyfill,
在vue中的入口文件main.js文件的最上面:
import "@babel/polyfill";
或者在webpack入口里引入:
module.exports = { entry: ["@babel/polyfill", "./main.js"], };
兩者任選其一
上面這兩種方式是將整個polyfill都引入了,很多代碼其實對我們是沒有用的,比如,我們的env配置的是不需要兼容ie9以下的瀏覽器,這種引入方式把所有兼容ie的代碼都引入了,包含ie8以下,所以,一般我們會在.babelrc文件里的env里配置下useBuiltIns參數(shù),這樣babel在引入的時候會根據(jù)我們env環(huán)境去加載相應(yīng)的polyfill:詳細(xì)
有如下三種方式
如果在 .babelrc 中設(shè)置 useBuiltIns: "usage",則不要在 webpack.config.js entry 數(shù)組或 源碼中包含 @babel/polyfill。注意,仍然需要安裝 babel-polyfill(就是說 npm i -S @babel/polyfill后就不管了)。
如果在 .babelrc 中設(shè)置 useBuiltIns: "entry",在應(yīng)用程序入口(main.js)的頂部引入 @babel/polyfill。
如果在 .babelrc 中沒有明確設(shè)置useBuiltIns的值(就是你沒有去配置這項)或者設(shè)置了 useBuiltIns: false,將 @babel/polyfill 添加到 webpack.config.js 的入口數(shù)組中。
// .babelrc { ["env", { "modules": false, "targets": { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] }, // 是否自動引入polyfill,開啟此選項必須保證已經(jīng)安裝了babel-polyfill // 在這里設(shè)置自動引入后,babel會根據(jù)你配置的兼容的環(huán)境,去按需加載polyfill的代碼,這樣能保證代碼量最少 // 參數(shù):Boolean,默認(rèn)為false. "useBuiltIns": false }] } // webpack.base.conf.js module.exports = { entry: ["@babel/polyfill", "./main.js"], };@babel/plugin-transform-runtime
我們看到上面的配置中有個transform-runtime,這個是配置@babel/plugin-transform-runtime,它是做什么的呢?官網(wǎng)說:一個插件,通過重復(fù)使用babel注入的助手(helper)代碼,來減少代碼體積,我們看看它是如何工作的。
npm i -D @babel/plugin-transform-runtime // .babelrc { "plugins": [ "@babel/plugin-transform-runtime", // 默認(rèn)配置 { "absoluteRuntime": false, "corejs": false, "helpers": true, "regenerator": true, "useESModules": false } ] }
比如這個es6的class類:
class Person { }
在沒有使用transform-runtime時,每個使用class函數(shù)處,Babel 會生成class的helper函數(shù)放置在文件頂部,就是說在多個文件里使用了class, babel就會在每個文件里面都生成相同的helper:
"use strict"; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function"); } } var Person = function Person() { _classCallCheck(this, Person); };
這樣不必要的重復(fù)會使我們的代碼體積非常雍腫,transform-runtime就是來解決這個重復(fù)生成helper的問題的,它會將這個es6的class語法的helper函數(shù)放在babel-runtime/helpers里,然后在使用處通過require引入,這樣就沒必要在每個使用處重復(fù)定義helper了,達(dá)到了減少代碼體積的效果。
"use strict"; var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var Person = function Person() { (0, _classCallCheck3.default)(this, Person); };@babel/runtime 對比 babel-polyfill
@babel/runtime和@babel/polyfill這兩個模塊功能幾乎相同,就是轉(zhuǎn)碼新增 api
@babel/polyfill 把原生的方法重寫了,以promise為例,判斷環(huán)境promise存不存在,不存在就寫個全局作用域的promise。它會一次引入所有的api的polyfill,只是根據(jù)env配置引入的包大小可能會不同。
@babel/runtime 是寫了個helper函數(shù),以promise為例,你代碼中的promise都會被換成_promise,然后babel會生成一個_promise helper函數(shù),大致也是目標(biāo)環(huán)境存在就用原生的,不存在就用polyfill的promise。而且這個是按需引入的,如果你的項目中只使用了promise,就只會引入promise的polyfill。但是它有個問題,實例上的方法無能為力,比如 Array上的form方法,String上的includes等
根據(jù)它們兩的特點,@babel/polyfil一般用于前端項目,@babel/runtime一般用來寫插件
幾個常用的babel插件 babel-cilBabel 的 CLI 是一種在命令行下使用 Babel 編譯文件的簡單方法。有時候我們只是寫一個插件,需要用babel轉(zhuǎn)一下我們代碼中的高階語法,因為項目可能不太大,用不到構(gòu)建工具,就可以用babel-cil。轉(zhuǎn)換依據(jù)我們的.babelrc文件或者package.json中babel選項
編譯一個文件
babel my-file.js
如果我們想要把一個目錄整個編譯成一個新的目錄,可以使用 --out-dir 或者 -d。.
$ babel src --out-dir lib # 或 $ babel src -d libbabel-loader
babel-loader是什么呢?前面說了,我們可以通過babel-cil在命令行里告訴babel轉(zhuǎn)譯哪些js,也可以通過babel-register,在代碼里通過require來轉(zhuǎn),但是,現(xiàn)在前端開發(fā)是一個工程化過程,依賴關(guān)系比較復(fù)雜,在一個稍微大點兒的項目中還真沒法手動告訴babel要處理哪些文件,比如一個.vue文件,里面還包含html、css,還有一些不是js的鬼語法,這時候就要借助其它插件先提前處理下,所以,webpack根據(jù)依賴關(guān)系,加載文件的時候遇到j(luò)s文件后,會將文件內(nèi)容的js字符串根據(jù)loader配置的先后順序,挨個兒傳遞給它們處理,babel-loader就是其中之一
總結(jié) 什么是babelbabel就是將目標(biāo)環(huán)境(瀏覽器)通過打補丁升級成支持最新javascript語法的環(huán)境的工具。
用vue腳手架生成的項目,js怎么兼容到ie9// .babelrc { "presets": [ ["env", { // 這里默認(rèn)是false,不用再寫一遍 - // "modules": false, // 一般不多帶帶寫出來,babel/preset-env會自個讀取package里面的browserslist,與css兼容環(huán)境保持一致 // https://github.com/browserslist/browserslist - // "targets": { - // "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] - // }, }], "stage-2" ], "plugins": ["transform-vue-jsx", "transform-runtime"] } // webpack.base.conf.js module.exports = { entry: ["@babel/polyfill", "./main.js"], };插件快照
名稱 | 作用 | 備注 |
---|---|---|
babel/cli | 允許命令行使用 babel 命令轉(zhuǎn)譯文件 | 一般在寫插件時使用 |
babel/polyfill | 為所有 API 增加兼容方法 | 需要在所有代碼之前 require,且體積比較大 |
babel/plugin-transform-runtime | 把幫助類方法從每次使用前定義改為統(tǒng)一 require,精簡代碼 | --- |
babel/runtime | helper庫 | 需要安裝為依賴,而不是開發(fā)依賴,node環(huán)境使用,web環(huán)境不需要 |
babel/loader | babel插件在webpack項目中的一個入口 | --- |
babel/core | babel的polyfill庫 | --- |
babel/preset-env | babel預(yù)制環(huán)境的集合插件,通過配置目標(biāo)環(huán)境,轉(zhuǎn)換標(biāo)準(zhǔn)上的新特性 | 只轉(zhuǎn)新特性,不轉(zhuǎn)api |
babel/preset-stage-2 | 轉(zhuǎn)換草案stage-2以及stage-3階段的的新屬性 | --- |
參考:
babel
Babel 用戶手冊
Babel 插件手冊
babel-vs-babel-core-vs-babel-loader
babel全家桶
tc39草案
你真的會用 babel 嗎?
babel-preset-env/data/plugin-features.js
babel-plugin-transform-runtime 和 babel-runtime 的區(qū)別?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/102782.html
摘要:系列文章系列第一篇基礎(chǔ)雜記系列第二篇插件機制雜記系列第三篇流程雜記前言公司的前端項目基本都是用來做工程化的,而雖然只是一個工具,但內(nèi)部涉及到非常多的知識,之前一直靠來解決問題,之知其然不知其所以然,希望這次能整理一下相關(guān)的知識點。 系列文章 Webpack系列-第一篇基礎(chǔ)雜記 Webpack系列-第二篇插件機制雜記 Webpack系列-第三篇流程雜記 前言 公司的前端項目基本都是用...
摘要:全文的目的是達(dá)成使用進(jìn)行項目開發(fā),并且以我這個前端菜鳥所見所學(xué)來歸納整理。環(huán)境安裝與前期準(zhǔn)備我的基礎(chǔ)環(huán)境出的開源的編輯器命令行工具,下一個炒雞好用的神器。只提供組件,對配套技術(shù)不做限定,方便用戶與現(xiàn)有技術(shù)棧快速整合,降低使用成本。 全文的目的是達(dá)成使用amazeui-touch進(jìn)行項目開發(fā),并且以我這個前端菜鳥所見所學(xué)來歸納整理。文章不對詳細(xì)內(nèi)容做講解。 環(huán)境安裝與前期準(zhǔn)備 我的基礎(chǔ)環(huán)...
摘要:全文的目的是達(dá)成使用進(jìn)行項目開發(fā),并且以我這個前端菜鳥所見所學(xué)來歸納整理。環(huán)境安裝與前期準(zhǔn)備我的基礎(chǔ)環(huán)境出的開源的編輯器命令行工具,下一個炒雞好用的神器。只提供組件,對配套技術(shù)不做限定,方便用戶與現(xiàn)有技術(shù)棧快速整合,降低使用成本。 全文的目的是達(dá)成使用amazeui-touch進(jìn)行項目開發(fā),并且以我這個前端菜鳥所見所學(xué)來歸納整理。文章不對詳細(xì)內(nèi)容做講解。 環(huán)境安裝與前期準(zhǔn)備 我的基礎(chǔ)環(huán)...
摘要:今天我們來看一種優(yōu)雅的編寫的代碼的一種方式。有了之后,可以幫助我們在編寫模板的時候結(jié)構(gòu)更加簡單清晰。以上是筆者歸納總結(jié),如有誤之處,歡迎指出。 showImg(https://segmentfault.com/img/bVbiT3u?w=900&h=383);往期回顧 前文中我們講解了利用 ReactElement 來編寫React程序,但是我們也看到這種方式編寫 React 特別的麻...
閱讀 1057·2021-11-22 15:33
閱讀 3369·2021-11-08 13:20
閱讀 1383·2021-09-22 10:55
閱讀 2057·2019-08-29 11:08
閱讀 776·2019-08-26 12:24
閱讀 3073·2019-08-23 17:15
閱讀 2235·2019-08-23 16:12
閱讀 1941·2019-08-23 16:09