- Адрес столбца:Компиляция и разработка интерфейса
- Автор этой статьи:соус НСГУФ
1. Предпосылки
javascript — это динамический язык со слабой типизацией, который компилируется во время выполнения, что приводит к множеству ошибок, которые могут быть обнаружены только во время выполнения, и их трудно найти в процессе кодирования;
eslint — подключаемый инструмент для обнаружения кода JS, разработчики могут писать свои собственные правила и находить несоответствующие позиции в исходном коде, чтобы помочь разработчикам найти проблемы в процессе программирования;
2 ворсовых инструмента
- JSLint: Обнаружение отправителя, прямое обнаружение строки исходного файла;меньше конфигурации,Строгие спецификации,Плохая масштабируемость,Не удалось найти соответствующее правило на основе ошибки;
- JSHint: Разработано на основе JSHint;Параметры правил можно настроить, предоставляя полный подключаемый модуль редактора, поддерживающий некоторые общие классы библиотек и es6, но не поддерживающий пользовательские правила и не могу найти соответствующие правила в соответствии с ошибками.;
- ESLint: На основе правил обнаружения дерева AST;Расширяемый синтаксический анализатор, расширяемые правила и конфигурация;
JSHint и ESlintФункции:
- JSHint напрямую определяет строку исходного файла, а ESLint преобразует исходный код в AST, а затем оценивает все правила, поэтому скорость выполнения JSHint будет выше, чем у ESlint;
- ESLint обладает хорошей масштабируемостью, ядром ESLint является определение того, соответствует ли AST правилам;
- Шаг 1: синтаксический анализатор преобразует исходный код в AST; синтаксический анализатор ESLint можно настраивать, исходный код использует любую расширенную грамматику или заменяется на TS, вы можете напрямую изменить синтаксический анализатор, чтобы получить окончательный AST, а eslint может выполнять сопоставление правил;
- Шаг 2: Правила выполнения, правила обнаружения ESLint могут быть настроены;
3 Основное использование
- Проект устанавливает eslint:
yarn add eslint -D
; - Инициализировать конфигурацию eslint: eslint --init;
- Обнаружить eslint: запустить eslint;
3.1 Основные параметры
Настроить параметры в eslint можно двумя способами, один через конфигурационный файл, а другой через командную строку, параметры конфигурационного файла не обязательно включают командную строку.Для удобства просмотра и использования,Рекомендуется сначала настроить его в конфигурации;
3.1.1 Параметры .eslintrc
Для получения подробной информации, пожалуйста, проверьтеESL int.org/docs/user —…;
module.exports = {
// 若项目中有多个子项目,且每个项目都会有.eslintrc,子项目会一直向上查找所有的.eslintrc,直到找到root:true的eslintrc,再将所有的.eslintrc合并
'root': true,
// 对环境定义的一组全局变量的预设 详细看:https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments
'env': {
// 浏览器全局变量
browser: true,
// Node.js 全局变量和作用域
node: true,
// CommonJS全局变量和CommonJS作用域
commonjs: true,
// 启用除模块之外的所有ECMAScript 6功能
es6: true
},
// 将数据提供给每一个将被执行的规则
"settings": {
"sharedData": "Hello"
},
// 继承另一个配置文件的所有特性
'extends': [
'eslint:recommended',
'plugin:@typescript-eslint/recommended'
],
// 插件,向ESLint添加各种扩展,可以定义规则,环境或配置的第三方模块
'plugins': [
'@typescript-eslint'
],
// 全局变量
'globals': {
// false、readable、readonly 这 3 个是等价的,表示变量只可读不可写;
// true、writeable、writable 这 3 个是等价的,表示变量可读可写;
'$': true,
'console': false
},
// 解释器
'parser': '@typescript-eslint/parser',
// 解释器的配置
'parserOptions': {
// 代码模块类型,可选script(默认),module
'sourceType': 'module',
// 指定ECMAScript版本,默认为5
'ecamVersion': 6,
// 额外的语言特性,所有选项默认都是 false
'ecmaFeatures': {
// 是否允许 return 语句出现在 global 环境下
'globalReturn': true,
// 是否开启全局 script 模式
'impliedStrict': true,
// 是否启用 JSX
'jsx': true,
// 是否启用对实验性的objectRest/spreadProperties的支持
'experimentalObjectRestSpread': false
}
},
// 规则
'rules': {
// 禁止使用 alert
'no-alert': 'off',
// 逗号前面没有空格 后面有空格
'comma-spacing': [2, {
'before': false, 'after': true
}],
}
};
3.1.2 Параметры командной строки
Для получения подробной информации, пожалуйста, проверьтеESL от /docs/user-a…;
eslint [options] file.js [file.js] [dir]
Basic configuration:
--no-eslintrc 禁止使用配置文件.eslintrc.*
-c, --config path::String 指定使用.eslintrc.*配置文件的路径(可以不是这个名字)
--env [String] 指定环境
--ext [String] 指定JavaScript文件扩展名,默认值:.js
--global [String] 定义全局变量
--parser String 指定解析器
--parser-options Object 指定解析器配置
--resolve-plugins-relative-to path::String 应该从中解析插件的文件夹,默认为CWD
Specifying rules and plugins:
--rulesdir [path::String] 使用其他规则的目录
--plugin [String] 指定插件
--rule Object 指定规则
Fixing problems:
--fix 自定修复eslint问题
--fix-dry-run 自动修复问题但不保存对文件的更改
--fix-type Array 指定要应用的修复类型(问题、建议、布局)
Ignoring files:
--ignore-path path::String 指定忽略的路径 即指定一个文件作为.eslintignore
--no-ignore 禁用忽略文件和模式的使用
--ignore-pattern [String] 要忽略的文件模式(除了.eslintignore中的文件)
Using stdin:
--stdin <STDIN>上提供的Lint代码-默认值:false
--stdin-filename String 指定STDIN的文件名
Handling warnings:
--quiet 仅报告错误-默认值:false
--max-warnings Int 触发退出代码的警告次数-默认值:-1
Output:
-o, --output-file path::String 指定要将报告写入的文件
-f, --format String 使用特定的输出格式-默认值:stylish
--color, --no-color 强制启用/禁用颜色
Inline configuration comments:
--no-inline-config 防止注释更改配置或规则
--report-unused-disable-directives 添加错误信息给未被使用的eslint-disable指令
Caching:
--cache 仅检查已更改的文件-默认值:false
--cache-file path::String 缓存文件的路径,不推荐使用:使用--cache-location - 默认值:.eslintcache
--cache-location path::String 缓存文件或目录的路径
Miscellaneous:
--init 运行配置初始化向导-默认值:false
--debug 输出调试信息
-h, --help 显示help文档
-v, --version 输出版本号
--print-config path::String 打印给定文件的配置
3.2 Дополнение общих концепций параметров
3.2.1 Парсер
- esprima: парсер, использовавшийся на заре eslint;
- espree: разработан на основе esprema v1.2.2, теперь парсер по умолчанию;
- @babel/eslint-parser: синтаксический анализатор расширенной грамматики js;
- @typescript-eslint/parser: парсер для ts;
3.2.2 Конфигурация правил
- "off" или 0: отключить правило;
- "warn" или 1: включить правило, использовать ошибки уровня предупреждения: warn (не приводит к выходу из программы);
- «ошибка» или 2: включить правило, использовать уровень ошибки error: error (при срабатывании программа завершится);
3.2.3 Типы конфигурации, поддерживаемые расширениями
- Начиная с eslint: официальное расширение ESLint;
- В начале плагина: расширение типа плагина, однозначное соответствие с конфигурацией в конфигах;
- Начиная с пакета eslint-config: npm, вы можете опустить префикс eslint-config- при использовании;
- Путь к файлу;
Общие расширения:
- eslint:recommended: рекомендуемые встроенные правила ESLint, то есть те правила, которые отмечены галочкой в списке правил ESLint;
- eslint:all: все правила, встроенные в ESLint;
- eslint-config-standard: стандартная спецификация JS;
- eslint-config-prettier: закрывает конфликтующие правила в ESLint и других расширениях;
- eslint-plugin-vue: официальный плагин конфигурации eslint для vue.
- плагин:vue/база:база;
- плагин: vue/основной: существенный;
- плагин: vue/рекомендуется: рекомендуется;
- плагин: vue/настоятельно рекомендуется: настоятельно рекомендуется;
3.3 Настройка файлов или каталогов, для которых не требуется lint
Вы можете указать соответствующий файл или каталог в .eslintignore, чтобы избежать обнаружения при выполнении eslint (сам eslint игнорирует node_modules и bower_components), например:
mock
build/*.js
config/*.js
4 Совместное использование конфигурации ESLint
Спецификации каждой команды разные.Компания надеется, что спецификации каждой линейки продуктов согласуются, поэтому конфигурацию можно будет разделить и упаковать в пакет npm для прямой настройки и использования разными командами;
Как написать файл конфигурации?
- Создайте папку с именем eslint-config-myconfig;
- воплощать в жизнь
yarn init -y
; (имя модуля должно начинаться с eslint-config-, имя файла проекта указывать необязательно); - Создайте index.js и напишите в нем конфигурацию .eslintrc.js, которая будет использоваться совместно;
- использоватьpeerDependenciesESLint, от которого зависит объявление поля (явно плагину требуется ESLint для правильной работы);
- Вы можете отправить пакет;
PS: Все плагины, написанные в виде отправки пакетов, поддерживают форму @scope/eslint-xxx-xxx,Подробности;
Как использовать вышеуказанный пакет?
- Установите такие пакеты, как:
yarn add eslint-config-myconfig -D
; - Настройте конфигурацию расширений в файле .eslintrc в проекте и см. основные сведения об использовании;
5 Плагин ESLint
5.1 Что такое плагин ESLint?
Плагины могут добавлять в ESLint различные расширения и являются сторонними модулями, определяющими правила, среды, процессоры или конфигурации;
Как настроить плагин ESLint?
использоватьgenerator-eslintСоздайте проект. Имя модуля проекта должно начинаться с eslint-plugin-. При его использовании удалите eslint-plugin-;
Например, имя пакета npm: eslint-plugin-myplugin;
5.1.1 Определение правил
Правила: Правильный метод обнаружения eslint;
Метод определения: предусматривает, что объект правил должен быть выставлен;
// 这是插件的index.js
module.exports = {
rules: {
'my-rule': {
// 规则的一些数据配置
meta: {
// 规则的类型 "problem"、"suggestion" 或 "layout"
type: 'suggestion',
// 文档信息 自定义规则或插件中可省略,对eslint核心规则是必须的
docs: {
description: '规则的简短描述,在eslint规则首页展示',
category: '规则在规则首页处于的分类',
recommended: true, // "extends": "eslint:recommended"属性是否启用该规则
url: 'https://eslint.org/docs/rules/no-extra-semi' // 访问完整文档的 url
},
// 打开修复功能,如果没有 fixable 属性,即使规则实现了 fix 功能,ESLint 也不会进行修复。如果规则不是可修复的,就省略 fixable 属性
fixable: 'code',
// 指定该规则对应的配置,用于验证配置的选项是否有效
schema: [
{
"enum": ["always", "never"]
},
{
"type": "object",
"properties": {
"exceptRange": {
"type": "boolean"
}
},
"additionalProperties": false
}
]
},
// create 返回一个对象,对象的格式是key对应一个回调方法;这个对象包含了ESLint在遍历JavaScript代码的AST树(ESTree定义的AST)时,用来访问节点的方法。
// context 当前执行eslint时的上下文对象,其中包含了各种相关数据,如eslint的配置信息、当前遍历节点的信息、报告问题的方法等;
create: function (context) {
return {
// callback functions
ReturnStatement: function (node) {
// at a ReturnStatement node while going down
},
// at a function expression node while going up:
'FunctionExpression:exit': function checkLastSegment (node) {
// report problem for function if last code path segment is reachable
},
'ArrowFunctionExpression:exit': function checkLastSegment (node) {
// report problem for function if last code path segment is reachable
},
onCodePathStart: function (codePath, node) {
// at the start of analyzing a code path
},
onCodePathEnd: function (codePath, node) {
// at the end of analyzing a code path
}
};
}
}
}
};
Как использовать:
module.exports = {
"plugins": ["myplugin"],
"rules": {
"myplugin/my-rule": [2, "never", { "exceptRange": true }],
}
}
5.1.1.1 Параметры правил
Метапараметр правил предназначен для заполнения некоторой базовой информации, а значение параметра создания представляет собой метод обратного вызова, используемый для выполнения правила обнаружения AST;
Параметр контекста создания:
- id: имя правила, настроенное в правилах .eslintrc, как в случае использования выше.
myplugin/my-rule
; - options: параметры правила, настроенные в правилах .eslintrc, например результат приведенного выше примера: ["never", {exceptRange: true}]
- отчет: используется для выдачи предупреждений или ошибок, оценки вызова в обратном вызове;Конкретные параметры;
Дополнительные параметры контекста:ESL междунар. VELO для /docs/…;
Возвращаемый объект создания:
- Если ключ является типом узла или селектором, ввнизПри обходе дерева ESLint вызываетvisitorфункция;
- Если ключ является типом узла или селектором с:exit,существуетвверхПри обходе дерева ESLint вызываетvisitorфункция;
- Если ключ является именем события, ESLintАнализ пути кодапередачаhandlerфункция;
Тип узла:Тип узла AST;
детали следующим образом:
серийный номер | Введите исходное имя | китайское имя | описывать |
---|---|---|---|
1 | Program | тело программы | тело всего кода |
2 | VariableDeclaration | объявление переменной | объявить переменную, например, var let const |
3 | FunctionDeclaration | объявление функции | объявить функцию, например, function |
4 | ExpressionStatement | оператор выражения | Обычно путем вызова такой функции, как console.log() |
5 | BlockStatement | оператор блока | Код, заключенный в блок {}, например, if (condition) {var a = 1;} |
6 | BreakStatement | оператор перерыва | обычно относится к разрыву |
7 | ContinueStatement | оператор продолжения | обычно относится к продолжению |
8 | ReturnStatement | оператор возврата | обычно относится к возвращению |
9 | SwitchStatement | оператор переключения | Обычно относится к Switch в операторе Switch Case. |
10 | IfStatement | Если оператор управления потоком | Оператор потока управления, обычно называемый if(условие){}else{} |
11 | Identifier | идентификатор | Идентичности, такие как identi в var identi = 5 при объявлении переменной |
12 | CallExpression | выражение вызова | Обычно относится к вызову функции, такой как console.log(). |
13 | BinaryExpression | бинарное выражение | Обычно относится к операциям, таким как 1+2 |
14 | MemberExpression | выражение члена | Обычно относится к члену вызывающего объекта, например члену журнала консольного объекта. |
15 | ArrayExpression | выражение массива | Обычно относится к массиву, например [1, 3, 5] |
16 | NewExpression | Новое выражение | Обычно относится к использованию нового ключевого слова |
17 | AssignmentExpression | выражение присваивания | Обычно относится к значению возвращаемого функцией значения переменной |
18 | UpdateExpression | Обновить выражение | Обычно относится к обновлению значений членов, например i++ |
19 | Literal | буквальный | буквальный |
20 | BooleanLiteral | логический литерал | логическое значение, такое как true false |
21 | NumericLiteral | числовой литерал | число, например 100 |
22 | StringLiteral | символьный литерал | строка, например, vansenb |
23 | SwitchCase | Заявление о случае | Обычно относится к Case в операторе Switch. |
Кстати, вы можете взглянуть на типы узлов vue:GitHub.com/v UE JS/v UE - о...
селектор: это строка, которую можно использовать для сопоставления узлов в абстрактном синтаксическом дереве (AST). Это полезно для описания конкретных синтаксических шаблонов в коде. Селекторы не ограничиваются сопоставлением одного типа узла. Например, селектор «VariableDeclarator > Identifier» будет соответствовать всем идентификаторам, имеющим VariableDeclarator.Подробности;
мероприятие: анализ событий, вызванных кодовым путем;
module.exports = function(context) {
return {
/**
* 这在分析代码路径的开始时被调用,此时,代码路径对象只有初始段。
*
* @param {CodePath} codePath - The new code path.
* @param {ASTNode} node - The current node.
* @returns {void}
*/
"onCodePathStart": function(codePath, node) {
// do something with codePath
},
/**
* 这在分析代码路径的末尾被调用。此时,代码路径对象已经完成。
*
* @param {CodePath} codePath - The completed code path.
* @param {ASTNode} node - The current node.
* @returns {void}
*/
"onCodePathEnd": function(codePath, node) {
// do something with codePath
},
/**
* 这在创建代码路径段时调用。
* 这意味着代码路径是分叉或合并的。
* 在这段时间内,该段具有先前的段,并且已被判断为可到达或不可到达。
*
* @param {CodePathSegment} segment - The new code path segment.
* @param {ASTNode} node - The current node.
* @returns {void}
*/
"onCodePathSegmentStart": function(segment, node) {
// do something with segment
},
/**
* 这是在代码路径段离开时调用的。
* 此时还没进入下个阶段。
*
* @param {CodePathSegment} segment - The leaved code path segment.
* @param {ASTNode} node - The current node.
* @returns {void}
*/
"onCodePathSegmentEnd": function(segment, node) {
// do something with segment
},
/**
* 在代码路径段被循环时调用的。
* 通常每段在创建时都有以前的段,
* Usually segments have each previous segments when created,
* but when looped, a segment is added as a new previous segment into a
* existing segment.
*
* This is called when a code path segment was looped.Usually segments have each previous segments when created,but when looped, a segment is added as a new previous segment into aexisting segment.
*
* 当循环代码路径段时调用此函数。通常创建段时,段具有每个先前段,但循环时,段作为新的先前段添加到现有段中。
* @param {CodePathSegment} fromSegment - A code path segment of source.
* @param {CodePathSegment} toSegment - A code path segment of destination.
* @param {ASTNode} node - The current node.
* @returns {void}
*/
"onCodePathSegmentLoop": function(fromSegment, toSegment, node) {
// do something with segment
}
};
};
ESL междунар. VELO для /docs/…
5.1.2 Определение среды
Среда: это групповая конфигурация, например, jquery внутри всех глобальных переменных;
Среда плагина может определять следующие объекты:
глобальные:То же, что и глобальные переменные в файле конфигурации.
параметры парсера:То же, что и parserOptions в файле конфигурации.
Определение: объект окружения должен быть открыт;
// 这是插件的index.js
module.exports = {
environments: {
jquery: {
globals: {
$: false
},
parserOptions: {
}
}
}
};
Как использовать:
module.exports = {
"plugins": ["myplugin"],
"env": {
"myplugin/jquery": true,
}
}
5.1.3 Определение процессора
eslint может определять только js, если это другие файлы, то нужно настраивать кастомные процессоры;
Метод определения: процессоры должны быть открыты, с суффиксом файла в качестве ключа, включая функцию, которая принимает содержимое файла и имя файла в качестве параметров и возвращает массив строк для обнаружения;
// 这是插件的index.js
// processor-name
module.exports = {
processors: {
// 不同后缀名 (.js, .jsx, .html, etc.)
".ext": {
// 获取文件的文本和文件名
preprocess: function(text, filename) {
// 在这里,您可以去掉任何非JS内容,并将其拆分为多个字符串以进行lint
return [string]; // return an array of strings to lint
},
// 获取Message[][]和文件名
postprocess: function(messages, filename) {
// `messages`参数是一个包含消息对象的二维数组,其中每个数组项的第一个参数包含了preprocess()方法返回的文本相关的lint消息数组
// postprocess 方法接受一个二维数组,包含检测消息和文件名。输入数组中的每一项都对应从 preprocess 方法返回的部分。preprocess 方法必须调整所有错误的位置,使其与原始的未处理的代码中的位置相对应,并将它们聚合成一个打平的数组并返回。
// 返回你想保留的一维数组
return messages[0];
},
supportsAutofix: true // (optional, defaults to false)
}
}
};
Как использовать:
// 方式一:统一
module.exports = {
"plugins": ["myplugin"],
"processor": "myplugin/processor-name"
}
// 方式二:为特定类型的文件指定处理器
module.exports = {
"plugins": ["myplugin"],
"overrides": [
{
"files": ["*.md"],
"processor": "a-plugin/markdown"
},
{// 在 config 部分为命名代码块指定其他配置
"files": ["**/*.md/*.js"],
"rules": {
"strict": "off"
}
}
]
}
5.1.4 Определение конфигурации
В дополнение к совместному использованию конфигурации путем отправки пакетов напрямую (Пункт 4 этой главыметод), вы также можете поделиться конфигурацией в виде плагинов, а также поддерживает несколько конфигураций плагина; например, если вы написали несколько правил и хотите поделиться конфигурацией нескольких стилей кода с помощью способ, вы можете использовать это;
// 这是插件的index.js
module.exports = {
configs: {
myConfig: {
plugins: ["myPlugin"],
env: ["browser"],
rules: {
semi: "error",
"myPlugin/my-rule": "error",
"eslint-plugin-myPlugin/another-rule": "error"
}
},
myOtherConfig: {
plugins: ["myPlugin"],
env: ["node"],
rules: {
"myPlugin/my-rule": "off",
"eslint-plugin-myPlugin/another-rule": "off"
"eslint-plugin-myPlugin/yet-another-rule": "error"
}
}
}
};
Как использовать:
- Добавьте плагин в конфигурацию плагинов;
- Конфигурация расширения используется напрямую;
module.exports = {
plugins: ['myPlugin'],
extends: ['plugin:myPlugin/myConfig', 'plugin:myPlugin/myOtherConfig']
}
5.2 Как прописать правила отдельно в проекте?
Написание отдельного плагина требует упаковки, что приводит к длительному процессу добавления правил и не обязательно подходит для других линеек продуктов, в этом случае пользовательские правила нужно добавлять в одном проекте;
5.2.1 Метод 1: IDE не распознает
Используйте собственный параметр eslint --rulesdir, чтобы получить правила в дополнительных файлах проекта; этот метод действителен только при запуске команды eslint;
Шаги настройки:
- Добавьте папку eslint-rules в каталог того же уровня проекта .eslintrc и добавьте в этот каталог пользовательские правила (создание правила: 5.1.1);
- Добавьте соответствующее правило xxx:2 в правила в .eslintrc;
- Измените команду eslint на:
eslint --rulesdir eslint-rules --ext .vue,.js,.ts src
; (также можно настроить в webpack или vite)
Результаты: команда будет обнаружена;
Недостатки: Редактор его не распознает, и он будет помечать первую строку каждого файла красным, чтобы сказать, что соответствующее правило не может быть найдено, и реальная проблема не будет помечена красным;
5.2.2 Метод 2: распознавание IDE
Используйте плагин eslint-plugin-rulesdir;
шаг:
- Добавьте папку eslint-rules в каталог того же уровня проекта .eslintrc и добавьте в этот каталог пользовательские правила (создание правила: 5.1.1);
- Установитьплагин:
yarn eslint-plugin-rulesdir -D
; - Измените конфигурацию .eslintrc;
const rulesDirPlugin = require('eslint-plugin-rulesdir');
// 规则对应的目录 可以是字符串或字符串数组
rulesDirPlugin.RULES_DIR = 'eslint-rules';
module.exports = {
// ...
plugins: ['rulesdir'],
rules: {
// xxx为对应的自定义规则
'rulesdir/xxx': ['error'],
},
};
Результат: Не нужно указывать --rulesdir, правила распознаются, и редактор тоже распознает;
6 Оптимальное использование сопутствующих инженерных решений
Инжиниринг проекта может повысить эффективность разработки и уменьшить количество ошибок, которых легко избежать; ниже приведены некоторые полезные инструменты, которые можно использовать с eslint:
- husky: выполнить команду eslint перед фиксацией, если eslint не прошла, фиксация не удалась;
- lint-staged: Хуки запуска хаски только для полученных постановочных файлов;
- prettier: изменить стиль кода, независимо от стиля кода, независимо от некоторых низкоуровневых проблем; если есть какие-то конфигурации, конфликтующие с eslint, вы можете сотрудничатьeslint-plugin-prettierиспользуется с эслинтом;
- mrm: автоматическая установка и настройка husky и lint-staged в соответствии с package.json, поэтому обязательно перед этим установите и настройте все инструменты качества кода, такие как Prettier и ESlint;
Использование этих инструментов не будет повторяться, это относительно просто, просто проверьте официальные документы;