<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] # Babel **[Babel](https://new.babeljs.io/) 主要用于將采用 ECMAScript 2015+ 語法編寫的代碼轉換為向后兼容的 JavaScript 語法,以便能夠運行在當前和舊版本的瀏覽器或其他環境中。** 作用如下: * 語法轉換 * 通過 Polyfill 方式在目標環境中添加缺失的特性(通過第三方 polyfill 模塊,例如 core-js,實現) * 源碼轉換 (codemods) 換而言之就是 Babel 能讓我們現在就使用新的語法,無需等待瀏覽器的支持。 為了命令行執行編譯,你可以安裝`@babel/cli`。不過一般都是靠 webpack 等工具進行自動編譯。 babel 的功能都是通過 plugin 來完成的。每個 plugin 都有特定的代碼處理的功能,只有將它配置到 babel 里面運行,才能對代碼進行轉換。 babel 目前有很多的 plugin,既有官方的,也有第三方的。 在加入 plugins 測試之前我們需要知道一些前置知識,babel 將 ECMAScript 2015+ 版本的代碼分為了兩種情況處理: * syntax(語法層面): let、const、class、arrow function等,這些需要在構建時進行轉譯,是指在**語法層面上的轉譯,babel 是可以直接轉換**的。 * features(api 方法層面):Promise、Set、Map等`ES6+` 標準推出的新特性,babel 不能直接轉換,這些是在全局或者 Object、Array 等的原型上新增的方法,它們可以由相應 ES5 的方式重新定義,即**需要為 Babel 做一些配置,也就是 polyfill 來實現**,polyfill 翻譯成中文就是**墊片**的意思,用來墊平不同瀏覽器環境之前差異。 # 例子 ``` mkdir babel-demo npm init -y touch index.js #?? index.js內容 npm i -D @babel/cli @babel/core npx babel index.js --out-file compiled.js # 編譯成 compiled.js ``` `index.js`內容: ``` const fn = () => { console.log("wens"); }; const p = new Promise((resolve, reject) => { resolve("wens"); }); const list = [1, 2, 3, 4].map(item => item * 2); ``` # 基礎配置 有三種方式對 babel 進行[配置](https://babeljs.io/docs/usage/babelrc/): 1. `.babelrc` 等專用配置文件。 2. `package.json` 中`babel`字段進行配置。 如果你同時使用了這兩種方式,那么`package.json`中的配置將被忽略! *.babelrc*: ```json { "presets": [ [ "@babel/preset-env", { "debug": true, # 查看哪些 API 被 polyfill "useBuiltIns": "usage", "targets": { "ie": 11 } } ], "@babel/preset-typescript" // presets是自下而上執行的 ], "plugins": [ "@babel/proposal-class-properties", "@babel/proposal-object-rest-spread", [ "@babel/plugin-transform-runtime", { "corejs": { "version": 3, // 指定 runtime-corejs 的版本,目前有 2 3 兩個版本 "proposals": true // 使用尚在 提議 階段 ECMAScript 特性的 polyfill }, "helpers": true, "regenerator": true, "useESModules": false } ] ] } ``` *.browserlistrc*: ```json > 0.25% not dead ``` ## 配置項 ### `sourceType:?'unambiguous'` 由于 Babel 默認將文件視為 ES modules,因此通常這些 plugins/presets 將插入`import`語句。插入`import`語句會導致 Webpack 和其他工具將一個文件看作是 ES modules,從而破壞了一個正常的 CommonJS 文件,一般會出現: <b style="color:red">`Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'`</b> 所以最好不要混用`import`and`module.exports`。在默認的 ES module 中,你需要進行更改: ``` // Change this module.exports = foo; // To this export default foo; ``` 如果你確實不能更改文件為 ES module ,那么你需要設置: ~~~ "sourceType": "unambiguous" ~~~ > [打包時遇到Cannot assign to read only property 'exports' of object 'Object'問題的解決方法](https://blog.csdn.net/fjh1997/article/details/88544354) > [issues/3650#issuecomment-397830621](https://github.com/vercel/next.js/issues/3650#issuecomment-397830621) > [options#sourcetype](https://babeljs.io/docs/en/options#sourcetype) ### `comments:?false` > [options#comments](https://babeljs.io/docs/en/options#comments) # @babel/core 包含了核心的轉換邏輯,需要對應的plugins/preset才能發揮作用。 ## @babel/helpers 一系列工具,比如`class`語法的實現就是 helper 提供的。被`@babel/core`依賴。 # @babel/preset-env 官網:https://www.babeljs.cn/docs/babel-preset-env 顧名思義,preset 即**預設插件**,它可以將 ES6 轉換為 ES5,包含了各種可能用到的轉譯工具。**之前的以年份為準的 preset (如:babel-preset-2015)已經廢棄了,現在統一用這個總包**。 同時,babel 已經放棄開發 `stage-*` 包,以后的轉譯組件都只會放進 `@babel/preset-env`包里。 `@babel/preset-env` 對于插件的選擇是基于某些開源項目的,比如[`browserslist`](https://github.com/browserslist/browserslist)、[`compat-table`](https://github.com/kangax/compat-table)以及[`electron-to-chromium`](https://github.com/Kilian/electron-to-chromium),比如常用`.browserslistrc`來設置我們預想滿足的目標運行環境。 接下來說的是`@babel/preset-env`的重要配置。 ## **useBuiltIns** 從其名字來說是“使用內置”,“內置”的什么呢? 從官方看來是“**polyfills(墊片)**”,控制 `@babel/preset-env` 使用何種方式幫我們導入 **polyfill** 的核心,`corejs`是 Babel 使用的內置 polyfills 庫。 它的取值可以是以下三種: ### `false` 默認值,不做任何 polyfil l處理。 ### `entry` 一種入口導入方式, 需要我們在`打包配置入口` 或者 *文件入口*寫入 `import "core-js"` 這樣一串代碼, babel 就會替我們根據當前你所配置的目標瀏覽器(browserslist 配置)來引入所需要的 polyfill。其他多余引入的無論有沒有用到,會全部引入進來,`entry`的覆蓋面積全,打包體積自然就大。 我們先使用`entry`,除此之外我們還指定了 corejs 的版本,然后我們在文件頂部手動引入 polyfill 也就是 core-js: ``` import "core-js/stable"; import "regenerator-runtime/runtime"; const message = "hello world"; ... ``` 然后執行`npm run build`,會發現轉換后的代碼里面引入了所有polyfill,包括我們需要的`Promise`: ``` ... require("core-js/modules/es.object.to-string"); require("core-js/modules/es.object.values"); require("core-js/modules/es.promise"); ... ``` 這樣,我們的代碼就可以在低版本瀏覽器中使用了。 ### `usage` 即 **按需引用**,如果目標瀏覽器不支持需要的 feature,那么就引入 polyfill,不然的話就不引用。由于目前的打包工具越發智能,隨著 tree shaking 的完善,這樣可以最低限度引入 polyfill。但是對第三方依賴包無效,常用來在開發第三方庫時使用,因為開發者無法控制庫的瀏覽器運行環境。 ### `corejs` `corejs`只在`useBuiltIns`取值為`entry`或`usage`的時候有用,因為 Babel 內置的 polyfills 就是 `core-js`。 先安裝 corejs 的版本,可以配置為`2`或`3`: ~~~shell npm i -S core-js@3 ~~~ ``` { "presets": [ [ "@babel/preset-env", { "targets": "> 5%", "useBuiltIns": "usage", "corejs": 3 } ] ] } ``` 絕大部分情況,推薦使用 `@babel/preset-env + useBuiltIns: 'usage'` 這種方式。 這種方式打包體積不大,但是如果我們排除`node_modules`目錄,遇上沒有經過轉譯的第三方包,就檢測不到第三方包內部的 `'hello'.includes('h')`這種語法,這時候我們就會遇到 bug(這種情況可以使用,參考本文中的`@babel/plugin-transform-runtime`)。 # `core-js@2`和`core-js@3` **[core-js](https://github.com/zloirock/core-js) 是一個 JavaScript 的模塊化標準庫。包括 ECMAScript 到 2021 年的 polyfill。** `core-js@2`分支中不包含一些最新的實例方法特性,新特性都會添加到 `core-js@3`,現在 2 版本被廢棄使用。例如:`core-js@2`不包含 `Array.prototype.flat()`。 由于`core-js@2`版本包的體積太大(~2M),并且有很多重復的文件被引用。`core-js@3`對包進行拆分,三個核心的包分別是: * [core-js](https://github.com/zloirock/core-js/tree/master/packages/core-js):定義全局的 polyfill(~500k, 40k minified and gzipped) * [core-js-pure](https://github.com/zloirock/core-js/tree/master/packages/core-js-pure):提供不污染全局環境的 polyfill,等價于 core-js@2/library(~440k) * [core-js-compat](https://github.com/zloirock/core-js/tree/master/packages/core-js-compat):包含了 core-js 模塊和 API 必要的數據,通過 browserslist 來生成所需要的 core-js 模塊的列表 對于`core-js@3`的入口文件,我們可以這樣使用: ~~~js // polyfill all `core-js` features: import "core-js"; // polyfill only stable `core-js` features - ES and web standards: import "core-js/stable"; // polyfill only stable ES features: import "core-js/es"; // if you want to polyfill `Set`: // all `Set`-related features, with ES proposals: import "core-js/features/set"; // stable required for `Set` ES features and features from web standards // (DOM collections iterator in this case): import "core-js/stable/set"; // only stable ES features required for `Set`: import "core-js/es/set"; // the same without global namespace pollution: import Set from "core-js-pure/features/set"; import Set from "core-js-pure/stable/set"; import Set from "core-js-pure/es/set"; // if you want to polyfill just required methods: import "core-js/features/set/intersection"; import "core-js/stable/queue-microtask"; import "core-js/es/array/from"; ~~~ 我們還可以使用`core-js-compat`用來提供目標引擎所需要的core-js的模塊信息: ~~~js const { list, // array of required modules targets, // object with targets for each module } = require('core-js-compat')({ targets: '> 2.5%', // browserslist query filter: 'es.', // optional filter - string-prefix, regexp or list of modules }); console.log(targets); ~~~ # babel 的 polyfill 包 ## `@babel/polyfill` **在 babel v7.4.0 版本中已經明確表示不推薦使用**,官方建議我們使用`core-js`來替代。 如果使用導入`@babel/polyfill`的方式的話,現在會報錯了: > `@babel/polyfill` is deprecated. Please, use required parts of `core-js` and `regenerator-runtime/runtime` separately `@babel/polyfill`內部就是引用`core-js`、`regenerator-runtime`這兩個包。從而完整的模擬`ES2015+`環境。 ----------- **通過向全局對象和內置對象的`prototype`上添加方法來實現**,比如目標運行環境中不支持 `Array.prototype.find`,引入polyfill,前端就可以放心的在代碼里用 ES6 的語法來寫; ----------- `@babel/polyfill`沒有提供從`core-js@2`到`core-js@3`平滑升級路徑:因為該原因,**決定棄用`@babel/polyfill`代之以分別引入需要的`core-js`和`regenerator-runtime`**。 `core-js@3`中等價替換`@babel/polyfill`是: ``` import "core-js/stable"; import "regenerator-runtime/runtime"; ``` 這里的`core-js`不一定要導入stable,具體視項目而定,點擊[這里](https://github.com/zloirock/core-js#commonjs-api)可以查看更多的`core-js`模式。 ## `@babel/plugin-transform-runtime` 官網:[@babel/plugin-transform-runtime](https://github.com/babel/website/blob/main/docs/plugin-transform-runtime.md) 它將開發者依賴的全局內置對象等,抽取成單獨的模塊,并通過模塊導入的方式引入,避免了對全局作用域的修改(污染)。 1. babel 在轉碼過程中,會加入很多 babe l自己的 helper 函數,這些 helper 函數,在每個文件里可能都會重復存在,transform-runtime 插件可以把這些重復的 helper 函數,轉換成公共的、單獨的依賴引入,從而節省轉碼后的文件大小。 2. transform-runtime 可以幫助這種項目創建一個沙盒環境,即使在代碼里用到了新的 ES 特性,它能將這些特性對應的全局變量,轉換為對 core-js 和 regenerator-runtime 非全局變量版本的引用。這其實也應該看作是一種給代碼提供 polyfill 的方式。 Important to note here is that`@babel/preset-env`**respects your targets**, and doesn't include unnecessary pollyfills, * > **注意**:`@babel/preset-env`會識別`.browserslistrc`,不包含不必要的 polyfills;而`@babel/transform-runtime`不識別`.browserslistrc`,會包含所有可填充的特性,這會導致許多不必要的膩子填充。 ### 是2還是3 `@babel/plugin-transform-runtime` 就是一個工具庫,默認使用`@babel/runtime` 提供的幫助函數(helpers)進行模塊隔離(即`corejs: false`)。如果想啟用`transform-runtime`對`core-js`的 polyfill 的話,就得使用`@babel/runtime`另外的兩個版本: * core-js@2 對應的`@babel/runtime`版本是:`@babel/runtime-corejs2`; * core-js@3 對應的`@babel/runtime`版本是:`@babel/runtime-corejs3`。 | `corejs`option | Install command | | --- | --- | | `false` | `npm install --save @babel/runtime` | | `2` | `npm install --save @babel/runtime-corejs2` | | `3` | `npm install --save @babel/runtime-corejs3` | > [babel-plugin-transform-runtime#corejs](https://babeljs.io/docs/en/babel-plugin-transform-runtime#corejs) ### 使用 ``` npm i @babel/runtime-corejs3 npm i -D @babel/plugin-transform-runtime ``` `@babel/runtime-corejs3`是一個核心, 一種實現方式,在局部文件中以模塊化引用的形式導入,不會污染全局變量;而 `@babel/plugin-transform-runtime` 負責更好的重復使用`@babel/runtime-corejs3`。兩個包是一起使用的。 ``` // webpack.config.js module.exports = { presets: ["@babel/env"], plugins: [ [ "@babel/plugin-transform-runtime", { corejs: { version: 3 } // 指定 runtime-corejs 的版本,目前有 2 3 兩個版本 } ] ] }; ``` 去掉了`@babel/env`的相關參數,而給`@babel/plugin-transform-runtime`添加了`corejs`參數,最終轉換后的文件不會再出現 polyfill 的`require`的方法了。解決轉譯 api 層出現的**全局變量污染**。 主要是為了解決轉換之后代碼重復使用而造成的包體積較大的問題,因為 babel 在轉換代碼時會使用一些 helpers 輔助函數,比如下面的代碼: ``` class Person { constructor(name) { this.name = name; } say() { console.log(this.name); } } ``` 轉換之后,我們會發現生成的代碼除了一些 polyfill 和實際的代碼之外,還有一些 helpers 代碼: ~~~ ... "use strict"; var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault"); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass")); ... ~~~ 如果有很多文件需要轉換,那這些代碼可能就會重復,為了解決這個問題,我們可以使用`@babel/plugin-transform-runtime`將這些helpers輔助函數的使用方式改為引用的方式,讓它們都去引用`@babel/runtime`包里的代碼,這樣他們就是重復引用同一個代碼,避免了內容上的重復,以節省代碼的冗余,從而減小了程序包的體積。其中`@babel/runtime`這個包里面就包含了所有的 helpers 輔助函數。 `useBuiltIns`的`entry` 和 `@babel/runtime` 不要同時使用,會產生各種幫助函數還引入了許多 polyfill,導致包體積增大! > [@babel/preset-env 與@babel/plugin-transform-runtime 使用及場景區別](https://segmentfault.com/a/1190000021188054) ## `@babel/runtime` Babel modular runtime helpers(Babel模塊化運行時助手); 源碼包含兩個文件夾: * helpers(定義了一些處理新的語法關鍵字的幫助函數 * regenerator(`regenerator-runtime`包的一個版本)。 它只是包含模塊化方式導出了一系列函數的包。 舉例: ```js class Circle {} // ------------轉譯后------------------ function _classCallCheck(instance, Constructor) { //... } var Circle = function Circle() { _classCallCheck(this, Circle); }; ``` babel通常會對這類代碼進行轉譯,`_classCallCheck`會被多次生成,這樣就很不好,所有我們還需要借用`@babel/plugin-transform-runtime`變為從`@babel/runtime`導入的方式: ```js var _classCallCheck = require("@babel/runtime/helpers/classCallCheck"); var Circle = function Circle() { _classCallCheck(this, Circle); }; ``` ## `@babel/runtime-corejs2` [@babel/runtime-corejs2 · Babel 中文網](https://www.babeljs.cn/docs/babel-runtime-corejs2) ## `@babel/runtime-corejs3` 源碼包含四個文件夾: * core-js(引用`core-js`這個包) * core-js-stable(引用`core-js`這個包) * helpers(定義了一些處理新的語法關鍵字的幫助函數) * regenerator(僅僅是引用`regenerator-runtime`這個包) —————————————————————————————— 可以看出,`@babel/runtime-corejs3 ≈ @babel/runtime + @babel/polyfill`: `@babel/runtime`只能處理語法關鍵字,而`@babel/runtime-corejs3`還能處理新的全局變量(例如,`Promise`)、新的原生方法(例如,`String.padStart` ); 使用了`@babel/runtime-corejs3`,就無需再使用`@babel/runtime`了。 因此,該插件可以代替 polyfill,將`Promise`或`Symbol`轉換為引用`core-js`庫里的函數,但不能對內置對象的實例方法進行轉換。 ```js Promise // ------轉換為:------ var _Promise = require("@babel/runtime-corejs3/core-js/promise.js"); ``` > [core-js@3, babel展望未來](https://juejin.im/post/5e355be0f265da3e491a53c5#heading-15) # @babel/preset-typescript 只做語法的轉換,不做類型檢查,因為類型檢查的任務可以交給 IDE (或者用 `tsc`)去做。 # 小結 Babel 負責兩件事: 1)語法轉換,由各種 transform 插件、helpers 完成; 2)對于可*polyfill*的 API 的提供,由 `corejs` 實現。 已經在 `@babel/preset-env` 中配置了polyfill,那么你連 `@babel/plugin-transform-runtime` 都是不必要的(他們二者都可以提供ES 新 API 的墊片,在這一項功能上是重復的。 `@babel/preset-env` 除了提供 polyfill 墊片,還提供 ES 新語法的轉譯,這一點 `@babel/plugin-transform-runtime` 做不了;`@babel/preset-env` 提供的 polyfill 墊片會污染原型鏈,這個既是缺點,也是優點,缺點是在開發第三方 JS 庫時不能這么干,會影響使用方的代碼。 ## 情況選擇 * 如果你是應用開發(一般我們都不是開發工具庫,只是使用一些前端框架做業務~),推薦使用`@babel/preset-env`搭配 `useBuiltIns` 并按規則導入 polyfill 即可,而無需再使用`@babel/plugin-transform-runtime`,參考[issues]https://github.com/babel/babel/issues/10008"),,一勞永逸,不必使用 `@babel/plugin-transform-runtime`。 * 如果是框架/庫開發,需要安裝`@babel/runtime`、`@babel/plugin-transform-runtime`,同時使用 `@babel/preset-env` 去轉譯語法,但不用它的 polyfill(如前面推薦的那樣去配置即可)。 # issues > [Using @babel/runtime-corejs2 and @babel/runtime-corejs3 leads to larger bundle sizes](https://github.com/babel/babel/issues/9853) > [regeneratorRuntime error with 'external' helpers](https://github.com/rollup/plugins/issues/356#issuecomment-626398978) # 參考 > [從零開始配置Babel](https://juejin.cn/post/6844904090833518600#heading-10) > [用了babel還需要polyfill嗎??](https://juejin.cn/post/6845166891015602190) > [jamiebuilds/babel-handbook](https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/user-handbook.md) > [Babel 7 下配置 TypeScript 支持](https://zhuanlan.zhihu.com/p/102250469) > [折騰 @babel/preset-env](https://blog.meathill.com/js/some-tips-of-babel-preset-env-config.html) > [babel詳解](https://blog.liuyunzhuge.com/2019/09/02/babel%E8%AF%A6%E8%A7%A3%EF%BC%88%E5%9B%9B%EF%BC%89-core-js/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看