前端小糾結--babel的配置的默認套路

我是一個標題黨,這篇文章介紹一點babel的默認配置套路,總結了一點遇到的項目管理問題。javascript

babel的bug刺激了我

  • 現象:項目編譯沒有任何問題,打開頁面才報錯 問題現象console報錯:_objectSpread is not defined
  • 緣由:根據輸出的錯誤,我猜想是babel的問題,由於_objectSpread就是使用了新的對象展開的語法...obj,編譯以後纔出現的。固然這裏我也調試了編譯後打代碼。【若是你想看編譯打包後代碼,介紹一篇文章給你: webpack編譯vue項目生成的代碼探索
  • 分析:經過git log快速分析package.json的變動,發現只更新過babel相關。因此實錘是babel問題。

分析git log時,咱們當時作的commit message style統一的做用就發揮出來了,全部的工具鏈相關變動,統一都是chore開頭,因此才能作到快速定位。順便看看咱們項目的commit messagecss

commit message style

真實緣由:對象展開的語法,babel編譯以後注入了_objectSpread或者_objectSpread2函數來處理,維護的小夥伴沒有把全部的分支都覆蓋。修復這個issues的小夥伴也挺幽默,估計也是被折騰的夠嗆,說了一句玩笑話I'll now go hiding myself somewhere and I won't touch an helper for a few months 😆前端

並且此bug是babel v7.5.4修復的,並且在低版本的@babel/core使用了高版本的@babel/plugin-proposal-object-rest-spread才能重現。vue

_objectSpread官方issues相關連接:java

ReferenceError: _objectSpread is not defined after updatenode

Missing helpers only throw oncewebpack

Fix _objectSpread2 for realgit

找的問題的根源了,新問題來了,我怎麼更新@babel/core呢?github

由於不是項目直接依賴的@babel/core,而是其它工具依賴,我更新了也不必定起做用。

介紹npm兩個很是有用的命令:

  • 查看項目中安裝的package版本和依賴關係

    npm ls @babel/core
    `-- @vue/cli-plugin-babel@3.9.2
      `-- @babel/core@7.5.4 
    複製代碼

    知道了依賴@babel/core是@vue/cli-plugin-babel,那升級@vue/cli-plugin-babel就好了。

  • 查看npm倉庫的package版本和依賴

    npm show @babel/core
    複製代碼
  • 推薦一個npm-check工具,專門用來更新依賴。

    npm-check

    能夠執行npm-check -u來進行交互式選擇更新,並且還列出了官方文檔,能夠直接看看release log以後再決定是否更新。

babel的plugin和preset配置默認套路

原本我就比較懶,一直在計劃學習的路上,基本都沒落實行動。此次項目出現問題,我不得不去了解了一下,babel配置的那些套路。Babel的v7版本全部包都重命名了,因此仍是要作到了解。

babel v7

官方升級文檔連接

包含的內容太多,仔細過一遍才行,不少配置或者包名稱命名規則都修改了。

babel v7.4支持core-js@3

babel v7.4支持core-js@3,尤爲是對@babel/polyfill@babel/preset-env又帶來了不少改變。

  • 新的corejs配置項

    corejs配置項連接options corejs

    當項目中的babel升級到v7.4+時會出現下面的警告:

    WARNING: We noticed you're using the useBuiltIns option without declaring a core-js version. Currently, we assume version 2.x when no version is passed. Since this default version will likely change in future versions of Babel, we recommend explicitly setting the core-js version you are using via the corejs option.

    // 使用core-js@3的babel.config.js
    module.exports = function (api) {
        api.cache(true);
    
        const presets =  [
            ["@babel/preset-env",
                {
                "useBuiltIns": "usage",
                "corejs":3, // 指定版本
                "targets":{
                    "browsers":["> 1%", "last 2 versions", "not ie <= 8"]
                    }
                }
            ]
        ];
        return {
            presets,
            // plugins
        };
    }
    複製代碼

    注意: 把相應的core-js安裝到項目依賴中,npm i core-js@2 或者npm i core-js@3

  • @babel/polyfill不支持從core-js2升級到core-js3,因此v7.4開始@babel/polyfill變成過期(deprecated)

    若是項目中使用core-js@3,則應該修改導入配置

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

    替換爲:

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

    直接安裝依賴到項目:

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

由於babel和core-js綁定的很緊密,因此推薦看一下core-js做者的文章:core-js-3-babel-and-a-look-into-the-future詳細介紹了core-js@3版本帶來的改變,以及解決的問題。

Plugin配置套路

syntax plugins容許babel去parse特定的類型的syntax而不是去轉換變形(transform)

注意:transform plugins會自動啓用syntax plugins。 所以,若是已經使用了相應的transform plugins,則無需指定syntax plugins。

Plugin 路徑

若是 plugin 在 npm 上,你能夠傳入預設名稱,babel 將檢查它是否已安裝在 node_modules

{
  "plugins": ["babel-plugin-myPlugin"]
}
複製代碼

還能夠指定的相對/絕對路徑。

{
  "plugins": ["./node_modules/asdf/plugin"]
}
複製代碼

Plugin 簡寫(官方很是不推薦)

若是包的名稱以 babel-plugin- 爲前綴,可使用簡寫:

{
  "plugins": [
    "myPlugin",
    "babel-plugin-myPlugin" // equivalent
  ]
}
複製代碼

這也適用於 scoped 包:

{
  "plugins": [
    "@org/babel-plugin-name",
    "@org/name" // equivalent
  ]
}
複製代碼

Plugin執行順序

若是兩個transforms都訪問「程序」節點,則transforms將以plugin或preset順序運行。

  • plugin在preset以前運行。
  • plugin執行順序是第一個到最後一個。
  • preset順序相反(從最後到第一個)。
{
  "plugins": ["transform-decorators-legacy", "transform-class-properties"]
}
複製代碼

先執行transform-decorators-legacytransform-class-properties

Plugin 選項

plugins和 presets 均可以經過將名稱和選項對象放在配置中的數組中來指定選項。

對於不指定選項,這些都是等同的:

{
  "plugins": ["pluginA", ["pluginA"], ["pluginA", {}]]
}
複製代碼

要指定選項,請使用選項名稱做爲 key 傳遞對象。

{
  "plugins": [
    [
      "transform-async-to-module-method",
      {
        "module": "bluebird",
        "method": "coroutine"
      }
    ]
  ]
}
複製代碼

preset配置套路

preset是一個插件數組

module.exports = function() {
  return {
    plugins: [
      "pluginA",
      "pluginB",
      "pluginC",
    ]
  };
}
複製代碼

Presets 能夠包含其餘的 presets 以及帶有選項的插件。

module.exports = () => ({
  presets: [
    require("@babel/preset-env"),
  ],
  plugins: [
    [require("@babel/plugin-proposal-class-properties"), { loose: true }],
    require("@babel/plugin-proposal-object-rest-spread"),
  ],
});
複製代碼

Preset 路徑

若是 preset 在 npm 上,你能夠傳入預設名稱,babel 將檢查它是否已安裝在 node_modules

{
  "presets": ["babel-preset-myPreset"]
}
複製代碼

還能夠指定 presets 的相對/絕對路徑。

{
  "presets": ["./myProject/myPreset"]
}
複製代碼

Preset 簡寫(官方很是不推薦)

若是包的名稱以 babel-preset- 爲前綴,可使用簡寫:

{
  "presets": [
    "myPreset",
    "babel-preset-myPreset" // 等同
  ]
}
複製代碼

這也適用於 scoped 包:

{
  "presets": [
    "@org/babel-preset-name",
    "@org/name" // 等同
  ]
}
複製代碼
// vue-cli生成的babel.config.js
module.exports = {
  presets: [
    [
      '@vue/app', // 對應 @vue/babel-preset-app,當時害的我找來找去都沒找到包
      {
        useBuiltIns: 'entry',
        corejs: 2, // @see https://babeljs.io/docs/en/babel-preset-env#corejs
      },
    ],
};

複製代碼

Preset執行順序相反

Preset 的順序是相反的(從最後一個到第一個).

{
  "presets": [
    "a",
    "b",
    "c"
  ]
}
複製代碼

將會按照如下順序運行:c, b, 而後 a

Preset 選項

插件和 presets 均可以經過將名稱和選項對象放在配置中的數組中來指定選項。

對於不指定選項,這些都是等同的:

{
  "presets": [
    "presetA",
    ["presetA"],
    ["presetA", {}],
  ]
}
複製代碼

要指定選項,請使用選項名稱做爲 key 傳遞對象。

{
  "presets": [
    ["@babel/preset-env", {
      "loose": true,
      "modules": false
    }]
  ]
}
複製代碼

ant-desgin-vue的依賴加載配置:

module.exports = {
  presets: [
    [
      '@vue/app',
      {
        useBuiltIns: 'entry',
        corejs: 2, // @see https://babeljs.io/docs/en/babel-preset-env#corejs
      },
    ],
  ],
 
  plugins: [
    [ // @see https://github.com/vueComponent/ant-design-vue/issues/193
      'import', // babel-plugin-import
      { libraryName: 'ant-design-vue', libraryDirectory: 'es', style: true },
    ],
  ],
};
複製代碼

總結

前端的知識鏈太長,技術更新愈來愈快。前端的投資風險仍是很大,因此謹慎選擇框架,分配一點時間投資在業界公認的工具上也是不錯的,例如:webpack, babel, vs code, scss等。這些都是現代前端工程的構建工具,因此生命週期會比某一個框架更長遠。

參考

babel-plugin-handbook

babel-user-handbook

強制jest使用新的babel

options corejs

core-js-3-babel-and-a-look-into-the-future

babel-preset-env官方倉庫

npm 經常使用命令詳解

A Beginner’s Guide to npm — the Node Package Manager

關注微信公衆號,發現更多精彩內容

相關文章
相關標籤/搜索