欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue項目中引入ESLint校驗代碼避免代碼錯誤

 更新時間:2022年07月21日 09:17:07   作者:DevUI團(tuán)隊  
這篇文章主要為大家介紹了Vue項目中引入ESLint插件校驗代碼避免代碼錯誤的使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

1 ESLint 是什么

ESLint 是一個插件式的 JavaScript / JSX 代碼檢查工具,用于檢測和修復(fù) JavaScript 代碼中的問題,目標(biāo)是讓代碼更一致并避免錯誤。

2 在 Vue 項目中引入 ESLint

使用 Vue CLI 搭建的 Vue2 項目已經(jīng)自帶 ESLint,就不贅述,我們看下 Vite 搭建的 Vue3 項目中怎么引入 ESLint。

使用以下命令搭建一個 Vue3 項目:

npm create vite@latest vue3-project

創(chuàng)建之后,啟動起來:

npm i
npm run dev

效果如下:

2.1 引入 ESLint

執(zhí)行以下命令:

npm init @eslint/config

進(jìn)入交互式界面,可通過上下方向鍵選擇,通過按回車鍵確定。

第一個問題是:

  • 你希望用 ESLint 來干嘛?
  • 我們選擇最全面的那個:檢查語法,發(fā)現(xiàn)問題,并強(qiáng)制統(tǒng)一代碼樣式
$ npm init @eslint/config
? How would you like to use ESLint? … 
  To check syntax only
  To check syntax and find problems
? To check syntax, find problems, and enforce code style

第二個問題是:

  • 你的項目用的是什么模塊系統(tǒng)?
  • 因為是運(yùn)行在瀏覽器端,選擇 ESModule
? What type of modules does your project use? … 
? JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

第三個問題是:

  • 你用的什么框架?(居然沒有 Angular)
  • 選擇 Vue
? Which framework does your project use? … 
  React
? Vue.js
  None of these

第四個問題是:

  • 你是否使用 TypeScript?
  • 選擇 Yes
? Does your project use TypeScript? ? No / Yes

第五個問題是:

  • 你的代碼運(yùn)行在什么環(huán)境?(這個可以多選)
  • 選擇 Browser 瀏覽器環(huán)境
? Where does your code run? …  (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Browser
? Node

第六個問題是:

  • 你想定義怎樣的代碼風(fēng)格?
  • 選擇使用一個流行的代碼風(fēng)格
? How would you like to define a style for your project? … 
? Use a popular style guide
  Answer questions about your style

第七個問題是:

  • 你想使用哪個樣式風(fēng)格?
  • Airbnb 用的人比較多,就選這個吧
? Which style guide do you want to follow? … 
? Airbnb: https://github.com/airbnb/javascript
  Standard: https://github.com/standard/standard
  Google: https://github.com/google/eslint-config-google
  XO: https://github.com/xojs/eslint-config-xo

第八個問題是:

  • 配置文件用什么格式?
  • 就選 JavaScript 吧(生成 eslintrc.js 文件)
? What format do you want your config file to be in? … 
? JavaScript
  YAML
  JSON

完成!是不是超級簡單!

看下我們都選了哪些配置:

? How would you like to use ESLint? · style
? What type of modules does your project use? · esm
? Which framework does your project use? · vue
? Does your project use TypeScript? · Yes
? Where does your code run? · browser
? How would you like to define a style for your project? · guide
? Which style guide do you want to follow? · airbnb
? What format do you want your config file to be in? · JavaScript

主要給我們安裝了以下依賴:

eslint-config-airbnb-base@15.0.0

eslint-plugin-import@2.26.0

eslint-plugin-vue@9.2.0

eslint@8.20.0

@typescript-eslint/parser@5.30.6

@typescript-eslint/eslint-plugin@5.30.6

并生成了一個 eslintrc.cjs 配置文件:

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'plugin:vue/vue3-essential',
    'airbnb-base',
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    parser: '@typescript-eslint/parser',
    sourceType: 'module',
  },
  plugins: [
    'vue',
    '@typescript-eslint',
  ],
  // 自定義 rules 規(guī)則
  rules: {
  },
};

2.2 ESLint 配置

  • parser 解析器
  • extends 配置擴(kuò)展
  • plugins 插件
  • rules 自定義規(guī)則 eslint.org/docs/latest…
  • eslint-disable-next-line 禁用ESLint

2.3 執(zhí)行 ESLint 代碼檢查

在 package.json 文件的 scripts 中配置 lint 腳本命令:

"scripts": {
  "dev": "vite",
  "build": "vue-tsc --noEmit && vite build",
  "preview": "vite preview",
  // 配置 lint 腳本命令
  "lint": "eslint --ext .vue,.ts src/"
},

執(zhí)行 lint 腳本命令:

npm run lint

出現(xiàn)了一堆報錯:

/vue3-project/src/App.vue
  4:53  error  Missing semicolon  semi
/vue3-project/src/components/HelloWorld.vue
  2:26  error  Missing semicolon  semi
  4:31  error  Missing semicolon  semi
  6:21  error  Missing semicolon  semi
/vue3-project/src/main.ts
  1:32  error  Missing semicolon  semi
  2:21  error  Missing semicolon  semi
  3:28  error  Missing semicolon  semi
  5:29  error  Missing semicolon  semi
/vue3-project/src/vite-env.d.ts
  4:3   error  Expected 1 empty line after import statement not followed by another import  import/newline-after-import
  4:45  error  Missing semicolon                                                            semi
  5:48  error  Missing semicolon                                                            semi
  6:27  error  Missing semicolon                                                            semi
? 12 problems (12 errors, 0 warnings)
  12 errors and 0 warnings potentially fixable with the `--fix` option.

大部分都是說句尾沒有分號,因為我們選擇的是 Airbnb 代碼規(guī)范,所以會有這個報錯提示,不同的代碼規(guī)范,內(nèi)置的檢查規(guī)則不一定完全相同。

2.4 自動修復(fù) ESLint 問題

在 scripts 中增加自動修復(fù) ESLint 問題的腳本命令:

"scripts": {
  "dev": "vite",
  "build": "vue-tsc --noEmit && vite build",
  "preview": "vite preview",
  "lint": "eslint --ext .vue,.ts src/",
  // 自動修復(fù) ESLint 問題腳本命令
  "lint:fix": "eslint --ext .vue,.ts src/ --fix"
},

執(zhí)行:

npm run lint:fix

執(zhí)行自動修復(fù)的命令之后,所有分號都加上了,未使用的變量也自動移除了。

再次執(zhí)行:

npm run lint

沒有再報錯。

3 配置 husky 和 PR 門禁

3.1 配置 husky 門禁

為了確保每次提交(git commit)之前代碼都通過 ESLint 檢查,我們增加一個 pre-commit 門禁。

  • 第一步:安裝 husky 和 lint-staged
npm i lint-staged husky -D
  • 第二步:在 package.json 的 scripts 中增加 prepare 腳本命令
"scripts": {
  "dev": "vite",
  "build": "vue-tsc --noEmit && vite build",
  "preview": "vite preview",
  "lint": "eslint --ext .vue,.ts src/",
  "lint:fix": "eslint --ext .vue,.ts src/ --fix",
  // 在 npm install 之后自動執(zhí)行,生成`.husky`目錄。
  "prepare": "husky install"
},
  • 第三步:執(zhí)行 prepare 腳本
npm run prepare

該命令執(zhí)行完會在項目根目錄自動生成.husky目錄。

  • 第四步:增加 pre-commit 鉤子

執(zhí)行以下命令,會在.husky目錄自動生成pre-commit文件鉤子。

npx husky add .husky/pre-commit "npx lint-staged"
  • 第五步:增加 lint-staged 配置
"lint-staged": {
  "src/**/*.{vue,ts}": "eslint --fix"
},

通過以上五個步驟,以后每次使用git commit命令提交提交代碼,都會:

  • 被 pre-commit 鉤子攔截
  • 執(zhí)行 npx lint-staged 命令
  • 進(jìn)而執(zhí)行 eslint --fix 命令,對本次提交修改的代碼涉及的文件進(jìn)行代碼檢查,并自動修復(fù)能修復(fù)的錯誤,不能修復(fù)的錯誤會提示出來,只有所有 ESLint 錯誤都修復(fù)了才能提交成功

3.2 配置 PR 門禁

如果你在做自己的開源項目,并且非常幸運(yùn),有一群志同道合的小伙伴愿意一起參與貢獻(xiàn),這時為了統(tǒng)一大家的代碼風(fēng)格,讓貢獻(xiàn)者們專注于特性開發(fā),不用擔(dān)心代碼格式規(guī)范問題,并通過 ESLint 工具提示貢獻(xiàn)者,哪些代碼可能帶來潛在的風(fēng)險,你就有必要給提交的 PR 加上 ESLint 門禁。

我們已經(jīng)增加了本地的 ESLint 命令:

"scripts": {
  "lint": "eslint --ext .vue,.ts src/",
},

我們需要在本目錄創(chuàng)建一個.github/workflows/pull-request.yml文件,在該文件中寫入以下內(nèi)容:

name: Pull Request
on:
  push:
    branches: [ dev, main ]
  pull_request:
    branches: [ dev, main ]
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [16.x]
    name: "ESLint"
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Install pnpm
        uses: npm/action-setup@v2
        with:
          version: 6
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}
      - name: Install deps
        run: npm i
      - name: ESLint
        run: npm run lint

這樣只要 PR 是往 dev 或 main 分支合入的,都會跑一遍這個 Github Actions 工作流任務(wù),ESLint 檢查不通過的話,PR 的 checks 里面會提示,攔截該 PR 的合入。

PR 的提交者看到提示,也可以點到任務(wù)里面去看是哪里報錯,修改掉這些 ESLint 問題,PR 就會變成綠色,項目的管理員就可以順利合入 PR 到目標(biāo)分支啦??

4 常見的 ESLint 問題及修復(fù)案例

接下來跟大家分享 Vue DevUI 開源 Vue3 組件庫 ESLint 問題修復(fù)過程中遇到的典型問題。

4.1 案例1:

warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any

該問題出現(xiàn)頻率比較高,原因是有些類型寫了any,需要明確的類型。

比如Pagination組件的單元測試文件pagination.spec.ts中:

const wrapper = mount({
    components: {
        DPagination
    },
    template: `&lt;d-pagination ... /&gt;`
}, globalOption);
const btns = wrapper.findAll('a.devui-pagination-link');
expect(btns.map((ele: any) =&gt; ele.text()).join()).toEqual('&lt;,1,...,4,5,6,...,16,&gt;');

其中的ele: any就屬于這類問題。

解決辦法是給ele加上明確的類型,看邏輯是<button>元素,由于是@vue/test-utils庫的包裹元素,因此需要包一層DOMWrapper

import { DOMWrapper } from '@vue/test-utils';
expect(btns.map((ele:  DOMWrapper&lt;Element&gt;) =&gt; ele.text()).join()).toEqual('&lt;,1,...,4,5,6,...,16,&gt;');

4.2 案例2:

'xxx' was used before it was defined no-use-before-define

這也是一個比較常見的問題,在聲明之前使用變量或方法,解決辦法也很簡單,只需要調(diào)整下代碼的順序即可,將變量或方法的聲明放在調(diào)用的語句之前。

比如Pagination組件的pagination.tsx中:

    // 極簡模式下,可選的下拉選擇頁碼
    const litePageOptions = computed(() =>  liteSelectOptions(totalPages.value));
    // 當(dāng)前頁碼
    const cursor = computed({
      get() {
        // 是否需要修正錯誤的pageIndex
        if (!props.showTruePageIndex && props.pageIndex > totalPages.value) {
          emit('update:pageIndex', totalPages.value || 1);
          return totalPages.value || 1;
        }
        return props.pageIndex || 1;
      },
      set(val: number) {
        emit('update:pageIndex', val);
      }
    });
    // 總頁數(shù)
    const totalPages = computed(() => Math.ceil(props.total / props.pageSize));

其中的totalPages的聲明在比較靠后的位置,但是卻在聲明之前在litePageOptionscursor變量中都使用了totalPages,所以提示 ESLint 問題。

解決的方法就是將totalPages的聲明放在litePageOptionscursor之前。

    // 總頁數(shù)
    const totalPages = computed(() =&gt; Math.ceil(props.total / props.pageSize));
    // 極簡模式下,可選的下拉選擇頁碼
    const litePageOptions = computed(() =&gt;  liteSelectOptions(totalPages.value));
    // 當(dāng)前頁碼
    const cursor = computed({ ... });

4.3 案例3:

warning Missing return type on function @typescript-eslint/explicit-module-boundary-types

該問題是因為函數(shù)缺少返回類型,比如Fullscreen組件utils.ts文件的launchImmersiveFullScreen方法中:

export const launchImmersiveFullScreen = async (docElement: any) =&gt; {
  let fullscreenLaunch = null;
  if (docElement.requestFullscreen) {
    fullscreenLaunch = docElement.requestFullscreen();
  } else if (docElement.mozRequestFullScreen) {
    fullscreenLaunch = docElement.mozRequestFullScreen();
  } else if (docElement.webkitRequestFullScreen) {
    fullscreenLaunch = Promise.resolve(docElement.webkitRequestFullScreen());
  } else if (docElement.msRequestFullscreen) {
    fullscreenLaunch = Promise.resolve(docElement.msRequestFullscreen());
  }
  return await fullscreenLaunch.then(() =&gt; !!document.fullscreenElement);
};

先看下launchImmersiveFullScreen方法的參數(shù)問題,docElement用了any,也缺失了返回類型,docElement其實就是document對象,可以使用HTMLElement類型,但是launchImmersiveFullScreen這個方法是用來啟動沉浸式全屏的,為了實現(xiàn)瀏覽器兼容,比如使用了docElement.mozRequestFullScreen兼容火狐,而這些方法在HTMLElement中是沒有的,會報TS類型錯誤,所以需要做一些改造。

interface CompatibleHTMLElement extends HTMLElement {
  mozRequestFullScreen?: () =&gt; void;
  webkitRequestFullScreen?: () =&gt; void;
  msRequestFullscreen?: () =&gt; void;
}

這里定義了一個CompatibleHTMLElement的類型,繼承了HTMLElement,并增加了一些自定義的方法。

export const launchImmersiveFullScreen = async (docElement: CompatibleHTMLElement) =&gt; {
  ...
}

再來看下launchImmersiveFullScreen方法的返回類型問題。

return await fullscreenLaunch.then(() =&gt; !!document.fullscreenElement);

該方法返回了一個Promise對象,它的類型是一個泛型,我們需要傳入具體的類型:

export const launchImmersiveFullScreen = async (docElement: CompatibleHTMLElement): Promise&lt;boolean&gt; =&gt; {
  ...
  return await fullscreenLaunch.then(() =&gt; !!document.fullscreenElement);
};

4.4 案例4:

'xxx' is already declared in the upper scope @typescript-eslint/no-shadow

這個問題是由于嵌套的作用域中定義了相同的變量名,比如Tree組件的use-checked.ts文件中:

export default function useChecked(...) {
  const onNodeClick = (item: TreeItem) => {
    // 這里定義了 id 變量
    const { id } = item;
    ...
    filter 里面又定義了一個 id 參數(shù)
    const currentSelectedItem = flatData.filter(({ id }) => currentSelected[id] && currentSelected[id] !== 'none');
    ...
  }
}

修改方式就是將其中一個 id 的名字改了,比如把里面的 id 改成 itemId:

const currentSelectedItem = flatData.filter(({ id: itemId }) => currentSelected[itemId] && currentSelected[itemId] !== 'none');

歡迎在評論區(qū)分享你在項目中遇到的 ESLint 問題????

5 感謝

Vue DevUI 組件庫 ESLint 問題清零之路上,不得不提的一位小伙伴就是 @linxiang07 同學(xué),他從2022年3月到7月,持續(xù)4個多月,累計修復(fù)40多個組件的100多個 ESLint 問題,直到7月5日 ESLint 清零,并給 PR 添加 ESLint 門禁,后續(xù) PR 如果未通過 ESLint 檢查將無法合入。

感謝 linxiang 同學(xué)的付出!

以下是 linxiang 同學(xué)提交的部分PR:

linxiang 同學(xué)也因此成為 Vue DevUI 組件庫 TOP3 的貢獻(xiàn)者,并成為我們的 Committer 和管理員????

值得一提的是 linxiang 同學(xué)還是我們的 VirtualList 虛擬列表組件和 Tree 組件等多個組件的田主和貢獻(xiàn)者,并且完善了多個組件的單元測試,能力很強(qiáng),是非?;钴S和積極的貢獻(xiàn)者。

以上就是Vue項目中引入ESLint校驗代碼避免代碼錯誤的詳細(xì)內(nèi)容,更多關(guān)于Vue引入ESLint代碼校驗的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論