<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          中小型前端團(tuán)隊(duì)代碼規(guī)范工程化最佳實(shí)踐 - ESLint

          共 7802字,需瀏覽 16分鐘

           ·

          2021-04-14 14:28

          作者:axuebing

          來(lái)源:Segmentfault 思否社區(qū)

          前言

          There are a thousand Hamlets in a thousand people's eyes.


          一千個(gè)程序員,就有一千種代碼風(fēng)格。在前端開(kāi)發(fā)中,有幾個(gè)至今還在爭(zhēng)論的代碼風(fēng)格差異:
          • 單引號(hào)還是雙引號(hào)?
          • 代碼行結(jié)束是否需要分號(hào)?
          • 兩個(gè)空格還是四個(gè)空格?
          • ...
          這幾個(gè)代碼風(fēng)格差異在協(xié)同開(kāi)發(fā)中經(jīng)常會(huì)被互相吐槽,甚至不能忍受。
          除此之外,由于 JavaScript 的靈活性,往往一段代碼能有多種寫法,這時(shí)候也會(huì)導(dǎo)致協(xié)同時(shí)差異。并且,有一些寫法可能會(huì)導(dǎo)致不易發(fā)現(xiàn)的 bug,或者這些寫法的性能不好,開(kāi)發(fā)時(shí)也應(yīng)該避免。
          為了解決這類靜態(tài)代碼問(wèn)題,每個(gè)團(tuán)隊(duì)都需要一個(gè)統(tǒng)一的 JavaScript 代碼規(guī)范,團(tuán)隊(duì)成員都遵守這份代碼規(guī)范來(lái)編寫代碼。當(dāng)然,靠人來(lái)保障代碼規(guī)范是不可靠的,需要有對(duì)應(yīng)的工具來(lái)保障,ESLint 就是這個(gè)工具。
          有的讀者看到這里,可能會(huì)說(shuō):Prettier 也可以保證代碼風(fēng)格一致。是的,Prettier 確實(shí)可以按照設(shè)置的規(guī)則對(duì)代碼進(jìn)行統(tǒng)一格式化,后面的文章也會(huì)有對(duì)應(yīng)的介紹。但是需要明確的一點(diǎn)是,Prettier 只會(huì)在格式上對(duì)代碼進(jìn)行格式化,一些隱藏的代碼質(zhì)量問(wèn)題 Prettier 是無(wú)法發(fā)現(xiàn)的,而 ESLint 可以。

          關(guān)于 ESLint

          關(guān)于 ESLint,它的 Slogan 是 Find and fix problems in your JavaScript code。如上文所說(shuō),它可以發(fā)現(xiàn)并修復(fù)你 JavaScript 代碼中的問(wèn)題。來(lái)看一下官網(wǎng)上描述 ESLint 具備的三個(gè)特性:
          • Find Problems。ESLint 通過(guò)靜態(tài)代碼分析可以快速發(fā)現(xiàn)代碼中的問(wèn)題。ESLint 可以運(yùn)行在大多數(shù)文本編輯器中,并且也可以在工作流中接入 ESLint
          • Fix Automatically。ESLint 發(fā)現(xiàn)的很多問(wèn)題都可以自動(dòng)修復(fù)
          • Customize。可以定制 ESLint 檢查規(guī)則
          基于以上描述,我們?cè)谇岸斯こ袒锌梢赃@樣使用 ESLint:
          1. 基于業(yè)界現(xiàn)有的 ESLint 規(guī)范和團(tuán)隊(duì)代碼習(xí)慣定制一套統(tǒng)一的 ESLint 代碼規(guī)則
          2. 將統(tǒng)一代碼規(guī)則封裝成 ESLint 規(guī)則包接入
          3. 將 ESLint 接入腳手架、編輯器以及研發(fā)工作流中

          快速上手

          先簡(jiǎn)單介紹一下如何使用 ESLint,如果已經(jīng)有所了解的同學(xué),可以直接跳過(guò)這一節(jié)。
          新建一個(gè)包含 package.json 的目錄(可以在空目錄下執(zhí)行 npm init -y),新建一個(gè) index.js
          // index.js
          const name = 'axuebin'
          安裝 eslint :
          npm install eslint --save-dev
          然后執(zhí)行 ./node_modules/.bin/eslint --init 或者 npx eslint --init 生成一個(gè) ESLint 配置文件 .eslintc.js
          module.exports = {
            env: {
              es2021: true,
            },
            extends: 'eslint:recommended',
            parserOptions: {
              ecmaVersion: 12,
            },
            rules: {},
          };
          生成好配置文件之后,就可以執(zhí)行 ./node_modules/.bin/eslint index.js 或者 npx eslint index.js 命令對(duì)文件進(jìn)行檢查。結(jié)果如下
          index.js 中的代碼命中了 no-unused-vars 這個(gè)規(guī)則,默認(rèn)情況下,這個(gè)規(guī)則是會(huì)報(bào) error 的,也就是 ESLint 不允許代碼中出現(xiàn)未被使用的變量。這是一個(gè)好習(xí)慣,有利于代碼的維護(hù)。

          簡(jiǎn)單配置

          我們來(lái)嘗試配置 ESLint 的檢查規(guī)則。以分號(hào)和引號(hào)舉例,現(xiàn)在你作為團(tuán)隊(duì)代碼規(guī)范的指定人,希望團(tuán)隊(duì)成員開(kāi)發(fā)的代碼,都是單引號(hào)帶分號(hào)的。
          打開(kāi) .eslintrc.js 配置文件,在 rules 中添加相關(guān)配置項(xiàng):
          module.exports = {
            env: {
              es2021: true,
            },
            extends: 'eslint:recommended',
            parserOptions: {
              ecmaVersion: 12,
            },
            rules: {
              semi: ['error''always'],
              quotes: ['error''single'],
            },
          };
          然后我們將 index.js 中的代碼改成:
          // index.js
          const name = "axuebin"
          執(zhí)行 eslint 命令之后:
          可以看到檢查結(jié)果如下:
          • [no-unused-vars] 'name' is assigned a value but never used。定義了 name 變量卻未使用。
          • [quotes] Strings must use singlequote。字符串必須使用單引號(hào)。
          • [semi] Missing semicolon。缺失分號(hào)。
          老老實(shí)實(shí)地按照規(guī)范修改代碼,使用單引號(hào)并將加上分號(hào)。當(dāng)然,如果你們希望是雙引號(hào)和不帶分號(hào),修改相應(yīng)的配置即可。
          具體各個(gè)規(guī)則如何配置可以查看:
          https://eslint.org/docs/rules

          自動(dòng)修復(fù)

          執(zhí)行 eslint xxx --fix 可以自動(dòng)修復(fù)一些代碼中的問(wèn)題,將無(wú)法自動(dòng)修復(fù)的問(wèn)題暴露出來(lái)。比如上文中提到的引號(hào)和分號(hào)的問(wèn)題,就可以通過(guò) --fix 自動(dòng)修復(fù),而 no-unused-vars 變量未使用的問(wèn)題,ESLint 就無(wú)法自動(dòng)修復(fù)。
          使用配置包
          在 init 生成的配置文件中,我們看到包含這一行代碼:
          module.exports = {
            extends: "eslint:recommended"
          }
          這一行代碼的意思是,使用 ESLint 的推薦配置。 extends: 'xxx' 就是 繼承,當(dāng)前的配置繼承于 xxx 的配置,在此基礎(chǔ)上進(jìn)行擴(kuò)展。
          因此,我們也可以使用任意封裝好的配置,可以在 NPM 上或者 GItHub 上搜索 eslint-config 關(guān)鍵詞獲取,本文我們將這類封裝好的配置稱作 “配置集”。比較常見(jiàn)的配置包有以下幾個(gè):
          • eslint-config-airbnb: Airbnb 公司提供的配置集
          • eslint-config-prettier: 使用這個(gè)配置集,會(huì)關(guān)閉一些可能與 Prettier 沖突的規(guī)則
          • eslint-config-react: create react app 使用的配置集
          • eslint-config-vue: vuejs 使用的配置集
          • ...

          最佳實(shí)踐

          簡(jiǎn)單了解完 ESLint 之后,對(duì)于 ESLint 的更多使用細(xì)節(jié)以及原理,在本篇文章就不展開(kāi)了,感興趣的朋友可以在官網(wǎng)詳細(xì)了解。本文重點(diǎn)還是在于如何在團(tuán)隊(duì)工程化體系中落地 ESLint,這里提幾個(gè)最佳實(shí)踐。

          抽象配置集

          對(duì)于獨(dú)立開(kāi)發(fā)者以及業(yè)務(wù)場(chǎng)景比較簡(jiǎn)單的小型團(tuán)隊(duì)而言,使用現(xiàn)成、完備的第三方配置集是非常高效的,可以較低成本低接入 ESLint 代碼檢查。
          但是,對(duì)于中大型團(tuán)隊(duì)而言,在實(shí)際代碼規(guī)范落地的過(guò)程中我們會(huì)發(fā)現(xiàn),不可能存在一個(gè)能夠完全符合團(tuán)隊(duì)風(fēng)格的三方配置包,我們還是會(huì)在 extends 三方配置集的基礎(chǔ)上,再手動(dòng)在 rules 配置里加一些自定義的規(guī)則。時(shí)間長(zhǎng)了,有可能 A 應(yīng)用和 B 應(yīng)用里的 rules 就不一樣了,就很難達(dá)到統(tǒng)一的目的。
          這時(shí)候,就需要一個(gè)中心化的方式來(lái)管理配置包:根據(jù)團(tuán)隊(duì)代碼風(fēng)格整理(或者基于現(xiàn)有的三方配置集)發(fā)布一個(gè)配置集,團(tuán)隊(duì)統(tǒng)一使用這個(gè)包,就可以做到中心化管理和更新。
          除此之外,從技術(shù)層面考慮,目前一個(gè)前端團(tuán)隊(duì)的面對(duì)的場(chǎng)景可能比較復(fù)雜。比如:
          • 技術(shù)選型不一致:框架上 PC 使用 React,H5 使用 Vue;是否使用 TypeScript
          • 跨端場(chǎng)景多:Web 端和小程序端,還有 Node
          • ...
          以上問(wèn)題在真實(shí)開(kāi)發(fā)中都是存在的,所以在代碼規(guī)范的工程化方案落地時(shí),一個(gè)單一功能的配置集是不夠用的,這時(shí)候還需要考慮這個(gè)配置集如何抽象。
          為了解決以上問(wèn)題,這里提供一種解決方案的思路:
          具體拆解來(lái)看,就是有一個(gè)類似 eslint-config-standard 的基礎(chǔ)規(guī)則集(包括代碼風(fēng)格、變量相關(guān)、ES6 語(yǔ)法等),在此基礎(chǔ)之上集成社區(qū)的一些插件(Vue/React)等,封裝成統(tǒng)一的一個(gè) NPM Package 發(fā)布,消費(fèi)時(shí)根據(jù)當(dāng)前應(yīng)用類型通過(guò)不同路徑來(lái) extends 對(duì)應(yīng)的配置集。
          這里有一個(gè) Demo,感興趣的朋友可以看一下:eslint-config-axuebin

          開(kāi)發(fā)插件

          ESLint 提供了豐富的配置供開(kāi)發(fā)者選擇,但是在復(fù)雜的業(yè)務(wù)場(chǎng)景和特定的技術(shù)棧下,這些通用規(guī)則是不夠用的。ESLint 通過(guò)插件的形式賦予了擴(kuò)展性,開(kāi)發(fā)者可以自定義任意的檢查規(guī)則,比如 eslint-plugin-vue / eslint-plugin-react 就是 Vue / React 框架中使用的擴(kuò)展插件,官網(wǎng)也提供了相關(guān)文檔引導(dǎo)開(kāi)發(fā)者開(kāi)發(fā)一個(gè)插件。
          一般來(lái)說(shuō),我們也不需要開(kāi)發(fā)插件,但我們至少需要了解有這么個(gè)東西。在做一些團(tuán)隊(duì)代碼質(zhì)量檢查的時(shí)候,我們可能會(huì)有一些特殊的業(yè)務(wù)邏輯,這時(shí)候 ESLint 插件是可以幫助我們做一些事情。
          這里就不展開(kāi)了,主要就是一些 AST 的用法,照著官方文檔就可以上手,或者可以參考現(xiàn)有的一些插件寫法。

          腳手架 / CLI 工具

          當(dāng)有了團(tuán)隊(duì)的統(tǒng)一 ESLint 配置集和插件之后,我們會(huì)將它們集成到腳手架中,方便新項(xiàng)目集成和開(kāi)箱即用。但是對(duì)于一些老項(xiàng)目,如果需要手動(dòng)改造還是會(huì)有一些麻煩的,這時(shí)候就可以借助于 CLI 來(lái)完成一鍵升級(jí)。
          本文結(jié)合上文的 Demo eslint-config-axuebin,設(shè)計(jì)一個(gè)簡(jiǎn)單的 CLI Demo。由于當(dāng)前配置也比較簡(jiǎn)單,所以 CLI 只需要做幾件簡(jiǎn)單的事情即可:
          • 詢問(wèn)用戶當(dāng)前項(xiàng)目的類型(是 JavaScript 還是 TypeScript、是 React 還是 Vue)
          • 根據(jù)項(xiàng)目類型寫 .eslintrc.js 文件
          • 根據(jù)項(xiàng)目類型安裝所需依賴(比如 vue 需要 eslint-plugin-vue)
          • 在 package.json 的 scripts 中寫入 "lint": "eslint src test --fix"  
          核心代碼如下:
          const path = require('path');
          const fs = require('fs');
          const chalk = require('chalk');
          const spawn = require('cross-spawn');

          const { askForLanguage, askForFrame } = require('./ask');
          const { eslintrcConfig, needDeps } = require('./config');

          module.exports = async () => {
            const language = await askForLanguage();
            const frame = await askForFrame();

            let type = language;
            if (frame) {
              type += `/${frame}`;
            }

            fs.writeFileSync(
              path.join(process.cwd(), '.eslintrc.js'),
              `// Documentation\n// https://github.com/axuebin/eslint-config-axuebin\nmodule.exports = ${JSON.stringify(
                eslintrcConfig(type),
                null,
                2
              )}`
            );

            const deps = needDeps.javascript;
            if (language === 'typescript') {
              deps.concat(needDeps.typescript);
            }
            if (frame) {
              deps.concat(needDeps[frame]);
            }

            spawn.sync('npm', ['install', ...deps, '--save'], { stdio: 'inherit' });
          };
          可運(yùn)行的 CLI Demo 代碼見(jiàn):axb-lint,在項(xiàng)目目錄下執(zhí)行:axblint eslint 即可,如圖:
          自動(dòng)化
          配置了 ESLint 之后,我們需要讓開(kāi)發(fā)者感知到 ESLint 的約束。開(kāi)發(fā)者可以自己運(yùn)行 eslint 命令來(lái)跑代碼檢查,這不夠高效,所以我們需要一些自動(dòng)化手段來(lái)做這個(gè)事情。當(dāng)然 在開(kāi)發(fā)時(shí),編輯器也有提供相應(yīng)的功能可以根據(jù)當(dāng)前工作區(qū)下的 ESLint 配置文件來(lái)檢查當(dāng)前正在編輯的文件,這個(gè)不是我們關(guān)心的重點(diǎn)。
          一般我們會(huì)在有以下幾種方式做 ESLint 檢查:
          • 開(kāi)發(fā)時(shí):依賴編輯器的能力
          • 手動(dòng)運(yùn)行:在終端中手動(dòng)執(zhí)行 eslint 命令
          • pre-commit:在提交 git 前自動(dòng)執(zhí)行 eslint 命令
          • ci:依賴 git 的持續(xù)集成,可以將檢查結(jié)果輸出文件上傳到服務(wù)器
          這里提一下 pre-commit 的方案,在每一次本地開(kāi)發(fā)完成提交代碼前就做 ESLint 檢查,保證云端的代碼是統(tǒng)一規(guī)范的。
          這種方式非常簡(jiǎn)單,只需要在項(xiàng)目中依賴 husky 和 lint-staged 即可完成。安裝好依賴之后,在 package.json 文件加入以下配置即可:
          {
            "lint-staged": {
              "*.{js,jsx,ts,tsx}""eslint --cache --fix"
            },
            "husky": {
              "hooks": {
                "pre-commit""lint-staged"
              }
            }
          }
          效果如圖所示:
          如果代碼跑 ESLint 檢查拋了 Error 錯(cuò)誤,則會(huì)中斷 commit 流程:
          這樣就可以確保提交到 GitHub 倉(cāng)庫(kù)上的代碼是統(tǒng)一規(guī)范的。(當(dāng)然,如果認(rèn)為將這些配置文件都刪了,那也是沒(méi)辦法的)

          總結(jié)

          本文介紹了 ESLint 在中小型前端團(tuán)隊(duì)的一些最佳實(shí)踐的想法,大家可以在此基礎(chǔ)上擴(kuò)展,制訂一套完善的 ESLint 工作流,落地到自己團(tuán)隊(duì)中。


          點(diǎn)擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開(kāi)更多互動(dòng)和交流,掃描下方”二維碼“或在“公眾號(hào)后臺(tái)回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~

          - END -


          瀏覽 25
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91人人妻人人妻人人澡 | 91麻豆精品91AⅤ久久久久久 | 日韩88页 | 97人妻人人操 | 日韩精品第一页 |