ESLint выполняет статический анализ JavaScript-кода, выявляя ошибки, нарушения стиля и потенциально проблемные конструкции ещё до запуска приложения. В связке с современными сборщиками особое значение приобретает корректная организация этапа линтинга, поскольку инструменты вроде esbuild ориентированы на скорость компиляции и минимальный overhead.
ESLint функционирует как независимый слой анализа исходного кода и не требует выполнения программы. Это позволяет интегрировать его практически в любую сборочную систему, включая esbuild, Rollup, Webpack и Vite.
В архитектуре фронтенд-сборки ESLint обычно размещается в отдельном этапе:
esbuild при этом выполняет исключительно трансформацию и бандлинг, не включая встроенный линтинг.
esbuild ориентирован на предельную производительность за счёт реализации на Go. Основные характеристики:
Такое разделение ответственности делает ESLint внешним инструментом, интегрируемым через CLI или API.
Наиболее распространённая архитектура включает два независимых процесса:
Пример разделения скриптов:
{
"scripts": {
"lint": "eslint src",
"build": "esbuild src/index.js --bundle --outfile=dist/app.js",
"dev": "npm run lint && npm run build"
}
}
Подход обеспечивает детерминированность: ошибки линтинга блокируют сборку.
ESLint CLI поддерживает кэширование, что критично при частых пересборках:
eslint "src/**/*.{js,ts}" --cache
Кэш уменьшает время повторного анализа, что особенно важно при watch-режиме esbuild.
Типовая конфигурация .eslintrc:
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended"
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"no-unused-vars": "warn",
"no-console": "off"
}
}
esbuild поддерживает плагины, позволяющие подключать сторонние инструменты анализа. ESLint может быть встроен через пользовательский плагин, вызывающий его Node.js API.
Пример плагина:
import { ESLint } from "eslint";
export function eslintPlugin() {
return {
name: "eslint-plugin",
setup(build) {
const eslint = new ESLint({ cache: true });
build.onEnd(async () => {
const results = await eslint.lintFiles(["src/**/*.js"]);
const formatter = await eslint.loadFormatter("stylish");
const resultText = formatter.format(results);
if (resultText) {
console.log(resultText);
}
const hasErrors = results.some(r =>
r.errorCount > 0
);
if (hasErrors) {
throw new Error("ESLint validation failed");
}
});
}
};
}
Использование в конфигурации esbuild:
import esbuild from "esbuild";
import { eslintPlugin } from "./eslint-plugin.js";
esbuild.build({
entryPoints: ["src/index.js"],
bundle: true,
outfile: "dist/app.js",
plugins: [eslintPlugin()]
});
Такой подход переводит ESLint в фазу post-build анализа, сохраняя скорость основной компиляции.
Комбинация ESLint и esbuild обычно строится по принципу разделения потоков:
Это разделение предотвращает деградацию производительности сборщика.
В больших проектах применяется параллельный запуск:
npm run lint & npm run build --watch
или через инструменты управления процессами:
{
"scripts": {
"dev": "concurrently \"eslint src --cache --watch\" \"esbuild src/index.js --bundle --watch\""
}
}
esbuild обеспечивает мгновенные пересборки, тогда как ESLint может стать узким местом при полном прогоне анализа.
Оптимизация достигается через:
--cacheПример ограниченного анализа:
eslint src/components/Button.js --cache
В системах контроля качества ESLint часто выполняется до сборки:
{
"husky": {
"hooks": {
"pre-commit": "eslint src --cache"
}
}
}
Такой механизм предотвращает попадание некорректного кода в сборочный процесс esbuild.
В CI ESLint выполняется как отдельный stage:
steps:
- run: npm ci
- run: npm run lint
- run: npm run build
Важная особенность — детерминированность результатов. ESLint не должен зависеть от состояния сборки, а esbuild не должен учитывать результаты линтинга.
При совместном использовании возникают типовые проблемы:
Дублирование обработки файлов
Различие парсеров
Несовпадение модульных систем
sourceType: moduleПри использовании TypeScript ESLint требует дополнительного конфигурационного слоя:
import tsParser from "@typescript-eslint/parser";
import tsPlugin from "@typescript-eslint/eslint-plugin";
export default {
parser: tsParser,
plugins: {
"@typescript-eslint": tsPlugin
},
extends: [
"plugin:@typescript-eslint/recommended"
]
};
esbuild при этом выполняет трансляцию без типовой проверки, что усиливает роль ESLint как статического анализатора.
В зрелых проектах применяется комбинация:
Типовая структура:
lint → typecheck → build → test
esbuild занимает исключительно этап build, не вмешиваясь в анализ качества кода.
Связка ESLint и esbuild демонстрирует принцип разделения инструментов по ответственности:
Такое разделение позволяет масштабировать проект без деградации производительности сборки и без усложнения пайплайна трансформации кода.