Модульная система JavaScript определяет способ разбиения кода на изолированные единицы, их экспорта и последующего использования в других файлах. ESLint рассматривает модули как статическую структуру, поддающуюся анализу, и предоставляет набор правил, обеспечивающих предсказуемость импортов, отсутствие циклических зависимостей, корректность путей и согласованность архитектуры.
ESLint работает на уровне синтаксического дерева (AST), поэтому
анализ импортов опирается на статические конструкции import
и export. Это создаёт ряд принципиальных ограничений:
require() частично выпадают из полного
анализаМодульная проверка в ESLint строится вокруг предположения, что структура зависимостей должна быть прозрачной и предсказуемой без выполнения кода.
В современных проектах сосуществуют две модульные системы:
Используют синтаксис import и export:
import fs from 'fs';
export const value = 42;
Особенности:
Использует require и module.exports:
const fs = require('fs');
module.exports = { value: 42 };
Особенности:
ESLint-правила для модулей учитывают различия этих систем, но большинство современных правил ориентировано на ES Modules как целевой стандарт.
Одно из ключевых правил модульной системы, проверяющее возможность разрешения импортируемых путей.
Основные задачи:
Пример нарушения:
import utils from './utills/helpers';
Ошибка возникает при отсутствии файла или опечатке в пути.
Настройка резолвера особенно важна при использовании TypeScript, Webpack или Babel:
{
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".ts"]
}
}
}
}
Правило контролирует соответствие импортов объявленным зависимостям в
package.json.
Проверяемые случаи:
Пример:
import lodash from 'lodash';
Если lodash не указан в зависимостях, ESLint фиксирует
нарушение.
Правило критично для монорепозиториев и CI-сборок, где избыточные зависимости приводят к нестабильности окружения.
Одна из наиболее используемых групп правил, регулирующая порядок импортов.
Ключевые группы:
Пример логически упорядоченного кода:
import fs from 'fs';
import React from 'react';
import utils from '@/utils/helpers';
import './styles.css';
Дополнительно правило может:
Конфигурация:
{
"rules": {
"import/order": [
"error",
{
"groups": ["builtin", "external", "internal"],
"newlines-between": "always"
}
]
}
}
Циклические зависимости нарушают линейность графа модулей:
// a.js
import { b } from './b';
// b.js
import { a } from './a';
Такие структуры приводят к:
ESLint анализирует граф импортов и выявляет циклы на уровне файлов или модулей. В сложных проектах правило может учитывать глубину цикла:
{
"rules": {
"import/no-cycle": ["error", { "maxDepth": 1 }]
}
}
Запрещает повторные импорты из одного источника:
import { map } from 'lodash';
import { filter } from 'lodash';
Корректная форма:
import { map, filter } from 'lodash';
Это правило улучшает читаемость и упрощает анализ зависимостей.
Запрещает импорт самого себя:
import utils from './utils';
внутри utils.js.
Такие ошибки часто возникают при рефакторинге и переименовании файлов.
Удаляет избыточные сегменты путей:
import utils from './utils/index.js';
предлагается заменить на:
import utils from './utils';
Правило уменьшает шум в графе импортов и повышает читаемость структуры каталогов.
Контролирует использование расширений файлов:
import helper from './helper.js';
или
import helper from './helper';
В зависимости от конфигурации проекта правило может:
Пример конфигурации:
{
"rules": {
"import/extensions": [
"error",
"ignorePackages",
{
"js": "never",
"ts": "never"
}
]
}
}
Гарантирует, что все импорты находятся в начале файла:
console.log('init');
import fs from 'fs';
Такой код нарушает правило, поскольку импорт должен быть статическим и предсказуемым.
Правильный вариант:
import fs from 'fs';
console.log('init');
Это правило важно для корректной работы статического анализа.
Регулирует визуальное разделение импортов и основного кода:
import fs from 'fs';
function run() {}
Отсутствие разделительной строки ухудшает читаемость и затрудняет восприятие структуры файла.
Позволяет явно запрещать импорт определённых модулей:
{
"rules": {
"no-restricted-imports": [
"error",
{
"paths": ["moment"]
}
]
}
}
Пример применения:
Также возможно ограничение подмодулей:
{
"paths": [
{
"name": "lodash",
"importNames": ["cloneDeep"]
}
]
}
Регулирует стиль экспорта в модулях с единственной сущностью:
export function parse() {}
вместо:
export default function parse() {}
или наоборот — в зависимости от выбранной архитектуры.
Правило влияет на:
В крупных проектах часто используются алиасы:
import Button from '@/ui/Button';
ESLint не понимает такие пути без дополнительной настройки. Используются резолверы:
eslint-plugin-importeslint-import-resolver-nodeeslint-import-resolver-aliasПример настройки:
{
"settings": {
"import/resolver": {
"alias": {
"map": [["@", "./src"]],
"extensions": [".js", ".ts"]
}
}
}
}
Без корректного резолвера правила вроде
import/no-unresolved будут давать ложные срабатывания.
Совокупность правил модульной системы формирует архитектурный слой линтинга, который отвечает за:
В крупных приложениях модульные правила ESLint фактически становятся частью архитектурной спецификации, фиксируя допустимые формы взаимодействия между частями системы.