六贡未、Babel的深入解析

1 為什么需要babel种樱?

事實(shí)上,在開發(fā)中我們很少直接去接觸babel俊卤,但是babel對(duì)于前端開發(fā)來說嫩挤,目前是不可缺少的一部分。原因如下:

  • 開發(fā)中消恍,我們想要使用ES6+的語法岂昭,想要使用TypeScript,開發(fā)React項(xiàng)目狠怨,它們都是離不開Babel的
  • 學(xué)習(xí)Babel對(duì)于我們理解代碼從編寫到線上的轉(zhuǎn)變過程直觀重要
  • 了解真相惧磺,你才能獲得真知的自由

那么反璃,Babel到底是什么呢么夫?
Babel是一個(gè)工具鏈沸枯,主要用于舊瀏覽器或者緩解中將ECMAScript 2015+代碼轉(zhuǎn)換為向后兼容版本的JavaScript无宿。包括:語法轉(zhuǎn)換茵汰、源代碼轉(zhuǎn)換、Polyfill實(shí)現(xiàn)目標(biāo)緩解缺少的功能等孽鸡。

2 Babel命令行使用

babel本身可以作為一個(gè)獨(dú)立的工具(和postcss一樣)蹂午,不和webpack等構(gòu)建工具配置來單獨(dú)使用栏豺。如果我們希望在命令行嘗試使用babel,需要安裝如下庫:

yarn add @babel/cli @babel/core -D
  • @babel/core:babel的核心代碼豆胸,必須安裝
  • @babel/cli:可以讓我們?cè)诿钚惺褂胋abe

使用babel來處理我們的源代碼:

npx babel src --out-dir dist

src:源文件的目錄奥洼。
--out-dir:指定要輸出的文件夾dist。

2.1 插件的使用

比如我們需要轉(zhuǎn)換箭頭函數(shù)晚胡,那么我們就可以使用箭頭函數(shù)轉(zhuǎn)換相關(guān)的插件

yarn add  @babel/plugin-transform-arrow-functions -D
npx babel src --out-dir dist --plugins=@babel/plugin-transform-arrow-functions

const轉(zhuǎn)成 var:

yarn add  @babel/plugin-transform-block-scoping -D 
npx babel src --out-dir dist --plugins=@babel/plugin-transform-block-scoping
,@babel/plugin-transform-arrow-functions

2.3 Babel的預(yù)設(shè)preset

但是如果要轉(zhuǎn)換的內(nèi)容過多灵奖,一個(gè)個(gè)設(shè)置是比較麻煩的,我們可以使用預(yù)設(shè)(preset)估盘,后面我們?cè)倬唧w來講預(yù)設(shè)代表的含義瓷患。

yarn add @babel/preset-env -D
npx babel src --out-dir dist --presets=@babel/preset-env

3 Babel的底層原理

babel是如何做到將我們的一段代碼(ES6、TypeScript遣妥、React)轉(zhuǎn)成另外一段代碼(ES5)的呢擅编?
從一種源代碼(原生語言)轉(zhuǎn)換成另一種源代碼(目標(biāo)語言),這是什么的工作呢箫踩?
就是編譯器爱态,事實(shí)上我們可以將babel看成就是一個(gè)編譯器。Babel編譯器的作用就是將我們的源代碼境钟,轉(zhuǎn)換成瀏覽器可以直接識(shí)別的另外一段源代碼锦担。

3.1 babel編譯器執(zhí)行原理

Babel的執(zhí)行階段:


image.png

當(dāng)然,這只是一個(gè)簡化版的編譯器工具流程吱韭,在每個(gè)階段又會(huì)有自己具體的工作:


image.png

以下面代碼為例:

const name = "coderwhy";
const foo = (name) => console.log(name);
foo(name);

首先吆豹,babel通過此法分析生成tokens數(shù)組,生成結(jié)構(gòu)如下:

[
  {
      "type": "Keyword",
      "value": "const"
  },
  {
      "type": "Identifier",
      "value": "foo"
  },
  {
      "type": "Punctuator",
      "value": "="
  },
  {
      "type": "Punctuator",
      "value": "("
  },
  {
      "type": "Identifier",
      "value": "name"
  },
  {
      "type": "Punctuator",
      "value": ")"
  },
  {
      "type": "Punctuator",
      "value": "=>"
  },
  {
      "type": "Identifier",
      "value": "console"
  },
  {
      "type": "Punctuator",
      "value": "."
  },
  {
      "type": "Identifier",
      "value": "log"
  },
  {
      "type": "Punctuator",
      "value": "("
  },
  {
      "type": "Identifier",
      "value": "name"
  },
  {
      "type": "Punctuator",
      "value": ")"
  },
  {
      "type": "Punctuator",
      "value": ";"
  },
  {
      "type": "Identifier",
      "value": "foo"
  },
  {
      "type": "Punctuator",
      "value": "("
  },
  {
      "type": "String",
      "value": "\"coderwhy\""
  },
  {
      "type": "Punctuator",
      "value": ")"
  },
  {
      "type": "Punctuator",
      "value": ";"
  }
]

其次理盆,babel通過語法分析(parsing)生成AST(抽象語法樹):

{
  "type": "Program",
  "body": [
    {
      "type": "VariableDeclaration",
      "declarations": [
        {
          "type": "VariableDeclarator",
          "id": {
            "type": "Identifier",
            "name": "foo"
          },
          "init": {
            "type": "ArrowFunctionExpression",
            "id": null,
            "params": [
              {
                "type": "Identifier",
                "name": "name"
              }
            ],
            "body": {
              "type": "CallExpression",
              "callee": {
                "type": "MemberExpression",
                "computed": false,
                "object": {
                  "type": "Identifier",
                  "name": "console"
                },
                "property": {
                  "type": "Identifier",
                  "name": "log"
                }
              },
              "arguments": [
                {
                  "type": "Identifier",
                  "name": "name"
                }
              ]
            },
            "generator": false,
            "expression": true,
            "async": false
          }
        }
      ],
      "kind": "const"
    },
    {
      "type": "ExpressionStatement",
      "expression": {
        "type": "CallExpression",
        "callee": {
          "type": "Identifier",
          "name": "foo"
        },
        "arguments": [
          {
            "type": "Literal",
            "value": "coderwhy",
            "raw": "\"coderwhy\""
          }
        ]
      }
    }
  ],
  "sourceType": "script"
}

接著痘煤,babel遍歷AST后進(jìn)行訪問操作,并通過相應(yīng)的插件轉(zhuǎn)成新的AST:

{
  "type": "Program",
  "body": [
    {
      "type": "VariableDeclaration",
      "declarations": [
        {
          "type": "VariableDeclarator",
          "id": {
            "type": "Identifier",
            "name": "foo"
          },
          "init": {
            "type": "FunctionExpression",
            "id": {
              "type": "Identifier",
              "name": "foo"
            },
            "params": [
              {
                "type": "Identifier",
                "name": "name"
              }
            ],
            "body": {
              "type": "BlockStatement",
              "body": [
                {
                  "type": "ReturnStatement",
                  "argument": {
                    "type": "CallExpression",
                    "callee": {
                      "type": "MemberExpression",
                      "computed": false,
                      "object": {
                        "type": "Identifier",
                        "name": "console"
                      },
                      "property": {
                        "type": "Identifier",
                        "name": "log"
                      }
                    },
                    "arguments": [
                      {
                        "type": "Identifier",
                        "name": "name"
                      }
                    ]
                  }
                }
              ]
            },
            "generator": false,
            "expression": false,
            "async": false
          }
        }
      ],
      "kind": "var"
    },
    {
      "type": "ExpressionStatement",
      "expression": {
        "type": "CallExpression",
        "callee": {
          "type": "Identifier",
          "name": "foo"
        },
        "arguments": [
          {
            "type": "Literal",
            "value": "coderwhy",
            "raw": "\"coderwhy\""
          }
        ]
      }
    }
  ],
  "sourceType": "script"
}

最后生成目標(biāo)代碼啦:

var name = "coderwhy";

var foo = function foo(name) {
  return console.log(name);
};

foo(name);

4. webpack使用babel

4.1 babel-loader

在實(shí)際開發(fā)中猿规,我們通常會(huì)在構(gòu)建工具中通過配置babel來對(duì)其進(jìn)行使用的衷快,比如在webpack中。
那么我們就需要去安裝相關(guān)的依賴:

  • 如果之前已經(jīng)安裝了@babel/core姨俩,那么這里不需要再次安裝蘸拔;
yarn add  babel-loader @babel/core -D

我們可以設(shè)置一個(gè)規(guī)則,在加載js文件時(shí)环葵,使用我們的babel:
webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  }
}

4.2 指定使用的插件

我們必須指定使用的插件才會(huì)生效:
webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        use: {
          loader: 'babel-loader',
          options: {
            plugins: [
              '@babel/plugin-transform-arrow-functions',
              '@babel/plugin-transform-block-scoping'
            ]
          }
        }
      }
    ]
  }
}

4.3 babel-preset

如果我們一個(gè)個(gè)去安裝使用插件调窍,那么需要手動(dòng)來管理大量的babel插件,我們可以直接給webpack提供一個(gè)preset张遭,webpack會(huì)根據(jù)我們的預(yù)設(shè)來加載對(duì)應(yīng)的插件列表邓萨,并且將其傳遞給babel。
安裝preset-env:

yarn add @babel/preset-env -D

配置:
webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env'
            ]
          }
        }
      }
    ]
  }
}

4.4 設(shè)置目標(biāo)瀏覽器 browserslist

我們最終打包的JavaScript代碼,是需要跑在目標(biāo)瀏覽器上的缔恳,那么如何告知babel我們的目標(biāo)瀏覽器呢宝剖?

  • browserslist工具,之前在postcss已經(jīng)配置過了歉甚。
  • target屬性
module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ['@babel/preset-env', {
                targets: 'chrome 87'
              }]
            ]
          }
        }
      }
    ]
  }
}

target的優(yōu)先級(jí)高于browserslist万细,也就是說,當(dāng)設(shè)置target后纸泄,browserlist的配置會(huì)失效赖钞。但我們開發(fā)中推薦在browserlist里配置,這樣能和postcss同步刃滓。

4.5 Stage-X的preset

要了解Stage-X仁烹,我們需要先了解一下TC39的組織:

  • TC39是指技術(shù)委員會(huì)(Technical Committee)第 39 號(hào);
  • 它是 ECMA 的一部分咧虎,ECMA 是 “ECMAScript” 規(guī)范下的 JavaScript 語言標(biāo)準(zhǔn)化的機(jī)構(gòu)卓缰;
  • ECMAScript 規(guī)范定義了 JavaScript 如何一步一步的進(jìn)化、發(fā)展砰诵;

TC39 遵循的原則是:分階段加入不同的語言特性征唬,新流程涉及四個(gè)不同的 Stage:

  • Stage 0:strawman(稻草人),任何尚未提交作為正式提案的討論茁彭、想法變更或者補(bǔ)充都被認(rèn)為是第 0 階段的"稻草人"总寒;
  • Stage 1:proposal(提議),提案已經(jīng)被正式化理肺,并期望解決此問題摄闸,還需要觀察與其他提案的相互影響;
  • Stage 2:draft(草稿)妹萨,Stage 2 的提案應(yīng)提供規(guī)范初稿年枕、草稿。此時(shí)乎完,語言的實(shí)現(xiàn)者開始觀察 runtime 的具體實(shí)現(xiàn)是否合理熏兄;
  • Stage 3:candidate(候補(bǔ)),Stage 3 提案是建議的候選提案树姨。在這個(gè)高級(jí)階段摩桶,規(guī)范的編輯人員和評(píng)審人員必須在最終規(guī)范上簽字。Stage 3 的提案不會(huì)有太大的改變帽揪,在對(duì)外發(fā)布之前只是修正一些問題硝清;
  • Stage 4:finished(完成),進(jìn)入 Stage 4 的提案將包含在 ECMAScript 的下一個(gè)修訂版中转晰;

4.1.1 Babel的Stage-X設(shè)置

在babel7之前(比如babel6中)芦拿,我們會(huì)經(jīng)忱危看到這種設(shè)置方式:

  • 它表達(dá)的含義是使用對(duì)應(yīng)的 babel-preset-stage-x 預(yù)設(shè)
  • 但是從babel7開始,已經(jīng)不建議使用了防嗡,建議使用preset-env來設(shè)置;
image.png

5 Babel的配置文件

像之前一樣侠坎,我們可以將babel的配置信息放到一個(gè)獨(dú)立的文件中蚁趁,babel給我們提供了兩種配置文件的編寫:

  • babel.config.json(或者.js,.cjs实胸,.mjs)文件他嫡;
  • .babelrc.json(或者.babelrc,.js庐完,.cjs钢属,.mjs)文件;

它們兩個(gè)有什么區(qū)別呢门躯?目前很多的項(xiàng)目都采用了多包管理的方式(babel本身淆党、element-plus、umi等)讶凉;

  • .babelrc.json:早期使用較多的配置方式染乌,但是對(duì)于配置Monorepos項(xiàng)目是比較麻煩的;
  • babel.config.json(babel7):可以直接作用于Monorepos項(xiàng)目的子包懂讯,更加推薦荷憋;

在項(xiàng)目根目錄新建babel.config.js文件

module.exports = {
  presets: [
    ['@babel/preset-env']
  ]
}

然后移除webpack.config.js的babel配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        use: {
          loader: 'babel-loader',
        }
      }
    ]
  }
}

6 認(rèn)識(shí)polyfill

Polyfill是什么呢?

  • 翻譯:一種用于衣物褐望、床具等的聚酯填充材料, 使這些物品更加溫暖舒適勒庄;
  • 理解:更像是應(yīng)該填充物(墊片),一個(gè)補(bǔ)丁瘫里,可以幫助我們更好的使用JavaScript实蔽;

為什么時(shí)候會(huì)用到polyfill呢?

  • 比如我們使用了一些語法特性(例如:Promise, Generator, Symbol等以及實(shí)例方法例如
    Array.prototype.includes等)
  • 但是某些瀏覽器壓根不認(rèn)識(shí)這些特性减宣,必然會(huì)報(bào)錯(cuò)盐须;
  • 我們可以使用polyfill來填充或者說打一個(gè)補(bǔ)丁,那么就會(huì)包含該特性了漆腌;

6.1 如何使用polyfill贼邓?

babel7.4.0之前,可以使用 @babel/polyfill的包闷尿,但是該包現(xiàn)在已經(jīng)不推薦使用了塑径。


image.png

babel7.4.0之后,可以通過單獨(dú)引入core-js和regenerator-runtime來完成polyfill的使用:

 yarn add core-js regenerator-runtime --save

webpack.configf.js中排除node_modules的文件填具。因?yàn)楹芏嗟谌桨鼉?nèi)部已經(jīng)實(shí)現(xiàn)了polyfill了统舀,會(huì)引起沖突匆骗。

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        }
      }
    ]
  }
}

配置babel.config.js
我們需要在babel.config.js文件中進(jìn)行配置,給preset-env配置一些屬性:

  • useBuiltIns:設(shè)置以什么樣的方式來使用polyfill誉简;
  • corejs:設(shè)置corejs的版本碉就,目前使用較多的是3.x的版本,比如我使用的是3.8.x的版本闷串;
    • 另外corejs可以設(shè)置是否對(duì)提議階段的特性進(jìn)行支持瓮钥;設(shè)置 proposals屬性為true即可;

useBuiltIns屬性設(shè)置
useBuiltIns屬性有三個(gè)常見的值

  • 第一個(gè)值:false
    • 打包后的文件不使用polyfill來進(jìn)行適配烹吵;
    • 并且這個(gè)時(shí)候是不需要設(shè)置corejs屬性的碉熄;
  • 第二個(gè)值:usage
    • 會(huì)根據(jù)源代碼中出現(xiàn)的語言特性,自動(dòng)檢測(cè)所需要的polyfill肋拔;
    • 這樣可以確保最終包里的polyfill數(shù)量的最小化锈津,打包的包相對(duì)會(huì)小一些;
    • 可以設(shè)置corejs屬性來確定使用的corejs的版本;
module.exports = {
  presets: [
    ['@babel/preset-env', {
      useBuiltIns: 'usage',
      corejs: 3 // 默認(rèn)值2版本凉蜂,我們安裝的是3
    }]
  ]
}
  • 第三個(gè)值:entry
    • 如果我們依賴的某一個(gè)庫本身使用了某些polyfill的特性琼梆,但是因?yàn)槲覀兪褂玫氖莡sage,所以之后用戶瀏覽器可能會(huì)報(bào)錯(cuò)跃惫;
    • 所以叮叹,如果你擔(dān)心出現(xiàn)這種情況,可以使用 entry爆存;
    • 并且需要在入口文件中添加 `import 'core-js/stable'; import 'regenerator-runtime/runtime';
    • 這樣做會(huì)根據(jù) browserslist 目標(biāo)導(dǎo)入所有的polyfill蛉顽,但是對(duì)應(yīng)的包也會(huì)變大;
      useBuiltIns值解讀:
      babel.config.js
module.exports = {
  presets: [
    ['@babel/preset-env', {
      useBuiltIns: 'entry',
      corejs: 3
    }]
  ]
}

main.js

import 'core-js/stable'; 
import 'regenerator-runtime/runtime'
new Promise (resolve => {
  resolve(2)
})

6.2 認(rèn)識(shí)Plugin-transform-runtime(了解)

在前面我們使用的polyfill先较,默認(rèn)情況是添加的所有特性都是全局的

  • 如果我們正在編寫一個(gè)工具庫携冤,這個(gè)工具庫需要使用polyfill;
  • 別人在使用我們工具時(shí)闲勺,工具庫通過polyfill添加的特性曾棕,可能會(huì)污染它們的代碼;
  • 所以菜循,當(dāng)編寫工具時(shí)翘地,babel更推薦我們使用一個(gè)插件: @babel/plugin-transform-runtime來完成polyfill的功能
image.png

安裝

yarn add install @babel/plugin-transform-runtime -D

使用plugins來配置babel.config.js:
注意:因?yàn)槲覀兪褂昧薱orejs3,所以我們需要安裝對(duì)應(yīng)的庫:

image.png

module.exports = {
  presets: [
    ['@babel/preset-env', {
      // useBuiltIns: 'entry',
      // corejs: 3
    }]
  ],
  plugins: [
    ['@babel/plugin-transform-runtime', {
      corejs: 3
    }]
  ]
}

7 React的jsx支持

在我們編寫react代碼時(shí)癌幕,react使用的語法是jsx衙耕,jsx是可以直接使用babel來轉(zhuǎn)換的。
對(duì)react jsx代碼進(jìn)行處理需要如下的插件:

  • @babel/plugin-syntax-jsx
  • @babel/plugin-transform-react-jsx
  • @babel/plugin-transform-react-display-name

但是開發(fā)中勺远,我們并不需要一個(gè)個(gè)去安裝這些插件橙喘,我們依然可以使用preset來配置:

yarn add @babel/preset-react -D

babel.config.js

module.exports = {
  presets: [
    ['@babel/preset-env', {
      useBuiltIns: 'entry',
      corejs: 3
    }],
    ['@babel/preset-react']
  ],
}

8 TypeScript

在項(xiàng)目開發(fā)中,我們會(huì)使用TypeScript來開發(fā)胶逢,那么TypeScript代碼是需要轉(zhuǎn)換成JavaScript代碼厅瞎。

8.1 TypeScript的命令行使用

可以通過TypeScript的compiler來轉(zhuǎn)換成JavaScript:

npm install typescript -g

另外TypeScript的編譯配置信息我們通常會(huì)編寫一個(gè)tsconfig.json文件:

tsc --init

之后我們可以運(yùn)行 npx tsc來編譯自己的ts代碼

tsc ./index.ts

8.2 使用ts-loader

如果我們希望在webpack中使用TypeScript饰潜,那么我們可以使用ts-loader來處理ts文件:

yarn add ts-loader -D

配置ts-loader:
webpack.config.js

module.exports = {
  module: {
    rules: [
        test: /\.ts$/,
        exclude: /node_modules/,
        use: 'ts-loader'
      }
    ]
  }
}

8.3 使用babel-loader

除了可以使用TypeScript Compiler來編譯TypeScript之外,我們也可以使用Babel:

  • Babel是有對(duì)TypeScript進(jìn)行支持和簸;
  • 我們可以使用插件: @babel/tranform-typescript彭雾;
  • 但是更推薦直接使用preset:@babel/preset-typescript;

我們來安裝@babel/preset-typescript:

yarn add @babel/preset-typescript -D

webpack.config.js

module.exports = {
  entry: './src/main.ts', // ts入口文件
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      }
    ]
  }
}

babel.config.js

module.exports = {
  presets: [
    ['@babel/preset-env', {
      useBuiltIns: 'usage',
      corejs: 3
    }],
    ['@babel/preset-typescript']
  ],
}

8.4 ts-loader和babel-loader選擇

那么我們?cè)陂_發(fā)中應(yīng)該選擇ts-loader還是babel-loader呢锁保?
使用ts-loader(TypeScript Compiler)

  • 來直接編譯TypeScript冠跷,那么只能將ts轉(zhuǎn)換成js;
  • 如果我們還希望在這個(gè)過程中添加對(duì)應(yīng)的polyfill身诺,那么ts-loader是無能為力的;
  • 我們需要借助于babel來完成polyfill的填充功能抄囚;

使用babel-loader(Babel)

  • 來直接編譯TypeScript霉赡,也可以將ts轉(zhuǎn)換成js,并且可以實(shí)現(xiàn)polyfill的功能幔托;
  • 但是babel-loader在編譯的過程中穴亏,不會(huì)對(duì)類型錯(cuò)誤進(jìn)行檢測(cè);

那么在開發(fā)中重挑,我們?nèi)绾慰梢酝瑫r(shí)保證兩個(gè)情況都沒有問題呢嗓化?

8.5 編譯TypeScript最佳實(shí)踐

事實(shí)上TypeScript官方文檔有對(duì)其進(jìn)行說明:


image.png

也就是說我們使用Babel來完成代碼的轉(zhuǎn)換,使用tsc來進(jìn)行類型的檢查谬哀。
但是刺覆,如何可以使用tsc來進(jìn)行類型的檢查呢?

  • 在這里史煎,我在scripts中添加了兩個(gè)腳本谦屑,用于類型檢查;
  • 我們執(zhí)行 npm run type-check可以對(duì)ts代碼的類型進(jìn)行檢測(cè)篇梭;
  • 我們執(zhí)行 npm run type-check-watch可以實(shí)時(shí)的檢測(cè)類型錯(cuò)誤氢橙;

package.json

{
  "scripts": {
    "build": "webpack --config wk.config.js",
    "type-check": "tsc --noEmit",
    "type-check-watch": "tsc --noEmit --watch"
  }
}

*注意:必須有tsconfig.json文件

9 es-lint

ESLint是一個(gè)靜態(tài)代碼分析工具(Static program analysis,在沒有任何程序執(zhí)行的情況下恬偷,對(duì)代碼進(jìn)行分析)悍手,ESLint可以幫助我們?cè)陧?xiàng)目中建立統(tǒng)一的團(tuán)隊(duì)代碼規(guī)范,保持正確袍患、統(tǒng)一的代碼風(fēng)格坦康,提高代碼的可讀性、可維護(hù)性协怒;并且ESLint的規(guī)則是可配置的涝焙,我們可以自定義屬于自己的規(guī)則;早期還有一些其他的工具孕暇,比如JSLint仑撞、JSHint赤兴、JSCS等,目前使用最多的是ESLint隧哮。

9.1 使用ESLint

安裝

yarn add eslint -D

創(chuàng)建ESLint的配置文件:

npx eslint --init

執(zhí)行檢測(cè)命令:

npx eslint ./src/main.js

9.2 ESLint的配置文件解析

默認(rèn)創(chuàng)建的環(huán)境如下:

  • env:運(yùn)行的環(huán)境桶良,比如是瀏覽器,并且我們會(huì)使用es2021(對(duì)應(yīng)的ecmaVersion是12)的語法沮翔;
  • extends:可以擴(kuò)展當(dāng)前的配置陨帆,讓其繼承自其他的配置信息,可以跟字符串或者數(shù)組(多個(gè))采蚀;
  • parserOptions:這里可以指定ESMAScript的版本疲牵、sourceType的類型
    • parser:默認(rèn)情況下是espree(也是一個(gè)JS Parser,用于ESLint)榆鼠,但是因?yàn)槲覀冃枰幾gTypeScript纲爸,所以需要指定對(duì)應(yīng)的解釋器;
  • plugins:指定我們用到的插件妆够;
  • rules:自定義的一些規(guī)則识啦;
module.exports = {
  env: {
    browser: true,
    commonjs: true,
    es2021: true,
  },
  extends: ['plugin:vue/essential', 'airbnb-base'],
  parserOptions: {
    ecmaVersion: 12,
    parser: '@typescript-eslint/parser',
  },
  plugins: ['vue', '@typescript-eslint'],
  rules: {
    // 0 => off
    // 1 => warn
    // 2 => error
    'no-unused-vars': 0,
    quotes: ['warn', 'single'],
    'no-console': 0,
    'import/no-extraneous-dependencies': 0,
  },
};

9.3 eslint-loader

安裝

yarn add eslint-loader -D

配置
webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /node_modules/,
        use: ['babel-loader', 'eslint-loader'],
      }
    ],
  },
};

配置完成后,執(zhí)行yarn build的時(shí)候如果有eslint錯(cuò)誤就會(huì)拋出神妹,阻止打包颓哮。

9.4 vscode插件eslint

但是如果每次校驗(yàn)時(shí),都需要執(zhí)行一次npm run eslint就有點(diǎn)麻煩了鸵荠,所以我們可以使用一個(gè)VSCode的插件:ESLint


image.png

9.5 VSCode的Prettier插件

ESLint會(huì)幫助我們提示錯(cuò)誤(或者警告)冕茅,但是不會(huì)幫助我們自動(dòng)修復(fù),在開發(fā)中我們希望文件在保存時(shí)蛹找,可以自動(dòng)修復(fù)這些問題嵌赠;我們可以選擇使用另外一個(gè)工具:prettier


image.png

image.png

10 加載Vue文件

安裝vue

yarn add vue

安裝相關(guān)依賴

yarn add vue-loader  vue-template-compiler -D

配置
webpack.config.js

const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              importLoaders: 2
            }
          },
          "postcss-loader",
          "less-loader"
        ]
      },
      {
        test: /\.vue$/,
        use: "vue-loader"
      }
    ],
  },

  plugins: [
    new VueLoaderPlugin()
  ],
};

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市熄赡,隨后出現(xiàn)的幾起案子姜挺,更是在濱河造成了極大的恐慌,老刑警劉巖彼硫,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炊豪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡拧篮,警方通過查閱死者的電腦和手機(jī)词渤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來串绩,“玉大人缺虐,你說我怎么就攤上這事〗阜玻” “怎么了高氮?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵慧妄,是天一觀的道長。 經(jīng)常有香客問我剪芍,道長塞淹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任罪裹,我火速辦了婚禮饱普,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘状共。我一直安慰自己套耕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布峡继。 她就那樣靜靜地躺著箍铲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鬓椭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天关划,我揣著相機(jī)與錄音小染,去河邊找鬼。 笑死贮折,一個(gè)胖子當(dāng)著我的面吹牛裤翩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播调榄,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼踊赠,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了每庆?” 一聲冷哼從身側(cè)響起筐带,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缤灵,沒想到半個(gè)月后伦籍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腮出,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年帖鸦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胚嘲。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡作儿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出馋劈,到底是詐尸還是另有隱情攻锰,我是刑警寧澤晾嘶,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站口注,受9級(jí)特大地震影響变擒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜寝志,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一娇斑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧材部,春花似錦毫缆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至物臂,卻和暖如春旺拉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背棵磷。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來泰國打工蛾狗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仪媒。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓沉桌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親算吩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子留凭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容