es6基礎0x024:babel簡單使用

0x001 polyfill

咱們都知道,js老是一直存在着兼容性問題,雖然其餘語言也存在着兼容性問題,好比c++java,但那種兼容性是新特性在舊版本上的不兼容,js則存在着各類奇形怪哉的不兼容。這其中有着很是複雜的歷史和時代的緣由,並不加以累述。而解決兼容性問題的方法在之前只存在一種,那就是polyfill。先說什麼是polyfill,好比咱們想要用數組的一個新的方法includes,在較新版本的瀏覽器下,能夠直接使用:前端

clipboard.png

可是在舊的瀏覽器下,好比ie10,就會報錯:java

clipboard.png

這種狀況下咱們能夠經過自定義一個方法來解決:react

function includesPolyfill(){
    if(!Array.prototype.includes){
        Array.prototype.includes=function(element){
              for(var i=0; i<this.length; i++){
                  if(this[i]===element)return true
              }
              return false
        }
    }
}

這裏定義一個簡單的方法,添加到Array.prototype上,爲了簡單,並無作太多的異常檢測,接着在代碼中引入以上方法並優先執行,就能夠作到在不兼容這個方法的js環境總直接調用Array.protorype.includes方法了:webpack

clipboard.png
這就是polyfill,可是polyfill有其侷限性,對於能夠用舊的方法實現的新特性,可使用polyfill來解決,好比Array.prototype.includes,可是,對於一些沒法使用舊方法實現的新特性、新語法,好比箭頭函數const之類的,polyfill就無能爲力了,這個時候須要使用另外一種方法:預編譯,或者說是語法轉換c++

0x002 預編譯

在以前的js開發中,是沒有預編譯這個流程的,擼完js就直接部署了,可是隨着前端工程化的推動,預編譯也就出現了,特別是typescript之類的語言出現之後,編碼和發佈就再也不是同一種方式了。es6

如今在發佈以前,老是須要打包,而打包有許多的流程,好比資源整合、代碼優化、壓縮混淆...而在其中對代碼的操做上,咱們能夠將新的語法轉化成舊的語法來達到對新語法的支持。web

簡單的說就是,新語法->編譯器->舊語法typescript

編譯器的做用就是將輸入的源碼中的新特性轉化成就語法,說白了就是字符串處理,好比對箭頭函數的處理:var add=(num1, num2)=>num1+num2,這段代碼在不兼容箭頭函數的環境中,好比ie10,是沒法執行的npm

clipboard.png
可是咱們能夠經過語法轉化、編譯處理,將源碼轉化成var add=function(num1, num2){return num1+num2},這樣在不支持箭頭函數的瀏覽器中就能夠執行了json

clipboard.png

如今來實現一個簡單的編譯器,固然只支持箭頭函數

function translate(src){
    let [_, name, args, body]=src.match(/\((.+)\)=>(.+)/)
    return `function ${name}(${args}){return ${body}}`
}

爲了簡單,只是使用簡單的正則提取來作實驗,而且不作任何異常處理

translate('var add=(num1, num2)=>num1+num')
//  var add=function(num1, num2){return num1+num2}

將轉化結果保存成文件,就能夠在不兼容箭頭語法的環境中使用了。甚至咱們能夠在瀏覽器中嵌入這個編譯器,將源碼編譯以後使用Function構造函數或者eval來執行,達到執行新語法的做用,這種狀況下,稱爲運行時編譯器,固然通常不會這麼用。

0x003 使用babel

很明顯,不可能本身寫這麼一個編譯器,那還要不要作項目了?這時候只能藉助社區的力量了,babel就是這麼一個東西,接下來將會使用babel來解析箭頭函數

  • 初始化一個項目

    $ mk babel-demo 
    $ cd babel-demo
    $ npm init -y
  • 安裝babel
    注意:(babel7之後babel相關的庫基本都是放在@babel命名空間下)

    $ npm install --save-dev @babel/core @babel/cli @babel/plugin-transform-arrow-functions
    • @babel/core:核心庫
    • @babel/cli:命令行工具
    • @babel/plugin-transform-arrow-functions:箭頭函數語法轉化插件
  • 編寫代碼:

    var add=(num1, num2)=>num1+num2
  • 使用babel解析

    $ npx babel --plugins @babel/plugin-transform-arrow-functions index.js -o bundle.js

    上面命令的意思是將index.js使用babel轉化,並將結果放到bundle.js中,執行以後,將會生成bundle

    • --plugins:爲此次轉化添加插件支持
    • -o:輸出文件
  • 查看轉化結果
    查看新生成的bundle.js,能夠發現,箭頭函數被轉化成了普通的funciton, 在任何環境中都支持。

    var add = function (num1, num2) {
      return num1 + num2;
    };
  • 說明
    因此,對於新特性,咱們能夠經過使用polyfill,也能夠經過語法轉化來達到兼容。

0x004 babel配置文件

很明顯,使用babel cli的侷限性很大,容易出錯、不直觀、繁瑣等,因此babel仍是支持配置文件的方式:

  • .babelrc方式

    • 在項目新建.babelrc文件,並使用JSON語法配置

      {
        "presets": [...],
        "plugins": [...]
      }
    • 直接寫在package.jsonbabel節點

      {
        "name": "my-package",
        "version": "1.0.0",
        "babel": {
          "presets": [ ... ],
          "plugins": [ ... ],
        }
      }
  • babel.config.js方式

    module.exports = function () {
      const presets = [ ... ];
      const plugins = [ ... ];
    
      return {
        presets,
        plugins
      };
    }

兩種方式大同小異,區別就是一個是動態的,一個是靜態的,推薦小項目就用.babelrc,大項目就使用babel.config.js

0x005 babel配置之plugin

pluginbabel中很重要的概念,能夠說,plugin纔是構成babel擴展性的核心,各類各樣的plugin構成了babel的生態,能夠在這裏看一些babel的插件列表。

.babelrc配置文件中配置插件

{
    "plugins": ["@babel/plugin-transform-arrow-functions"]
}

這時候咱們再執行npx babel index.js -o bundle.js,就能夠不指定plugin也能正常轉化箭頭函數了
若是一個plugin能夠配置參數,則能夠這麼配置:

{
  "plugins": [
    ["@babel/plugin-transform-arrow-functions", { "spec": true }]
  ]
}

0x006 babel配置之preset

在一個項目中,咱們老是要配置一大堆的插件,這個時候,就是preset出馬的時候了,那什麼是preset呢?其實就是預置插件列表了,引入了一個preset就包含了一個系列的plugin
好比preset-react就包含了如下插件:

  • @babel/plugin-syntax-jsx
  • @babel/plugin-transform-react-jsx
  • @babel/plugin-transform-react-display-name
  • .babelrc配置preset-react

    {
      "presets": ["@babel/preset-react"]
    }
  • 若是有配置項,就醬:

    {
      "presets": [
        [
          "@babel/preset-react",
          {
            "pragma": "dom", // default pragma is React.createElement
            "pragmaFrag": "DomFrag", // default is React.Fragment
            "throwIfNamespace": false // defaults to true
          }
        ]
      ]
    }

0x007 babel和webpack

  • 添加webpack.config.js

    const path=requrie('path')
    module.exports={
        entry:path.resolve(__dirname, 'index.js'),
        output:{
            path: path.resolve(__dirname, 'dist'),
            filename:'bundle.js'
        },
        module: {
            rules: [
              { test: /\.js$/, use: 'babel-loader' }
            ]
          }
- 添加相關依賴
$ npm install --save-dev webpack webpack-cli babel-loader
```
- `webpack`:`webpack`核心庫
- `webpack-cli`:`webpack`命令行工具
- `babel-loader`:`babel`的`webpack loader`
  • 打包

    $ npm webpack
  • 查看編譯結果
    省略無關的東西,能夠看到,箭頭函數也被轉化成了function

    /***/ "./index.js":
    /*!******************!*\
      !*** ./index.js ***!
      \******************/
    /*! no static exports found */
    /***/ (function(module, exports) {
    
    eval("let add = function (num1, num2) {\n  return num1 + num2;\n};\n\nmodule.exports = add;\n\n//# sourceURL=webpack:///./index.js?");
    
    /***/ })
    
    /******/ });

0x008 支持es6

支持es6可使用@babel/present-env來代替一系列的東西,還有許多的配置像,好比兼容的瀏覽器版本,具體能夠看這裏

  • 安裝依賴包

    $ npm install --save-dev @babel/preset-env
  • 配置

    {
        "plugins": ["@babel/present-env"]
    }
  • 打包

    $ npm webpack
  • 查看效果

    /***/ "./index.js":
    /*!******************!*\
      !*** ./index.js ***!
      \******************/
    /*! no static exports found */
    /***/ (function(module, exports) {
    
    eval("let add = function (num1, num2) {\n  return num1 + num2;\n};\n\nmodule.exports = add;\n\n//# sourceURL=webpack:///./index.js?");
    
    /***/ })
    
    /******/ });

0x009 總結

這只是babel功能的一個小覽,瞭解一下babel的基本使用和一些概念而已。

相關文章
相關標籤/搜索