(TODO)ESLint规范

如何使用ESLint

本地全局安装后,先通过npm init初始化项目,然后通过eslint –init,交互式的填写信息,即可为你生成一个.eslint配置文件

JS编码规范

公司的规范

详见这个文档,由架构组的同事王一帆编写。

airbnb

https://github.com/airbnb/javascript

这是爱彼迎(美国短租平台)的编码规范,是github上star最多的标准,具体内容尚待阅读。文档里面给每一种规范都注明了原因。

这里不光有规范,还有很多编程技巧,很值得一看。

standard

https://github.com/standard/standard

关于规范的讨论

Expected linebreaks to be ‘LF’ but found ‘CRLF’.

VSCode右下角点击可以给当前文件设置文件风格

如需全局设置,可以打开setting,将files.eol设置为\n或者\r\n

const

初始化后没有变更的变量,都用const定义。

缩进到底4个空格还是2个空格?

2个空格缩进

1
"indent": ["error", 4] 

一般来说如果一个语言可能导致的缩进层次很多的话,缩进的空格就会减少,这样才能最大限度避免自动折行和行过长问题。。。

像C这样的语言,默认缩进只有一层,也就是函数体,绝大部分代码都是写在函数体内,缩进空格加长也能避免程序员写出各种莫名其妙的控制流语句嵌套(for嵌for,if嵌if),过多的嵌套层次是邪恶的,应该抽出成为独立的函数。

到了C#/Java这样的语言,默认缩进层次一下子就增加到了三层,命名空间,类,方法,如果这个时候还采用8空格缩进,那么基本上有用的代码在第24个字符的地方才会出现,一般一个屏幕一行显示80-120个字符,那么意味着基本上1/3-1/4个屏幕都是空白的,这是巨大的浪费,所以这些语言的程序员和规范,都不可能再采用8空格缩进,以4空格缩进和2空格缩进居多。

如何通过代码美化插件自动调整整个文件的缩进?

如何修改tab缩进的空格数?

字符串用单引号还是双引号?

用单引号

1、方便插入html(html里面的节点属性一般都是用双引号)

2、随大流,国外的code,大部分都是用单引号

函数必须先定义,后使用

没有用到的参数,应该以下划线开头命名

不要用+连接字符串,用`来连接

匿名函数全部通过箭头函数的形式来定义,不要用function定义

匿名函数的参数必须加中括号

???

调用属性,不要用中括号,用点号

行末加不加分号?

加。避免ASI在判断一行是否结束时出现问题。

Why? When JavaScript encounters a line break without a semicolon, it uses a set of rules called Automatic Semicolon Insertion to determine whether or not it should regard that line break as the end of a statement, and (as the name implies) place a semicolon into your code before the line break if it thinks so. ASI contains a few eccentric behaviors, though, and your code will break if JavaScript misinterprets your line break. These rules will become more complicated as new features become a part of JavaScript. Explicitly terminating your statements and configuring your linter to catch missing semicolons will help prevent you from encountering issues.

配置文件

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
{
"name": "pacific-vis-2025",
"version": "0.0.0",
"description": "The code for the Visual Data Storytelling Contest held at Pacific Vis 2025.",
"keywords": [
"3D",
"Visualization",
"Pacific Vis 2025"
],
"homepage": "#readme",
"repository": {
"type": "git",
"url": ""
},
"license": "MIT",
"engines": {
"node": ">=16"
},
"author": "",
"exports": {
"import": "./index.esm.js",
"require": "./index.umd.js",
"browser": "./index.umd.js"
},
"main": "./index.umd.js",
"module": "./index.esm.js",
"browser": "./index.umd.js",
"types": "./types/index.d.ts",
"scripts": {
"build:docs-html": "generate-md --layout github --input ./docs --output ./docs-html",
"serve": "node scripts/serve.cjs",
"lint:js": "eslint src/ --config=.eslintrc.cjs --ext=.js,.ts --fix --quiet --cache --cache-location=node_modules/.cache/.eslintcache --format=pretty",
"lint": "npm run lint:js",
"test": "jest --passWithNoTests",
"test-watch": "jest --passWithNoTests --watch",
"tsc:types:check": "tsc --noEmit",
"tsc:types:build": "tsc --emitDeclarationOnly",
"tsc:types:build-watch": "tsc --emitDeclarationOnly --watch",
"build:types": "node scripts/run-cli.cjs \"npm run tsc:types:build\"",
"build-watch:types": "node scripts/run-cli.cjs \"npm run tsc:types:build-watch\" --silent",
"build": "npm run build:types && npm run test & cross-env NODE_ENV=production rollup --config",
"build-dev": "npm run build:types && npm run test & cross-env NODE_ENV=development rollup --config",
"build-watch": "cross-env NODE_ENV=development rollup --config --watch",
"build-watch-serve": "cross-env NODE_ENV=development rollup --config --watch --serve",
"esbuild-build-watch": "cross-env NODE_ENV=development node scripts/esbuild-watch.cjs",
"esbuild-build-watch-serve": "cross-env NODE_ENV=development node scripts/esbuild-watch.cjs --serve",
"dev": "concurrently --raw --kill-others \"npm:build-watch\" \"npm:build-watch:types\"",
"dev-serve": "concurrently --raw --kill-others \"npm:build-watch-serve\" \"npm:build-watch:types\"",
"esbuild-dev": "concurrently --raw --kill-others \"npm:esbuild-build-watch\" \"npm:build-watch:types\"",
"esbuild-dev-serve": "concurrently --raw --kill-others \"npm:esbuild-build-watch-serve\" \"npm:build-watch:types\"",
"commit": "cz",
"prerelease": "npm run test",
"release": "release-it",
"prepublishOnly": "npm run build"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"files": [
"build/",
"types/",
"index.esm.js",
"index.umd.js"
],
"devDependencies": {
"@babel/core": "7.23.9",
"@babel/plugin-proposal-decorators": "7.23.9",
"@babel/plugin-transform-runtime": "7.23.9",
"@babel/preset-env": "7.23.9",
"@babel/preset-typescript": "7.23.3",
"@commitlint/cli": "18.6.1",
"@commitlint/config-conventional": "18.6.3",
"@king-fisher/eslint-config": "^0.0.12",
"@release-it/conventional-changelog": "8.0.1",
"@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-commonjs": "25.0.7",
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-node-resolve": "15.2.3",
"@rollup/plugin-replace": "5.0.2",
"@rollup/plugin-strip": "3.0.4",
"@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-url": "8.0.2",
"@rollup/plugin-virtual": "3.0.2",
"@types/d3": "^7.4.0",
"@types/dat.gui": "^0.7.7",
"@types/jest": "29.5.3",
"@types/node": "20.11.30",
"@types/stats.js": "^0.17.0",
"@types/three": "0.172.0",
"@typescript-eslint/eslint-plugin": "6.20.0",
"@typescript-eslint/parser": "6.20.0",
"@wang1212/eslint-config": "0.4.0",
"babel-jest": "29.6.2",
"browser-sync": "2.29.3",
"commitizen": "4.3.0",
"concurrently": "8.2.2",
"cross-env": "7.0.3",
"cz-conventional-changelog": "3.3.0",
"esbuild": "0.15.12",
"esbuild-style-plugin": "1.6.3",
"eslint": "8.56.0",
"eslint-formatter-pretty": "5.0.0",
"eslint-plugin-etc": "^2.0.3",
"fs-extra": "11.2.0",
"jest": "29.6.2",
"jest-environment-jsdom": "29.6.2",
"lint-staged": "15.2.5",
"markdown-styles": "3.2.0",
"prettier": "3.2.5",
"release-it": "17.0.3",
"rollup": "2.79.1",
"rollup-plugin-esbuild": "5.0.0",
"rollup-plugin-filesize": "10.0.0",
"rollup-plugin-progress": "1.1.2",
"rollup-plugin-styles": "4.0.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-visualizer": "5.12.0",
"sass": "1.70.0",
"typescript": "5.3.3"
},
"dependencies": {
"@babel/runtime": "^7.22.6",
"core-js": "^3.32.0",
"d3-scale": "^4.0.2",
"dat.gui": "^0.7.9",
"eventemitter3": "^5.0.0",
"gsap": "^3.11.5",
"meshline": "^3.1.6",
"postprocessing": "^6.30.1",
"stats.js": "^0.17.0",
"three": "0.172.0",
"three-stdlib": "^2.35.7",
"three.interactive": "^1.6.1",
"xlsx": "^0.18.5"
}
}

.eslintrc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// see docs: https://eslint.org/docs/user-guide/configuring

module.exports = {
root: true,
parser: 'espree', // 使用默认 JS 解析器
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
},
env: {
es6: true,
commonjs: true,
browser: true,
},
// 前端架构组的规范
/**
* @see: http://cf.myhexin.com/pages/viewpage.action?pageId=1015984061
*/
extends: ['@king-fisher/eslint-config'],

settings: {},
rules: {
'import/prefer-default-export': 'off',
'no-underscore-dangle': 'off',
'@typescript-eslint/no-this-alias': 'off',
'class-methods-use-this': 'off',
'no-unused-expressions': 'error',
'no-empty': 'error',
'no-empty-pattern': 'error',
},
ignorePatterns: [
'node_modules',
'dist',
'build',
'coverage',
'assets',
'public',
'docs',
'types',
'vendors',
'.babelrc.cjs',
'.commitlintrc.cjs',
'.eslintrc.cjs',
'.lintstagedrc.mjs',
'jest.config.mjs',
'index.esm.js',
'index.umd.js',
],
globals: {},
// TypeScript 配置
overrides: [
{
files: ['src/**/*.ts', 'src/**/*.tsx'],
// extends: ['@wang1212/eslint-config/typescript'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
sourceType: 'module',
},
env: {
node: true,
browser: true,
es6: true,
jest: false,
},
plugins: ['etc'],
settings: {},
rules: {
'import/prefer-default-export': 'off',
'no-underscore-dangle': 'off',
'@typescript-eslint/no-this-alias': 'off',
'class-methods-use-this': 'off',
// 检查被注释掉的代码
'etc/no-commented-out-code': 'error',
},
globals: {},
},
],
};

no-commented-out-code(不允许注释掉的代码)

需要借助第三方包来实现:
https://github.com/cartant/eslint-plugin-etc/

验证

类似这样命令行验证:

1
2
npx eslint examples/multi.js
npx eslint src/core/RenderEngine.ts

配置检查规则

可以参考这个项目:
https://github.com/wang1212/eslint-config
将规则打包为npm包,然后给项目复用。
项目中只需要安装该包,然后配置对应的插件即可:

1
2
3
module.exports = {
extends: ['@wang1212/eslint-config/typescript']
}

配置TypeScript和JavaScript混合项目

通过overrides进行配置,参考上面的.eslintrc的示例。

常见问题

如何关闭检查?

关闭整个eslint:

在file -> preferences -> settings中,搜索eslint,将enable配置改为false即可。

如果你发现安装了eslint,但是没有生效,也可以检查下是不是这个配置导致的。

关闭当前文件:

1
/* eslint-disable */

关闭代码块:

1
2
3
/* eslint-disable */
代码块
/* eslint-enable */

关闭当前行:

1
一行代码 // eslint-disable-line

关闭下一行:

1
2
// eslint-disable-next-line
下一行的代码

怎么关闭console检查?

1
2
3
"rules": {
"no-console": "off",
}

如何引入jquery?

在.eslintrc.js中添加如下内容:

1
2
3
4
5
6
'env': {
'browser': true,
'es6': true,
// 添加这一行
'jquery': true,
},

ESLint不生效

我遇到一种情况,是我的.eslintrc.js配置文件写错了,我为了不强制返回return,加了这么一行:

1
2
3
4
'rules': {
// 不强制方法必须有return
'treatUndefinedAsUnspecified': true
}

结果就导致整个ESLint不生效了,折腾半天也没找到原因,VSCode没有任何提示。后来我命令行eslint xxx.js测试了下,才发现是配置有误。

正确的应该是这样(可以看到,我前面连配置的键名都配错了……):

1
2
3
4
'rules': {
// 不强制方法必须有return
'consistent-return': 0
}

需要注意,ESLint禁用某个配置,不是写false,而是写0:

Severity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed ‘false’).