[譯]core-js@3, babel展望將來

github.com/zloirock/co… 原文連接javascript

通過一年半的開發,數十個版本,許多不眠之夜,core-js@3 終於發佈了。這是 core-jsbabel 補丁相關的功能的最大的一次變化。html

什麼是 core-js?java

  • 它是JavaScript標準庫的 polyfill,它支持
    • 最新的 ECMAScript 標準
    • ECMAScript 標準庫提案
    • 一些 WHATGW / W3C 標準(跨平臺或者 ECMAScript 相關)
  • 它最大限度的模塊化:你能僅僅加載你想要使用的功能
  • 它可以不污染全局命名空間
  • 和babel緊密集成:這可以優化core-js的導入

它是最廣泛、最流行給 JavaScript 標準庫打補丁的方式,可是有很大一部分開發者並不知道他們間接的使用了core-js🙂node

貢獻

core-js 是我本身愛好的項目,沒有給我帶來任何利潤。它花了我很長的時間,真的很昂貴:爲了完成 core-js@3,我在幾個月以前已經離開個人工做。這個項目對許多人和公司起到了促進做用。由於這些,籌集資金去支持 core-js 的維護是說得通的。git

若是你對 core-js 感興趣或者在你天天的工做中有使用到,你能夠在 Open Collective 或者 Patreon 成爲贊助者。es6

你能夠給提供一個好的工做,和我如今作的相關的。github

或者你能夠以另外一種方式貢獻,你能夠幫助去改進代碼、測試或者文檔(如今,core-js 的文檔還很糟糕!)。web

core-js@3有哪些變化?

JavaScript 標準庫中變化的內容

因爲如下兩個緣由,這個版本包含豐富的、新的 JavaScript 補丁:chrome

  • core-js 只在 major(主)版本更新時纔有 break changes,即便須要和提案的內容對齊。
  • core-js@2 在一年半前已經進入功能凍結階段了;全部新的功能只可以添加到 core-js@3 這個分支。

穩定的 ECMAScript 功能

穩定的 ECMAScript 功能在 core-js 中已經幾乎徹底支持有很長一段時間了,除此以外,core-js@3 引進了一些新功能:npm

一些在 ES2016-ES2019 中做爲提案被接受且已經使用很長時間的功能,如今被標記爲穩定:

修復了針對瀏覽器的許多問題,例如,Safari 12.0 Array.prototype.reverse bug 已經被修復了。

ECMAScript 提案

除了上文提到的支持內容,core-js@3 如今還支持下面的 ECMAScript 提案:

  • globalThis stage 3( 如今是 stage 4 )的提案 - 以前,已經有了 globalSystem.global
  • Promise.allSettled stage 2( 如今是 stage 4 )提案
  • Set 方法 stage 2 提案:
    • Set.prototype.difference
    • Set.prototype.intersection
    • Set.prototype.isDisjoinFrom
    • Set.prototype.isSubsetOf
    • Set.prototype.isSupersetOf
    • Set.prototype.symmetricDifference
    • Set.prototype.union
  • 新 collections 方法 stage 1 提案,包函許多新的有用的方法:
    • Map.groupBy
    • Map.keyBy
    • Map.prototype.deleteAll
    • Map.prototype.every
    • Map.prototype.filter
    • Map.prototype.find
    • Map.prototype.findKey
    • Map.prototype.includes
    • Map.prototype.keyOf
    • Map.prototype.mapKeys
    • Map.prototype.mapValues
    • Map.prototype.merge
    • Map.prototype.reduce
    • Map.prototype.some
    • Map.prototype.update
    • Set.prototype.addAll
    • Set.prototype.deleteAll
    • Set.prototype.every
    • Set.prototype.filter
    • Set.prototype.find
    • Set.prototype.join
    • Set.prototype.map
    • Set.prototype.reduce
    • Set.prototype.some
    • WeakMap.prototype.deleteAll
    • WeakSet.prototype.addAll
    • WeakSet.prototype.deleteAll
  • String.prototype.replaceAll stage 1( 如今是 stage 3 ) 提案
  • String.prototype.codePoints stage 1 提案
  • Array.prototype.last(Item|Index) stage 1 提案
  • compositeKeycompositeSymbol 方法 stage 1 提案
  • Number.fromString stage 1 提案
  • Math.seededPRNG stage 1 提案
  • Promise.any (合併的錯誤) stage 0( 如今是stage 3 )提案

一些提案的變化很大,core-js 也將相應的更新:

web 標準

許多有用的功能被添加到這個類別中。

最重要的一個是 URLURLSearchParams。他是最受歡迎的功能請求之一。增長 URLURLSearchParams,並保證他們最大限度的符合規範,保持源代碼足夠緊湊來支撐任何環境是 core-js@3 開發中最困難的任務之一

core-js@3 包函在JavaScript中建立微任務( microtask )的標準方法:queueMicrotaskcore-js@2 提供了 asap 函數,提供了一樣功能的老的提案。queueMicrotask 被定義在 HTML 標準中,它已經可以在現代瀏覽器好比 Chromium 或者 NodeJS 中使用。

另外一個受歡迎的功能請求是支持 DOM集合的 .forEach 方法。因爲 core-js 已經針對DOM集合迭代器作了polyfill,爲何不給 節點列表DOMTokenList 也增長 .forEach 呢?

移除過期的功能:

  • Reflect.enumrate 由於他已經從標準中移除了
  • System.globalglobal 如今他們已經被 globalThis 代替
  • Array.prototype.flatten 如今被 Array.prototype.flat 代替
  • asapqueueMicrotask 代替
  • Error.isError 被撤銷很長時間了
  • RegExp.escape 好久以前被拒絕了
  • Map.prototype.toJSONSet.prototype.toJSON 也是好久前被拒絕了
  • 沒必要要而且被錯誤添加的迭代器方法:CSSRuleListMediaListStyleSheetList

再也不有非標準、非提案的功能

許多年前,我開始寫一個庫,他是個人JavaScript程序的核心:這個庫包函 polyfills 和一些我須要的工具函數。一段時間後,這個庫以 core-js 命名發佈。我認爲如今大多數 core-js 用戶不須要非標準的 core-js 功能,他們大多已經在早期版本移除了,如今是時候將剩餘部分從 core-js 中移除。從這個版本開始,core-js 能夠被稱爲 polyfill 了。

包、入口和模塊名字

一個issue裏提了 core-js 包的很大( ~2MB ),有不少重複文件。由於這個緣由,core-js 分紅了3個包:

core-js 的早期版本中,穩定的 ECMAScript 功能和 ECMAScript 提案的 polyfill 模塊化須要分別加 es6.es7. 前綴。這是在 2014 年作的決定,那時將 ES6 以後的全部功能都視爲 ES7。在 core-js@3 中全部穩定的 ECMAScript 功能都增長 es. 前綴,ECMAScript 提案增長 esnext. 前綴。

幾乎全部的 CommonJS 入口都改變了。core-js@3 相比於 core-js@2 有更多的入口:這帶來的最大限度的靈活性,使你可以僅僅引入你的應用須要的依賴。

這裏是一些例子關於如何使用新的入口:

// 使用 `core-js` 所有功能打補丁:
import "core-js";
// 僅僅使用穩定的 `core-js` 功能 - ES 和 web 標準:
import "core-js/stable";
// 僅僅使用穩定的 ES 功能
import "core-js/es";

// 若是你想用 `Set` 的補丁
// 全部 `Set`- ES 提案中,相關的功能:
import "core-js/features/set";
// 穩定的 `Set` ES 功能和來自web標準的功能
// (DOM 集合迭代器)
import "core-js/stable/set";
// 只有 `Set` 所需的穩定的 ES 功能
import "core-js/es/set";
// 與上面一致,但不會污染全局命名空間
import Set from "core-js-pure/features/set";
import Set from "core-js-pure/stable/set";
import Set from "core-js-pure/es/set";


// 僅僅爲須要的方法打補丁
import "core-js/feature/set/intersection";
import "core-js/stable/queque-microtask";
import "core-js/es/array/from";

// 爲 reflect metadata 提案打補丁
import "core-js/proposals/reflect-metadata";
// 爲全部 stage 2+ 的提案打補丁
import "core-js/stage/2";
複製代碼

其餘重要的變化

core-js polyfill 可以 配置侵入等級。若是你認爲有些情境 core-js 功能檢測侵入性太強,原生實現對你來講已經足夠,或者一個錯誤的實現沒有被 core-js 檢測到,你能夠修改 core-js 的默認行爲。

若是沒法安裝規範的每一個細節實現某個功能,core-js 增長了一個 .sham 屬性,例如,IE11中 Symbol.shamtrue

再也不有 LiveScript! 當我開始寫 core-js 時,我主要使用的是 LiveScript ;一段時間後,我用 JavaScript 重寫了所有的 polyfills 。在 core-js@2 中測試和幫助的工具函數仍然使用 LiveScript :它是很是有趣的像 CoffeeScript 同樣的語言,有強大的語法糖使你可以寫很是緊湊的代碼,可是它幾乎已經死了。除此以外,它也是爲 core-js 貢獻的屏障,由於大多數 core-js 用戶不知道這個語言。core-js@3 測試和工具函數使用現代 ES 語法:它將成爲爲 core-js 貢獻的好時機🙂。

對於大多數用戶,爲了優化 core-js 導入,我建議使用 babel。固然,有些狀況下 core-js-builder 仍然有用。如今它支持 target 參數,使用帶有目標引擎的瀏覽器列表 查詢 - 你可以建立一個 bundle,僅僅包含目標引擎須要的 polyfills。對於這種狀況,我作了 core-js-compat,更多關於它的信息,你可以從 這篇文章的 @babel/preset-env 部分瞭解到。


這僅僅是冰山一角,更多的變化在內部。更多關於 core-js 變化能夠在 changelog 中找到。

Babel

正如上文提到的,babelcore-js 是緊密集成的:babel 提供了優化 core-js 優化導入的可能性。core-js@3 開發中很重要的一部分是改進 core-js 相關的 babel 功能(看這個PR)。這些變化在 Babel 7.4.0 發佈了。

babel/polyfill

@babel/polyfill 是一個包裹的包,裏面僅僅包含 core-js 穩定版的引入(在Babel 6 中也包含提案)和 regenerator-runtime/runtime,用來轉譯 generators 和 async 函數。這個包沒有提供從 core-js@2core-js@3 平滑升級路徑:由於這個緣由,決定棄用 @babel/polyfill 代之以分別引入須要的 core-jsregenerator-runtime

原來

import "@babel/polyfill";
複製代碼

如今使用兩行代替:

import "core-js/stable";
import "regenerator-runtime/runtime";
複製代碼

別忘記直接安裝這兩個依賴!

npm i --save core-js regenerator-runtime
複製代碼

@babe/preset-env

@babel/preset-env 有兩種不一樣的模式,經過 useBuiltIns 選項:entryusage 優化 core-js的導入。

Babel 7.4.0 引入了兩種模式的共同更改,以及每種模式的特定的修改。

因爲如今 @babel/preset-env 支持 core-js@2core-js@3,所以 useBuiltIns 須要新的選項 -- corejs,這個選項用來定義使用 core-js 的版本(corejs: 2 或者 corejs: 3)。若是沒有設置,corejs: 2 是默認值而且會有警告提示。

爲了使 babel 支持未來的次要版本中引入的 core-js 的新功能,你能夠在項目中定義明確的次要版本號。例如,你想使用 core-js@3.1 使用這個版本的新特性,你能夠設置 corejs 選項爲 3.1corejs: '3.1' 或者 corejs: {version: '3.1'}

@babel/preset-env 最重要的一個功能就是提供不一樣瀏覽器支持特性的數據來源,用來肯定是否須要 core-js 填充某些內容。 caniusemdncompat-table 是很好的教育資源,可是並不意味着他們可以做爲數據源被開發者使用:只有 compat-table 包函好的 ES 相關數據集,它被 @babel/preset-env 使用,可是仍有些限制:

  • 它包含的數據僅僅關於 ECMAScript 特性和提案,和 web 平臺特性例如 setImmediate 或者 DOM 集合迭代器沒有關係。因此直到如今,@babel/preset-env 仍然經過 core-js 添加所有的 web 平臺特性即便他們已經支持了。

  • 它他不包含任何瀏覽器(甚至是嚴重的)bug 信息:例如,上文提到的在 Safari 12 中 Array#reverse,可是 compat-table 並無將它標記爲不支持。另外一方面,core-js 已經修復了這個錯誤實現,可是由於 compat-table 關係,並不能使用它。

  • 它僅包函一些基礎的、幼稚的測試,沒有檢查功能在真實環境下是否能夠正常工做。例如,老版本 Safari 的破壞的迭代器沒有 .next 方法,可是 compat-table 代表 Safari 支持,由於它用 typeof 方法檢測迭代器方法返回了 "function"。一些像 typed arrays 的功能幾乎沒有覆蓋。

  • compat-table 不是爲了向工具提供數據而設計的。我是 compat-table 的維護者之一,可是其餘的維護者反對爲維護這個功能

由於這個緣由,我建立了 core-js-compat:它提供了對於不一樣瀏覽器 core-js 模塊的必要性數據。當使用 core-js@3 時,@babel/preset-env 將使用新的包取代 compat-table請幫助咱們測試並提供缺乏的引擎的數據的映射關係!😊。

在 Babel 7.3 以前,@babel/preset-env 有一些與 polyfills 注入順序有關的問題。從 7.4.0開始,@babel/preset-env 只按推薦順序增長鬚要的 polyfills 。

useBuiltIns: entry with corejs: 3

當使用這個選項時,@babel/preset-env 代替直接引用 core-js 而是引入目標環境特定須要的模塊。

在這個變化前,@babel/preset 僅替換 import '@babel/polyfill'import 'core-js',他們是同義詞用來 polyfill 全部穩定的 JavaScript 特性。

如今 @babel/polyfill 棄用了,當 corejs 設置爲 3 時 @babel/preset-env 不會轉譯他。

core-js@3 中等價替換 @babel/polyfill

import "core-js/stable";
import "regenerator-runtime/runtime";
複製代碼

當目標瀏覽器是 chrome 72 時,上面的內容將被 @babel/preset-env 轉換爲

import "core-js/modules/es.array.unscopables.flat";
import "core-js/modules/es.array.unscopaables.flat-map";
import "core-js/modules/es.object.from-entries";
import "core-js/modlues/web.immediate";
複製代碼

當目標瀏覽器是 chrome 73(它徹底支持 ES2019 標準庫),他將變爲不多的引入:

import "core-js/modules/web.immediate";
複製代碼

自從 @babel/polyfill 被棄用,轉而使用分開的 core-jsregenerator-runtime,咱們可以優化 regenerator-runtime 的導入。由於這個緣由,若是目標瀏覽器原生支持 generators ,那麼 regenerator-runtime 的導入將從源代碼中移除。

如今,設置 useBuiltIns: entry 模式的 @babel/preset-env 編譯全部可以得到的 core-js 入口和他們的組合。這意味着你可以自定義,經過使用不一樣的 core-js 入口,它將根據的目標環境優化。

例如,目標環境是 chrome 72

import "core-js/es";
import "core-js/proposals/set-methods";
import "core-js/features/set/map";
複製代碼

將被替換爲

import "core-js/modules/es.array.unscopables.flat";
import "core-js/modules/es.array.unscopables.flat-map";
import "core-js/modules/es.object.from-entries";
import "core-js/modules/esnext.set.difference";
import "core-js/modules/esnext.set.intersection";
import "core-js/modules/esnext.set.is-disjoint-from";
import "core-js/modules/esnext.set.is-subset-of";
import "core-js/modules/esnext.set.is-superset-of";
import "core-js/modules/esnext.set.map";
import "core-js/modules/esnext.set.symmetric-difference";
import "core-js/modules/esnext.set.union";
複製代碼

useBuiltIns: usage with corejs: 3

當使用這個選項時,@babel/preset-env 在每一個文件的開頭引入目標環境不支持、僅在當前文件中使用的 polyfills。

例如,

const set = new Set([1, 2, 3]);
[1, 2, 3].includes(2);
複製代碼

當目標環境是老的瀏覽器例如 ie 11,將轉換爲

import "core-js/modules/es.array.includes";
import "core-js/modules/es.array.iterator";
import "core-js/modules/es.object.to-string";
import "core-js/modules/es.set";

const set = new Set([1, 2, 3]);
[1, 2, 3].includes(2);
複製代碼

當目標是 chrome 72 時不須要導入,由於這個環境須要 polyfills:

const set = new Set([1, 2, 3]);
[1, 2, 3].includes(2);
複製代碼

Babel 7.3 以前,useBuiltIns: usage 不穩定且不是足夠可靠:許多 polyfills 不包函,而且添加了許多不是必須依賴的 polyfills。在 Babel 7.4 中,我嘗試使它理解每種可能的使用模式。

在屬性訪問器、對象解構、in 操做符、全局對象屬性訪問方面,我改進了肯定使用哪一個 polyfills 的技術。

@babel/preset-env 如今注入語法特性所需的 polyfills:使用 for-of 時的迭代器,解構、擴展運算符和 yield 委託;使用動態 import 時的 promises,異步函數和 generators,等。

Babel 7.4 支持注入提案 polyfills。默認,@babel/preset-env 不會注入他們,可是你可以經過 proposals 標誌設置:corejs: { version: 3, proposals: true }

@babel/runtime

當使用 core-js@3 時, @babel/transform-runtime 如今經過 core-js-purecore-js的一個版本,不會污染全局變量) 注入 polyfills。

經過將 @babel/transform-runtime 設置 corejs: 3 選項和建立 @babel/runtime-corejs3 包,已經將 core-js@3@babel/runtime 集成在一塊兒。可是這將帶來什麼好處呢?

@babel/runtime 的一個受歡迎的 issue 是:不支持實例方法。從 @babel/runtime-corejs3 開始,這個問題已經解決。例如,

array.includes(something);
複製代碼

將被編譯爲

import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";

_includesInstanceProperty(array).call(array, something);
複製代碼

另外一個值得關注的變化是支持 ECMAScript 提案。默認狀況下的,@babel/plugin-transform-runtime 不會爲提案注入 polyfills 並使用不包含提案的入口。可是正如你在 @babel/preset-env 中作的那樣,你能夠設置 proposals 標誌去開啓:corejs: { version: 3, proposals: true }

沒有 proposals 標誌,

new Set([1, 2, 3, 2, 1]);
string.matchAll(/something/g);
複製代碼

將被編譯爲:

import _Set from "@babel/runtime-corejs/core-js-stable/set";

new _set([1, 2, 3, 2, 1]);
string.matchAll(/something/g);
複製代碼

當設置 proposals 後,將變爲:

import _Set from "@babel/runtime-corejs3/core-js/set";
import _matchAllInstanceProperty from "@babel/runtime-corejs/core-js/instance/match-all";

new _Set([1, 2, 3, 2, 1]);
_matchAllInstanceProperty(string).call(string, /something/g);
複製代碼

有些老的問題已經被修復了。例如,下面這種流行的模式在 @babel/runtime-corejs2 不工做,可是在 @babel/runtime-corejs3 被支持。

myArrayLikeObject[Symbol.tierator] = Array.prototype[Symbol.iterator];
複製代碼

儘管 @babel/runtime 早期版本不支持實例方法,可是使用一些自定義的幫助函數可以支持迭代([Symbol.iterator]() 和他的presence)。以前不支持提取 [Symbol.iterator] 方法,可是如今支持了。

做爲意外收穫,@babel/runtime 如今支持IE8-,可是有些限制,例如,IE8- 不支持訪問器、模塊轉換應該用鬆散的方式,regenerator-runtime(內部使用 ES5+ 實現)須要經過這個插件轉譯。

暢享將來

作了許多工做,可是 core-js 距離完美還很遠。這個庫和工具未來應該如何改進?語言的變化將會如何影響它?

老的引擎支持

如今,core-js 試圖去支持全部可能的引擎或者咱們可以測試到的平臺:甚至是IE8-,或者例如,早期版本的 Firefox。雖然它對某些用戶有用,可是僅有一小部分使用 core-js 的開發者須要它。對於大多數用戶,它將引發像包體積過大或者執行緩慢的問題。

主要的問題源自於支持 ES3 引擎(首先是 IE8- ):多數現代 ES 特性是基於 ES5,這些功能在老版本瀏覽器中均不可用。

最大的缺失特性是屬性描述符:當它缺失時,一些功能不能 polyfill,由於他們要麼是訪問器(像 RegExp.prototype.flagsURL 屬性的 setters )要麼就是基於訪問器(像 typed array polyfill)。爲了解決這個不足,咱們須要使用不一樣的解決方法(例如,保持 Set.prototype.size 更新)。維護這些解決方法有時很痛苦,移除他們將極大的簡化許多 polyfills。

然而,描述符僅僅是問題的一部分。ES5 標準庫包含了不少其餘特性,他們被認爲是現代 JavaScript 的基礎:Object.createObject.getPrototypeOfArray.prototype.forEachFunction.prototype.bind,等等。和多數現代特性不一樣,core-js 內部依賴他們而且爲了實現一個簡單的現代函數,core-js 須要加載其中一些"建築模塊"的實現。對於想要建立一個足夠小的構建包和僅僅想要引入部分 core-js 的用戶來講,這是個問題。

在一些國家 IE8 仍很流行,可是爲了讓 web 向前發展,瀏覽器到了某些時候就應該消失了。 IE8 在 2009 年 3 月 19 日發佈,到今天已經 10 年了。IE6 已經 18 歲了:幾個月前新版的 core-js 已經再也不測試 IE6 了。

core-js@4 咱們應該捨棄 IE8- 和其餘不知道 ES5 的引擎。

ECMAScript 模塊

core-js 使用 CommonJS 模塊規範。長期以來,他是最受歡迎的 JavaScript 模塊規範,可是如今 ECMAScript 提供了他本身的模塊規範。許多引擎已經支持它了。一些構建工具(像 rollup )基於它,其餘的構建工具提供它做爲 CommonJS 的替代。這意味提供了一個可選擇的使用 ESMAScript 模塊規範版本的 core-js 行得通。

支持 web 標準擴展?

core-js 當前專一在 ECMAScript 支持,可是也支持少許的跨平臺以及和 ECMAScript 緊密聯繫的 web 標準功能。爲 web 標準添加像 fetch 的這種的 polyfill 是受歡迎的功能請求。

core-js 沒有增長他們的主要緣由是,他們將嚴重的增長構建包大小而且將強制 core-js 用戶載入他們可能用不到的功能。如今 core-js 是最大限度的模塊化,用戶可以僅選擇他們須要的功能,這就像 @babel/preset-env@babel/runtime 可以幫助用戶去減小沒用到和沒必要要的 polyfills。

如今是時候從新審視這個決定了?

針對目標環境的 @babel/runtime

目前,咱們不能像對 @babel/preset-env 那樣爲 @babel/runtimne 設置目標加環境。這意味即便目標是現代瀏覽器, @babel/runtime 也將注全部可能的 polyfills:這沒必要要的增長了最終構建包的大小。

如今 core-js-compat 包函所有必要數據,未來,能夠在 @babel/runtime 中添加對目標環境的編譯支持,而且在 @babel/preset-env 中添加 useBuiltIns: runtime 選項。

更好的優化 polyfill 加載

正如上面解釋的,Babel 插件給了咱們不一樣的方式去優化 core-js 的使用,可是他並不完美:咱們能夠改進他們。

經過 useBuiltIns: usage 選項,@babe/preset-env 可以作的比以前更好,可是針對一些不尋常的例子他們仍然會失敗:當代碼不能被靜態分析。針對這個問題,咱們須要爲庫開發者尋找一個方式去肯定哪一種 polyfill 是他們的庫須要的,而不是直接載入他們:某種元數據 -- 將在建立最終構建包時注入 polyfill。

另外一個針對 useBuiltIns: usage 的問題是重複的 polyfills 導入。useBuiltIns: usage 可以在每一個文件中注入許多 core-js 的導入。但若是咱們的項目有數千個文件或者即便十分之一會怎麼樣呢?這種狀況下,與導入 core-js 自身相比,導入 core-js/... 將有更多代碼行:咱們須要一種方式去收集全部的導入到一個文件中,這樣纔可以刪除重複的。

幾乎每個須要支持像 IE11 瀏覽器的 @babel/preset-env 用戶都爲每一個瀏覽器使用同一個構建包。這意味着徹底支持 ES2019 的現代瀏覽器將加載沒必要要的、僅僅是 IE11 須要的 polyfills。固然,咱們能夠爲不一樣的瀏覽器建立不一樣的構建包來使用,例如,type=module / nomodules 屬性:一個構建包給支持模塊化的現代瀏覽器,另外一個給傳統瀏覽器。不幸的是,這不是針對這個問題的完整的解決方案:基於用戶代理打包目標瀏覽器須要的 polyfill 的服務很是有用。咱們已經有了一個 - polyfill-service。儘管頗有趣也很流行,可是 polyfill 的質量還有不少不足。它不像幾年前那麼差:項目團隊積極工做去改變它,可是若是你想用他們匹配原生實現,我不建議你經過這個項目使用 polyfill。許多年前我嘗試經過這個項目將 core-js 做爲 polyfill 的源,可是這不可能。由於 polyfill-service 依賴文件嵌套而不是模塊化(就像 core-js 發佈後的前幾個月 😊)。

像這樣一個集成了一個很棒的 polyfill 源 -- core-js 的服務,經過像 Babel 的 useBuiltIns: usage 選項,靜態分析源代碼真的可以引發咱們對於 polyfill 思考方式的革命。

來自 TC39 的新功能預案和 core-js 可能的問題

TC39 一直在努力工做去改進 ECMAScript:你能夠經過查看 core-js 中實現全部新提案查看進度。然而,我認爲有些新的提案功能在 polyfill 或者轉譯時可能引發嚴重的問題。關於這個足夠能夠寫一篇新的文章,可是我將嘗試在這總結一下個人想法。

標準庫提案,stage 1

如今,TC39 考慮給 ECMAScript 增長內置模塊:一個模塊化的標準庫。它將成爲 JavaScript 的最佳補充,而 core-js 是它能夠被 polyfill 的最佳位置。根據 @babel/preset-env@babel/runtime 用到的技術,理論上咱們能夠經過一種簡單的方式注入內置模塊須要的 polyfill。然而,這個提案的當前版本會致使一些嚴重問題,這些問題並無使其簡單明瞭。

內置模塊的 polyfill,根據做者的提案,僅僅意味着退回到分層 API 或者 導入 maps。這代表若是原生模塊缺失,它將可以經過提供的 url 載入一個polyfill。這絕對不是 polyfill 須要的,而且它與 core-js 的架構以及其餘流行的 polyfill 都不兼容。導入 maps 不該該是 polyfill 內置模塊的惟一方式。

咱們經過一個特定前綴使用 ES 模塊語法就可以獲得內置模塊。這個語法在語言的早期版本並無對等的 - 轉譯模塊不可能在如今瀏覽器中與未轉譯的交互 - 這會致使包分發的問題。

更進一步講,他將異步工做。對於功能檢測這是個嚴重的問題 - 當你要檢測一個功能而且加載 polyfill 時腳本不會等待 - 功能檢測應該同步的作。

在沒有轉譯和 polyfill 的狀況下第一次實現內置模塊。若是沒有修改,在當前的 core-js 格式下內置模塊將不可能 polyfill。建議的 polyfill 方式將使開發變得嚴重複雜。

這個標準庫的問題可以經過添加一個新的全局變量解決(這將是最後一個嗎?):一個內置模塊的註冊表將容許異步的設置和獲取,例如:

StandardLibraryRegistry.get(moduleName);
StandardLibraryRegistry.set(moduleName, value);
複製代碼

異步回調,好比分層API應該全局註冊表以後使用。

值得一提的是,它將簡化將本地模塊導入到老的語法的轉換。

裝飾器提案,新的迭代器語法,stage 2

這個提案中的 新迭代器,他被很認真的重作了。裝飾器定義再也不是語法糖,就像內置模塊,咱們不能在老版本的語言中編寫裝飾器並將其用做原生裝飾器。除此以外,裝飾器不只僅是普通的標識符 - 他們生活在平行的詞彙範圍內:這意味着已經編譯的裝飾器不能喝原生裝飾器交互。

提案做者建議使用未編譯的裝飾器發佈包,讓包的使用者選擇去編譯他們的依賴。然而,在不一樣的狀況下是不可能的。當他們被添加到 JS 標準庫時,這個方法將阻止 core-js polyfill 新的內置裝飾器。

裝飾器應該是在某些東西上應用功能的一種方法,他們應該僅僅是包裹的語法糖。爲何要複雜化呢?


若是引入的一個語言功能不是從根本上是新的,在語言的早期版本什麼不該該實現是能夠選擇的,咱們可以轉譯或者 polyfill 它,被轉譯或者 polyfill 的代碼應該可以和支持這個功能的瀏覽器原生交互。

我但願根據提案做者和委員會的智慧,這些提案可以被採納,這樣纔可以合理的轉譯或者 polyfill 他們。


若是你對 core-js 項目感興趣,或者你在你平常工做中使用它,你能夠成爲 OpenCollective 或者 Patreon 捐贈者。core-js 的背後不是一個公司:他的未來要靠你。


這裏 能夠評論這篇文章。

Denis Pushkarev,2019年3月19日,感謝 Nicolò Ribaudo 編輯。

可能用到的資料

感謝閱讀

感謝你閱讀到這裏,翻譯的很差的地方,還請指點。但願個人內容能讓你受用,再次感謝。by llccing 千里

相關文章
相關標籤/搜索