предисловие
Сяо Шэнь — фронтенд-стажер, который только начал работать, это первый опыт командной разработки, и неизбежно, что он немного нервничает. По договоренности с наставником я получил git-разрешение проекта и начал клонировать.
$ git clone git@github.com:company/project.git
Сяо Шэнь начал смаковать код своих коллег и, наконец, своими неустанными усилиями обнаружил ошибку, написанную Фараоном 2 года назад, и, сообщив о ней наставнику, начал ее модифицировать. Молодым людям легко быть импульсивными, они не только исправили баг Лао Ванга, но и провели рефакторинг этой части кода, используя паттерн стратегии, который я только что выучил из книги два дня назад, и убрали кое-какую ненужную if else логику. Сяо Шэнь небрежно погладил свои редеющие волосы, с гордостью готовясь отправить код, думая, что он продемонстрирует свои способности к суперкодированию в первый же день прибытия. Потом случилось ужасное.Код не смог пройти детектирование lint tool.Он так волновался,что покраснел и побежал спрашивать у репетитора.Тьютор сказал ему,что ему просто нужно модифицировать код согласно предупреждению на консоль. Сяо Шэнь возразил, что этот инструмент должен позволить мне удалить точку с запятой.Когда я учился в школе, учитель учил меня, что точка с запятой необходима, а код без точки с запятой не идеален. Наставник беспомощно улыбнулся, открыл оценочный лист стажировки Сяошэня и поставил отметку «плохо» в пункте командной работы.
Сяо Шэнь, которого это не убедило, написал блог и разместил его на CSDN, получив много прочтений.
В: Какие ошибки допустил Сяо Шэнь в первый рабочий день?
- Рефакторинг незнакомого бизнес-кода — табу в развитии бизнеса;
- Несоблюдение командных норм, развитие команды при слишком сильных личных эмоциях;
- Все вышеперечисленное выдумано мной, я слышал, что теперь я должен придумывать историю в начале статьи.
Краткая история инструмента lint
В компьютерных науках lint — это название инструмента, используемого для пометки подозрительных, неструктурированных (потенциально вызывающих ошибки) утверждений в коде. Это инструмент статического анализа программ, впервые примененный к языку C и разработанный на платформе UNIX. Позже он стал общим термином, который можно использовать для описания инструмента на любом языке программирования для пометки сомнительных операторов в коде. -- по википедии
В разработке JavaScript за более чем 20 лет было много инструментов lint, давайте представим три основных инструмента lint.
- JSLint
- JSHint
- ESLint
JSLint
Можно сказать, что JSLint — это самый ранний инструмент lint для JavaScript, разработанный Дугласом Крокфордом (автором книги «Сущность языка JavaScript»). Из стиля написания "Сущности языка JavaScript" видно, что Дуглас - человек, не терпящий недостатков в своих глазах, поэтому JSLint также наследует эту особенность. Все правила JSLint определены самим Дугласом. Он может Надо сказать, что это чрезвычайно первоклассный инструмент с личным стилем Дугласа, и если вы хотите его использовать, вы должны принять все его правила. Надо отдать должное, JSLint все еще обновляется, и также доступна версия узла:node-jslint.
JSHint
Так как JSLint сделал свои правила невыносимыми для многих людей и чувствовал себя угнетенным, Антон Ковалев (сейчас в Medium) разработал JSHint на основе JSLint. JSHint предоставляет множество элементов конфигурации на основе JSLint, предоставляя разработчикам большую свободу.JSHint с самого начала поддерживал стиль программного обеспечения с открытым исходным кодом, управляемый сообществом, и быстро развивался. В первые дни jQuery также использовал JSHint для проверки кода, но теперь он перешел на ESLint.
ESLint
ESLint был создан Николасом С. Закасом (автором книги «Расширенное программирование на JavaScript») в июне 2013 года. Он появился потому, что Закас хотел использовать JSHint для добавления пользовательского правила, но обнаружил, что JSHint его не поддерживает, поэтому он разработал его самостоятельно. .
ESLint известен как инструмент JS Linter следующего поколения.Он основан на PHP Linter, который анализирует исходный код в AST, а затем обнаруживает AST, чтобы определить, соответствует ли код правилам. ESLint использует esprima для анализа исходного кода в AST, а затем вы можете использовать произвольные правила, чтобы проверить, соответствует ли AST ожидаемому, поэтому ESLint обладает высокой масштабируемостью.
var ast = esprima.parse(text, { loc: true, range: true }),
walk = astw(ast);
walk(function(node) {
api.emit(node.type, node);
});
return messages;
Однако в то время ESLint не имел большого успеха, потому что ему нужно было конвертировать исходный код в AST, и он проигрывал JSHint по скорости работы, а у JSHint уже на тот момент была идеальная экология (поддерживаемая редакцией). . Что действительно зажгло ESLint, так это появление ES6.
После выпуска ES6 JSHint не сможет обеспечить поддержку в краткосрочной перспективе из-за добавления большого количества синтаксиса, а ESLint нужен только подходящий синтаксический анализатор, чтобы иметь возможность выполнять проверку lint. В это время babel обеспечил поддержку ESLint и разработал babel-eslint, что сделало ESLint самым быстрым инструментом lint, поддерживающим синтаксис ES6.
В 2016 году ESLint интегрировал еще один инструмент lint, который родился в то же время: JSCS, потому что он имеет ту же цель, что и ESLint, создавая AST для обнаружения правил.
С тех пор ESLint доминировал в области JS Linter и стал основным инструментом в мире фронтенда.
Значение инструментов Lint
Давайте подумаем над вопросом: является ли инструмент Lint гарантией качества кода или ограничением для инженеров?
Затем давайте взглянем на введение официального сайта ESLint:
Инспекция кода — это статический анализ, который часто используется для поиска проблемных шаблонов или кода и не привязан к определенному стилю кодирования. Проверка кода доступна для большинства языков программирования, и обычно компиляторы имеют встроенные инструменты проверки.
JavaScript — это динамический язык со слабой типизацией, подверженный ошибкам при разработке. Поскольку программа не компилируется, часто требуется постоянная отладка во время выполнения, чтобы найти ошибки в коде JavaScript. Что-то вроде ESLint позволяет программистам находить проблемы в процессе кодирования, а не в процессе выполнения.
Поскольку JavaScript — волшебный язык, он дает нам гибкость, но в то же время таит в себе некоторые подводные камни. Например==
Слабое преобразование типов действительно раздражает, иthis
Направление тоже сбивает с толку. Инструмент Lint очень хорошо решает эту проблему, и просто запрещает вам его использовать==
, хотя такой подход ограничивает гибкость языка, преимущества значительны.
Кроме того, поскольку это динамический язык, из-за отсутствия процесса компиляции некоторые ошибки, которые могут быть обнаружены в процессе компиляции, могут быть обнаружены только после запуска, что добавляет некоторую нагрузку на нашу работу по отладке, а инструмент Lint эквивалентен увеличению Чтобы понять процесс компиляции, перед запуском кода выполняется статический анализ, чтобы найти неправильное место.
Итак, резюмируя, преимущества инструмента Lint:
1. Избегайте низкоуровневых ошибок и находите возможные синтаксические ошибки
Использование необъявленных переменных, изменение константных переменных...
2. Предлагать удалить лишний код
Переменные объявлены, но не используются, повторяющиеся случаи...
3. Убедитесь, что ваш код соответствует лучшим практикам
Может относиться кairbnb style,javascript standard
4. Унифицируйте стиль кода команды
Добавлять или не ставить точку с запятой? Использовать табуляции или пробелы?
Как пользоваться
Сказав так много, давайте взглянем на практическое значение того, как используется ESLint.
инициализация
Если вы хотите внедрить ESLint в существующий проект, вы можете запустить следующую команду напрямую:
# 全局安装 ESLint
$ npm install -g eslint
# 进入项目
$ cd ~/Code/ESLint-demo
# 初始化 package.json
$ npm init -f
# 初始化 ESLint 配置
$ eslint --init
в настоящее время используетeslint --init
После этого появится множество элементов конфигурации пользователя.Подробнее см.:Исходный код части eslint cli.
После серии вопросов и ответов вы обнаружите, что.eslintrc.js
документ.
Метод конфигурации
Существует два метода настройки ESLint:
1. Используйте комментарии для встраивания правил lint непосредственно в исходный код
Это самый простой и грубый способ определить правила lint непосредственно в исходном коде, используя комментарии, которые может распознать ESLint.
/* eslint eqeqeq: "error" */
var num = 1
num == '1'
Конечно, мы обычно используем комментарии для временного подавления предупреждений от определенных строгих правил lint:
/* eslint-disable */
alert('该注释放在文件顶部,整个文件都不会出现 lint 警告')
/* eslint-enable */
alert('重新启用 lint 告警')
/* eslint-disable eqeqeq */
alert('只禁止某一个或多个规则')
/* eslint-disable-next-line */
alert('当前行禁止 lint 警告')
alert('当前行禁止 lint 警告') // eslint-disable-line
2. Используйте файлы конфигурации для настройки правила lint.
Во время инициализации одним из вариантов является тип файла, который следует использовать для конфигурации lint (What format do you want your config file to be in?
):
{
type: "list",
name: "format",
message: "What format do you want your config file to be in?",
default: "JavaScript",
choices: ["JavaScript", "YAML", "JSON"]
}
Официально есть три варианта:
- JavaScript (eslintrc.js)
- YAML (eslintrc.yaml)
- JSON (eslintrc.json)
Кроме того, вы также можетеpackage.json
файл добавленeslintConfig
поле для настройки.
Читать через ESLintисходный кодКак видите, приоритет его конфигурационного файла следующий:
const configFilenames = [
".eslintrc.js",
".eslintrc.yaml",
".eslintrc.yml",
".eslintrc.json",
".eslintrc",
"package.json"
];
.eslintrc.js > .eslintrc.yaml > .eslintrc.yml > .eslintrc.json > .eslintrc > package.json
Конечно, вы также можете использовать cli, чтобы самостоятельно указать путь к файлу конфигурации:
Конфигурация на уровне проекта и каталога
У нас есть следующая структура каталогов, в это время работает ESLint в корневом каталоге, тогда мы получим два файла конфигурации.eslintrc.js
(конфигурация на уровне проекта) иsrc/.eslintrc.js
(конфигурация на уровне каталога), два файла конфигурации будут объединены, ноsrc/.eslintrc.js
имеет более высокий приоритет.
Однако мы простоsrc/.eslintrc.js
Средняя конфигурация"root": true
, то ESLint подумает, чтоsrc
Каталог является корневым каталогом и больше не выполняет поиск конфигурации.
{
"root": true
}
Параметры конфигурации
Давайте подробнее рассмотрим правила настройки ESLinte.
Конфигурация парсера
{
// 解析器类型
// espima(默认), babel-eslint, @typescript-eslint/parse
"parse": "esprima",
// 解析器配置参数
"parseOptions": {
// 代码类型:script(默认), module
"sourceType": "script",
// es 版本号,默认为 5,也可以是用年份,比如 2015 (同 6)
"ecamVersion": 6,
// es 特性配置
"ecmaFeatures": {
"globalReturn": true, // 允许在全局作用域下使用 return 语句
"impliedStrict": true, // 启用全局 strict mode
"jsx": true // 启用 JSX
},
}
}
за@typescript-eslint/parse
Этот синтаксический анализатор в основном предназначен для замены существующего TSLint.Из-за процветания экосистемы ESLint и большего количества элементов конфигурации ESLint команде TS пришлось отказаться от TSLint и реализовать синтаксический анализатор ESLint. В то же время парсер имеетдругая конфигурация:
{
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"useJSXTextNode": true,
"project": "./tsconfig.json",
"tsconfigRootDir": "../../",
"extraFileExtensions": [".vue"]
}
}
Среда и глобальные переменные
ESLint обнаружит необъявленные переменные и выдаст предупреждение, но некоторые переменные объявлены представленной нами библиотекой, и здесь их нужно объявить в конфигурации заранее.
{
"globals": {
// 声明 jQuery 对象为全局变量
"$": false // true表示该变量为 writeable,而 false 表示 readonly
}
}
существуетglobals
Объявлять по одному несколько громоздко. В настоящее время вам нужно использоватьenv
, которые представляют собой пресеты для набора глобальных переменных, определяемых средой (аналогично пресетам Babel).
{
"env": {
"amd": true,
"commonjs": true,
"jquery": true
}
}
Есть много дополнительных сред, и значения по умолчаниюэтот файлОн определен в исходном коде, и, просмотрев исходный код, можно обнаружить, что все его предустановленные переменные ссылаются изglobals
Сумка.
Настройки правила
ESLint поставляется смного правил, вы можете сделать это в файле конфигурацииrules
Настройте нужные правила в свойствах. Каждое правило принимает параметр со следующими значениями:
- "off" или 0: отключить правило
- "предупреждать" или 1: включить правило, ошибка уровня предупреждения (не приведет к выходу из программы)
- «ошибка» или 2: Включить правило, ошибка уровня ошибки (при срабатывании программа завершает работу)
Например, давайте напишем фрагмент кода, использующий равенство, а затемeqeqeq
Правила настроены по-разному.
// demo.js
var num = 1
num == '1'
Здесь используется метод настройки командной строки.Если вы хотите проверить определенное правило только для одного файла, вы можете использовать этот метод.
Однако зачастую все не так просто, как мы думаем, правила ESLint не только просты, как закрытие и открытие, но каждое правило имеет свои собственные элементы конфигурации. Если вам нужно настроить правило, вам нужно использовать параметры в виде массива.
Посмотримquotes
Правила, согласно введению на официальном сайте, он поддерживает два элемента конфигурации, строку и объект.
{
"rules": {
// 使用数组形式,对规则进行配置
// 第一个参数为是否启用规则
// 后面的参数才是规则的配置项
"quotes": [
"error",
"single",
{
"avoidEscape": true
}
]
}
}
Согласно вышеприведенным правилам:
// bad
var str = "test 'ESLint' rule"
// good
var str = 'test "ESLint" rule'
расширять
Расширение состоит в том, чтобы напрямую использовать правила lint, написанные другими, что удобно и быстро. Расширения обычно поддерживают три типа:
{
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"eslint-config-standard",
]
}
-
eslint:
Начало официальное расширение ESLint, их два:eslint:recommended
,eslint:all
. -
plugin:
Начало в том, что расширение является подключаемым типом, и его также можно напрямуюplugins
свойств, которые будут подробно описаны в следующем разделе. - Последний тип расширения исходит из пакета npm, официально оговорено, что расширение пакета npm должно начинаться с
eslint-config-
В начале этот заголовок можно опустить при использовании, в вышеприведенном случаеeslint-config-standard
можно прямо сократить какstandard
.
Если вы удовлетворены своей конфигурацией, вы также можете опубликовать свою конфигурацию lint в пакете npm, просто назовите пакет какeslint-config-xxx
То есть одновременно вам нужно объявить номер версии ESLint, от которой вы зависите, в поле peerDependencies файла package.json.
плагин
Используйте плагины
Хотя официальный предоставляет сотни правил на выбор, но этого недостаточно, потому что официальные правила могут проверять только стандартный синтаксис JavaScript, если вы пишете однофайловые компоненты JSX или Vue, правила ESLint начинают беспомощны.
В настоящее время вам необходимо установить подключаемый модуль ESLint, чтобы настроить некоторые конкретные правила проверки. Как и расширения, плагины ESLint имеют фиксированный формат именования, начиная сeslint-plugin-
В начале вы также можете опустить этот заголовок при его использовании.
npm install --save-dev eslint-plugin-vue eslint-plugin-react
{
"plugins": [
"react", // eslint-plugin-react
"vue", // eslint-plugin-vue
]
}
Или внедрить плагины в расширения, как упоминалось ранее.plugin:
Начало заключается в том, что расширение предназначено для загрузки плагина.
{
"extends": [
"plugin:react/recommended",
]
}
Правила загрузки плагинов по расширению следующие:
extPlugin = `plugin:${pluginName}/${configName}`
По сравнению с приведенным выше случаем, имя плагина (pluginName) — это реакция, которая является предыдущей установкой.eslint-plugin-react
package, рекомендуется имя конфигурации (configName). Так откуда взялось это название конфигурации?
можно увидетьeslint-plugin-react
изисходный код.
module.exports = {
// 自定义的 rule
rules: allRules,
// 可用的扩展
configs: {
// plugin:react/recommended
recomended: {
plugins: [ 'react' ]
rules: {...}
},
// plugin:react/all
all: {
plugins: [ 'react' ]
rules: {...}
}
}
}
Имя конфигурации определяется атрибутом configs конфигурации плагина. Конфигурация здесь на самом деле является расширением ESLint. Таким образом, могут быть загружены как плагины, так и расширения.
разработать плагин
ESLint официально предоставляет шаблон Йомана (generator-eslint) для удобства разработчиков.
# 安装模块
npm install -g yo generator-eslint
# 创建目录
mkdir eslint-plugin-demo
cd eslint-plugin-demo
# 创建模板
yo eslint:plugin
Как только проект создан, пришло время приступить к созданию правила.К счастью, генератор-eslint имеет код шаблона для создания правил в дополнение к генерации кода шаблона для плагинов. Откройте созданный ранееeslint-plugin-demo
папку, добавьте правило в этот каталог, я надеюсь, что это правило может определить, есть ли в моем кодеconsole
, поэтому я назвал правило какdisable-console
.
yo eslint:rule
Далее посмотрим, как указать правило в ESLinte:
Открытымlib/rules/disable-console.js
, вы можете видеть, что код шаблона по умолчанию выглядит следующим образом:
module.exports = {
meta: {
docs: {
description: "disable console",
category: "Fill me in",
recommended: false
},
schema: []
},
create: function (context) {
// variables should be defined here
return {
// give me methods
};
}
};
Краткое введение в параметры (для более подробного ознакомления вы можете просмотретьофициальная документация):
- мета: некоторая информация описания правила
- docs: объект описания для правила
- description(string): Краткое описание правила
- category(string): Категория правила (конкретную категорию можно просмотретьОфициальный сайт)
- рекомендуется (логическое значение): присоединяться ли
eslint:recommended
- схема (массив): элементы конфигурации, принятые правилом
- docs: объект описания для правила
- create: возвращает объект, содержащий серию обработчиков событий, запускаемых ESLint при обходе кода JavaScript AST.
Прежде чем вдаваться в подробности создания правила, давайте поговорим об AST (абстрактном синтаксическом дереве). ESLint использует анализатор JavaScript под названием Espree для преобразования кода JavaScript в AST. Затем тщательно пройдитесь по AST, и каждое правило будет отслеживать процесс сопоставления. Чтобы облегчить просмотр различных типов узлов AST, вот веб-сайт, на котором можно четко увидеть внешний вид фрагмента кода после его разбора в AST:astexplorer. Если вы хотите найти тип всех узлов AST, вы можете увидетьestree.
можно увидетьconsole.log()
принадлежатьExpressionStatement(表达式语句)
серединаCallExpression(调用语句)
.
{
"type": "ExpressionStatement",
"expression": {
"type": "CallExpression",
"callee": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "console"
},
"property": {
"type": "Identifier",
"name": "log"
},
"computed": false
}
}
}
Итак, мы должны судить, вызывается ли кодconsole
, вы можете написать метод CallExpression в объекте, возвращаемом методом create, отслеживать оператор вызова в процессе обхода ESLint AST, а затем проверять, является ли оператор вызоваconsole
перечислить.
module.exports = {
create: function(context) {
return {
CallExpression(node) {
// 获取调用语句的调用对象
const callObj = node.callee.object
if (!callObj) {
return
}
if (callObj.name === 'console') {
// 如果调用对象为 console,通知 ESLint
context.report({
node,
message: 'error: should remove console'
})
}
},
}
}
}
Вы можете видеть, что мы, наконец, прошлиcontext.report
способ сообщить ESLint, что это проблемный фрагмент кода. Как с этим бороться, зависит от конфигурации ESLint. Правило[off, warn, error]
Который из .
Когда мы ввели правила раньше, было упомянуто, что правила можно настроить.Давайте посмотрим, как принимать элементы конфигурации, когда мы создаем наши собственные правила. На самом деле это очень просто, просто определите тип параметра в схеме объекта сопряжения, а затем в методе создания передайтеcontext.options
Возьми. следующая параdisable-console
Чтобы изменить, в конце концов, слишком строго запрещать все консоли, мы можем добавить параметр, который представляет собой массив, представляющий методы консоли, которые разрешено вызывать.
module.exports = {
meta: {
docs: {
description: "disable console", // 规则描述
category: "Possible Errors", // 规则类别
recommended: false
},
schema: [ // 接受一个参数
{
type: 'array', // 接受参数类型为数组
items: {
type: 'string' // 数组的每一项为一个字符串
}
}
]
},
create: function(context) {
const logs = [ // console 的所以方法
"debug", "error", "info", "log", "warn",
"dir", "dirxml", "table", "trace",
"group", "groupCollapsed", "groupEnd",
"clear", "count", "countReset", "assert",
"profile", "profileEnd",
"time", "timeLog", "timeEnd", "timeStamp",
"context", "memory"
]
return {
CallExpression(node) {
// 接受的参数
const allowLogs = context.options[0]
const disableLogs = Array.isArray(allowLogs)
// 过滤掉允许调用的方法
? logs.filter(log => !allowLogs.includes(log))
: logs
const callObj = node.callee.object
const callProp = node.callee.property
if (!callObj || !callProp) {
return
}
if (callObj.name !== 'console') {
return
}
// 检测掉不允许调用的 console 方法
if (disableLogs.includes(callProp.name)) {
context.report({
node,
message: 'error: should remove console'
})
}
},
}
}
}
После написания правил откройтеtests/rules/disable-console.js
, написать тестовые случаи.
var rule = require("../../../lib/rules/disable-console")
var RuleTester = require("eslint").RuleTester
var ruleTester = new RuleTester()
ruleTester.run("disable-console", rule, {
valid: [{
code: "console.info(test)",
options: [['info']]
}],
invalid: [{
code: "console.log(test)",
errors: [{ message: "error: should remove console" }]
}]
});
В конце концов, вам просто нужно ввести плагин, а затем включить правила.
// eslintrc.js
module.exports = {
plugins: [ 'demo' ],
rules: {
'demo/disable-console': [
'error', [ 'info' ]
],
}
}
лучшая конфигурация
В отрасли существует множество рекомендуемых стандартов кодирования для JavaScript, наиболее известными из которых являются следующие два:
Также рекомендуем AlloyTeameslint-config-alloy.
Однако лучше всего формулировать спецификации кода вместе с членами команды, чтобы убедиться, что все могут их принять.Если есть люди, у которых есть возражения, они могут подчиняться только большинству. Хотя заголовок этого раздела называется лучшей конфигурацией, но в индустрии программного обеспечения нет решения, которое было бы лучшим решением, даже стандарт javascript не является стандартом кодирования стандарта javascript, он просто называется именем, только подходящий - лучший.
Наконец, Amway будет использовать комбинацию ESLint и Prettier не только для унификации стандартов кодирования, но и для унификации стиля кода. Для конкретных практик, пожалуйста, обратитесь к моей статье:Используйте ESLint+Prettier для унификации стиля внешнего кода..
Суммировать
В связи с этим давайте подведем итоги.История разработки линтер-инструментов JavaScript на самом деле не коротка.Основная причина, по которой ESLint может догнать опоздавших, заключается в том, что JSLint и JSHint используют нисходящий подход к разбору кода и ранний синтаксис JavaScript. Если вы не будете обновлять его в течение десяти тысяч лет, вы сможете таким образом анализировать код с большей скоростью и находить возможные синтаксические ошибки и неправильные коды. Но после выхода ES6 синтаксис JavaScript претерпел массу изменений, таких как: стрелочные функции, шаблонные строки, операторы распространения и т. д. Выход этих синтаксисов делает невозможным обнаружение JSLint и JSHint кода ES6 без обновления парсера. . ESLint, с другой стороны, использует AST для статического анализа кода и сохраняет высокую масштабируемость и гибкие возможности настройки. Это также говорит нам о том, что в ежедневном процессе кодирования мы должны учитывать возможности последующего расширения.
Именно благодаря этой мощной возможности расширения многие стандарты кодирования JavaScript в отрасли могут быть быстро реализованы в различных командах, а стандарты кода, настроенные командой, также могут быть распространены извне.
Наконец, я надеюсь, что вы поняли преимущества ESLint благодаря вышеизложенному обучению, освоили использование ESLint и можете внедрить ESLint в существующие проекты, чтобы улучшить качество кода проекта.