在RN工程中,使用ESLint進(jìn)行代碼規(guī)范掃描。
Why-- 為什么需要代碼規(guī)范
JavaScript的應(yīng)用場(chǎng)景由最初的用在Web頁(yè)面中實(shí)現(xiàn)一些簡(jiǎn)單交互,發(fā)展到處理復(fù)雜的網(wǎng)站功能交互等,甚至通過(guò)NodeJS來(lái)跑在服務(wù)端。應(yīng)用的場(chǎng)景越來(lái)越多,越來(lái)越復(fù)雜,需要應(yīng)對(duì)不同的運(yùn)行的環(huán)境等,對(duì)代碼的穩(wěn)定性和兼容性要求越來(lái)越高。
加上JavaScript語(yǔ)言本身存在一些設(shè)計(jì)缺陷,例如既是優(yōu)點(diǎn)又是缺陷的弱類型特性、例如var變量的作用域問(wèn)題等等,這些特性會(huì)帶來(lái)非常多的安全隱患。代碼不嚴(yán)謹(jǐn)可能就會(huì)觸發(fā)一些神奇的錯(cuò)誤甚至一些低級(jí)錯(cuò)誤,這些錯(cuò)誤往往在編譯期間很難發(fā)現(xiàn),通常只有在運(yùn)行期間才會(huì)暴露出來(lái),這樣很容易把問(wèn)題帶到線上,導(dǎo)致面臨巨大的風(fēng)險(xiǎn)。以上問(wèn)題,需要通過(guò)一套代碼規(guī)范機(jī)制來(lái)約束代碼風(fēng)格、盡量避免低級(jí)錯(cuò)誤的產(chǎn)生。
同時(shí)在企業(yè)的項(xiàng)目開發(fā)中,制定一套完善有效的編碼規(guī)范也是極為必要的。好的編碼習(xí)慣,規(guī)范的代碼風(fēng)格對(duì)于降低團(tuán)隊(duì)成員開發(fā)時(shí)的溝通成本、提升codeReview效率、提高代碼質(zhì)量、提升系統(tǒng)穩(wěn)定性等都是有巨大好處的。
在前端開發(fā)中有一些輔助工具來(lái)解決這個(gè)問(wèn)題,例如JSLint、JSHint、ESLint等,其中現(xiàn)在比較流行且對(duì)JS新特性兼容比較好的是ESLint。這套機(jī)制同樣適用于React Native的開發(fā).
What-- 規(guī)則、自動(dòng)檢測(cè)工具(ESLint)
規(guī)則
工程目錄結(jié)構(gòu)
以下目錄結(jié)構(gòu)示例中只展示js與靜態(tài)資源,不包含原生代碼。
├── index.ios.js
├── index.android.js
└── js
├── component 可復(fù)用的組件(非完整頁(yè)面)
├── page 完整頁(yè)面
├── config 配置項(xiàng)(常量、接口地址、路由、多語(yǔ)言化等預(yù)置數(shù)據(jù))
├── util 工具類(非UI組件)
├── style 全局樣式
└── image 圖片
在component和page目錄中,可能還有一些內(nèi)聚度較高的模塊再建目錄
page/component
├── HomeView.component.js
├── HomeView.style.js
└── MovieView
├── MovieList.component.js
├── MovieList.style.js
├── MovieCell.component.js
├── MovieCell.style.js
├── MovieView.component.js
└── MovieView.style.js
代碼風(fēng)格、規(guī)范
JavaScript基礎(chǔ)語(yǔ)法部分的代碼規(guī)范
ESLint內(nèi)置的一套代碼規(guī)范(eslint:recommended):https://cn.eslint.org/docs/rules/
前端比較流行的一套代碼規(guī)范:Airbnb JavaScript Style Guide
React/JSX 相關(guān)的代碼規(guī)范
Airbnb React/JSX 風(fēng)格指南:https://github.com/lin-123/javascript/tree/cn/react
自動(dòng)檢測(cè)工具
JSLint、JSHint、ESLint對(duì)比
JSLint
2002 年,Douglas Crockford 開發(fā)了可能是第一款針對(duì) JavaScript 的語(yǔ)法檢測(cè)工具 —— JSLint,并于 2010 年開源。
JSLint 面市后,確實(shí)幫助許多 JavaScript 開發(fā)者節(jié)省了不少排查代碼錯(cuò)誤的時(shí)間。
但是 JSLint 的問(wèn)題也很明顯:
- 幾乎不可配置,所有的代碼風(fēng)格和規(guī)則都是內(nèi)置好的;
- 再加上 JSLint 作者冷處理方式,不會(huì)向開發(fā)者妥協(xié)開放配置或者修改他覺(jué)得是對(duì)的規(guī)則。
JSHint
于是 Anton Kovalyov 吐槽:「JSLint 是讓你的代碼風(fēng)格更像 Douglas Crockford 的而已」,并且在 2011 年 Fork 原項(xiàng)目開發(fā)了 JSHint。
JSHint 的特點(diǎn)就是:
- 可配置,
- 同時(shí)文檔也相對(duì)完善,
- 而且對(duì)開發(fā)者友好。
很快大家就從 JSLint 轉(zhuǎn)向了 JSHint。
ESLint
ESLint 的誕生
起初幾年,JSHint 一直是前端代碼檢測(cè)工具的首選,包括 Nicholas C. Zakas 也是 JSHint 的用戶。但在 2013 年,Zakas 大佬發(fā)現(xiàn) JSHint 已經(jīng)無(wú)法滿足自己定制化規(guī)則的需求,而且和 Anton 討論后達(dá)成共識(shí)這根本在不可能在 JSHint 上實(shí)現(xiàn)。同時(shí) Zakas 還設(shè)想發(fā)明一個(gè)基于 AST 的 lint,可以動(dòng)態(tài)執(zhí)行額外的規(guī)則,同時(shí)可以很方便的擴(kuò)展規(guī)則。
2013 年的 6 月份,Zakas 發(fā)布了全新的 lint 工具——ESLint。
ESLint的特點(diǎn):
- 可擴(kuò)展
- 每條規(guī)則獨(dú)立
- 可自定義規(guī)則
ESlint有一些內(nèi)置的規(guī)則讓你更容易上手,同時(shí)你可以隨時(shí)加載自己的規(guī)則。
發(fā)展&契機(jī)
ESLint 的出現(xiàn)并沒(méi)有撼動(dòng) JSHint 的霸主地位。由于前者是利用 AST 處理規(guī)則,用 Esprima 解析代碼,執(zhí)行速度要比只需要一步搞定的 JSHint 慢很多;其次當(dāng)時(shí)已經(jīng)有許多編輯器對(duì) JSHint 支持完善,生態(tài)足夠強(qiáng)大。真正讓 ESLint 逆襲的是 ECMAScript 6 的出現(xiàn)。
ES2015
2015 年 6 月,ES2015 規(guī)范正式發(fā)布。但是發(fā)布后,市面上瀏覽器對(duì)最新標(biāo)準(zhǔn)的支持情況極其有限。如果想要提前體驗(yàn)最新標(biāo)準(zhǔn)的語(yǔ)法,就得靠 Babel 之類的工具將代碼編譯成 ES5 甚至更低的版本,同時(shí)一些實(shí)驗(yàn)性的特性也能靠 Babel 轉(zhuǎn)換。這時(shí) JSHint 就略尷尬,ES2015 變化很大,短期內(nèi)無(wú)法完全支持。ESLint 可擴(kuò)展的優(yōu)勢(shì)一下就體現(xiàn)出來(lái)了,不僅可以擴(kuò)展規(guī)則,甚至連解析器也能替換。Babel 團(tuán)隊(duì)就為 ESLint 開發(fā)了 babel-eslint 替換默認(rèn)解析器,讓 ESLint 率先支持 ES2015 語(yǔ)法。
React&JSX
也是在 2015 年,React 的應(yīng)用越來(lái)越廣泛,誕生不久的 JSX 也愈加流行。ESLint 本身也不支持 JSX 語(yǔ)法。還是因?yàn)榭蓴U(kuò)展性,eslint-plugin-react[10] 的出現(xiàn)讓 ESLint 也能支持當(dāng)時(shí) React 特有的規(guī)則。
至此,ESLint 完美躺贏,替代 JSHint 成為前端主流工具
How--在RN項(xiàng)目中如何利用ESLint實(shí)現(xiàn)高效的代碼規(guī)范校驗(yàn)
ESLint的安裝
你可以使用 npm 安裝 ESLint,在JS工程的根目錄下執(zhí)行:
$ npm install eslint --save-dev
緊接著你應(yīng)該設(shè)置一個(gè)配置文件(初始化):
$ ./node_modules/.bin/eslint --init
之后,你可以在任何文件或目錄上運(yùn)行ESLint如下:
$ ./node_modules/.bin/eslint yourfile.js
也可以在全局而不是本地安裝 ESLint (使用 npm install eslint --global)。但是,你使用的任何插件或可共享配置都必須安裝在本地。
ESLint的配置
運(yùn)行 eslint --init 之后,.eslintrc 文件會(huì)在你的文件夾中自動(dòng)創(chuàng)建(文件格式可以是“.js”、“.json”等)。例如一個(gè).eslintrc.json文件內(nèi)容如下:
{
"env": {
"browser": true,
"es6": true,
"react-native/react-native": true
},
"parser": "babel-eslint",
"extends": [
"eslint:recommended",
"airbnb",
"plugin:react-native/all",
"plugin:flowtype/recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 6,
"sourceType": "module"
},
"plugins": [
"react",
"react-native",
"flowtype"
],
"rules": {
"react/jsx-filename-extension": "off",
"no-use-before-define": "off",
"react-native/sort-styles": "off",
"arrow-body-style": "off",
"indent": "off",
"react/jsx-indent": "off"
}
}
parser:解析器
如前述,ESLint支持替換默認(rèn)解析器。當(dāng)代碼中用到了一些比較新的語(yǔ)法特性(例如需要Babel轉(zhuǎn)換的一些新特性或?qū)嶒?yàn)特性)時(shí),就需要使用一些其他的解析器,例如babel-eslint。
當(dāng)然使用的前提是先在本地安裝對(duì)應(yīng)的解析器,例如:
npm install eslint babel-eslint --save-dev
安裝后在配置文件中,設(shè)置對(duì)應(yīng)的parser字段為自定義的解析器。(這里設(shè)置的為babel-eslint)
"parser": "babel-eslint",
extends:繼承
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"airbnb",
"plugin:react-native/all",
"plugin:flowtype/recommended"
],
可以繼承一些現(xiàn)有的規(guī)則配置(規(guī)則集合),例如ESLint內(nèi)置的推薦規(guī)則集(eslint:recommended),還有一些流行的第三方配置(例如:airbnb)或者第三方插件中的配置(例如:plugin:react/recommended)等。
- 可以指定繼承多個(gè)配置
- 繼承的配置可以是內(nèi)置配置,例如:"eslint:recommended"
- 可以是第三方配置包中的配置(例如eslint-config-airbnb),可以省略包名的前綴 eslint-config-,例如:"airbnb"
- 也可以是第三方插件中的配置, extends 屬性值可以由以下組成:(例如"plugin:react/recommended")
- plugin:
- 包名 (省略了前綴,比如,react)
- /
- 配置名稱 (比如 recommended)
- 繼承按順序依次繼承,如果有相同規(guī)則的設(shè)置,后面的會(huì)覆蓋前面的
plugins:插件
ESLint 支持使用第三方插件。在使用插件之前,你必須使用 npm 安裝它。
在配置文件里配置插件時(shí),可以使用 plugins 關(guān)鍵字來(lái)存放插件名字的列表。插件名稱可以省略 eslint-plugin- 前綴。
注意:插件是相對(duì)于 ESLint 進(jìn)程的當(dāng)前工作目錄解析的。換句話說(shuō),ESLint 將加載與用戶通過(guò)從項(xiàng)目 Node 交互解釋器運(yùn)行 ('eslint-plugin-pluginname') 獲得的相同的插件。
當(dāng)你需要自定義一些ESLint沒(méi)有提供規(guī)則的時(shí)候就需要用的插件,可以通過(guò)自定義或者使用別人開發(fā)好的插件來(lái)加入一些新的代碼規(guī)則。
配置包(eslint-config-) VS 插件(eslint-plugin-)
相同點(diǎn)
- 都是 npm 包
- 都可以共享,通過(guò)npm可以安裝別人分享的包
- 都可以對(duì)ESLint默認(rèn)的規(guī)則進(jìn)行設(shè)置
- 都可以提供規(guī)則集(配置)
不同點(diǎn)
- 配置包(eslint-config-),只是對(duì)已有規(guī)則的修改、聚合等
- 插件(eslint-plugin-),也可以提供配置,同時(shí)可以新增自定義規(guī)則
rules:規(guī)則
可以在rules中添加一些額外的規(guī)則(除extends繼承的配置中啟用的),或者對(duì)extends引入的規(guī)則進(jìn)行二次定制。
-
規(guī)則啟用狀態(tài)設(shè)置:要改變一個(gè)規(guī)則設(shè)置,你必須將規(guī)則 ID 設(shè)置為下列值之一:
- "off" 或 0 - 關(guān)閉規(guī)則
- "warn" 或 1 - 開啟規(guī)則,使用警告級(jí)別的錯(cuò)誤:warn (不會(huì)導(dǎo)致程序退出)
- "error" 或 2 - 開啟規(guī)則,使用錯(cuò)誤級(jí)別的錯(cuò)誤:error (當(dāng)被觸發(fā)的時(shí)候,程序會(huì)退出)
-
額外選項(xiàng)設(shè)置:如果一個(gè)規(guī)則有額外的選項(xiàng),你可以使用數(shù)組字面量指定它們,比如:
{ "rules": { "quotes": ["error", "double"] } }
"quotes": ["error", "double"] 為規(guī)則 quotes 指定了 “double”選項(xiàng)(雙引號(hào))。數(shù)組的第一項(xiàng)總是規(guī)則的嚴(yán)重程度(數(shù)字或字符串)。
-
配置定義在插件中的一個(gè)規(guī)則的時(shí)候,你必須使用 插件名/規(guī)則ID 的形式。比如:
"rules": { "react/jsx-filename-extension": "off", "react/jsx-indent": "off" }注意:當(dāng)指定來(lái)自插件的規(guī)則時(shí),確保刪除 eslint-plugin- 前綴。ESLint 在內(nèi)部只使用沒(méi)有前綴的名稱去定位規(guī)則。
ESLint與開發(fā)環(huán)境(工具)集成
WebStorm
- 進(jìn)入ESLint設(shè)置:
Preferences->Languages & Frameworks->JavaScript->Code Quality Tools->ESLint - 選擇
Menual ESlint configuration -
ESlint package設(shè)置為全局路徑(如果是本地安裝,選擇本地路徑):/usr/local/lib/node_modules/eslint - 將
Configuration file路徑手動(dòng)設(shè)置為項(xiàng)目 eslint 配置文件的路徑,例如:/Users/xxx/Documents/work_6/JD_Recharge/RN_Recharge/jdreact-jsbundle-jdreactrechargemodule/.eslintrc.json

設(shè)置好以后,WebStorm就會(huì)自動(dòng)檢測(cè)工程中的代碼,并會(huì)在發(fā)現(xiàn)的錯(cuò)誤(或不符合規(guī)范)處進(jìn)行波浪線標(biāo)注,例如:

Tips
1.sourceType 是什么意思?
sourceType 有兩個(gè)值,script 和 module。 對(duì)于 ES6+ 的語(yǔ)法和用 import / export 的語(yǔ)法必須用 module.
2. eslint --init
只有在選擇 "To check syntax, find problems, and enforce code style" 才可以選擇 airbnb, standard, recommended 標(biāo)準(zhǔn)。
3. 環(huán)境
有時(shí)候在前端項(xiàng)目中存在前端和 node 的代碼共存的情況,只要在 env 中配置好 browser: true, node: true 就可以把兼容不同環(huán)境的全局變量兼容進(jìn)來(lái),例如 nodejs 中的 global, process 等等。
4. 常見規(guī)則強(qiáng)度
規(guī)則強(qiáng)度是 airbnb > standard > recommended. 看下圖,
recommended 和 standard 大概有 88 出不同,主要是 recommended 很多都是 off, standard 是 error, 同時(shí) standard 還有很多特有的規(guī)則。


5. 關(guān)于自動(dòng)修復(fù)
現(xiàn)在代碼都比較嚴(yán)格,可能包含縮進(jìn)是 2 個(gè)空格,是否在語(yǔ)句最后加逗號(hào)的情況。不可能自己手動(dòng)去一個(gè)個(gè)修正。
eslint ./src --fix
加上 --fix 可以自動(dòng)修正一些明顯的問(wèn)題。
參考:
前端工具考 - ESLint 篇:ESLint的誕生和發(fā)展