Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/happy-carrots-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'arui-scripts': minor
---

Улучшен вывод ошибок сборки для `start` и `build`. Ошибки группируются по категориям (TypeScript,
Module, CSS, Module Federation, Configuration и тд.), для известных типов ошибок выводятся подсказки по
исправлению (проверка пути или установка пакета, `tsc --noEmit` для ошибок типизации, увеличение лимита
памяти Node.js и тд)
1 change: 1 addition & 0 deletions packages/arui-scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,4 @@ npm install arui-scripts --save-dev
- [Использование модулей](docs/modules.md)
- [Client-only режим](./docs/client-only.md)
- [Словарь для сжатия](./docs/compression-dictionary.md)
- [Вывод ошибок](./docs/error-grouping.md)
85 changes: 85 additions & 0 deletions packages/arui-scripts/docs/error-grouping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Улучшенный вывод ошибок

В режиме `start` / watch `arui-scripts` группирует ошибки сборки по категориям и выводит подсказки по исправлению.

Группировка работает через `handleCompilationResult` в client/server watch-компиляторах. Команда `build` по-прежнему выводит одну ошибку через `printBuildError` с подсказками, но без группировки по категориям.

## Группировка ошибок

Ошибки группируются по типу для удобства навигации:

| Категория | Описание |
|---|---|
| `Module Error` | Ошибки импорта (модуль не найден, экспорт не существует) |
| `TypeScript Error` | Ошибки типизации |
| `CSS Error` | Синтаксические ошибки стилей |
| `Syntax Error` | Синтаксические ошибки JS/TS |
| `Runtime Error` | Ошибки выполнения (React, undefined) |
| `Module Federation Error` | Проблемы с Module Federation |
| `Configuration Error` | Проблемы конфигурации (memory, target) |

## Подсказки по исправлению

Для каждой ошибки выводятся подсказки:

```
Client: Build failed

Module Error:
• Module not found: Error: Can't resolve './Button'
at src/components/index.tsx:5
Suggestions:
- Check that the file path is correct
```

Для пакетов из `node_modules` также печатается команда:

```
Suggestions:
- Check if the package is installed
Run: npm ls lodash
- Install the package
Run: npm install lodash
```

## Поддерживаемые ошибки

### Модули не найдены

Распознаются форматы Node (`Cannot find module`) и bundler (`Module not found` / `Can't resolve`).
Подсказки: проверка пути для relative imports или `npm ls` / `npm install` для пакетов.

### TypeScript ошибки

Команда для запуска `tsc --noEmit` для получения подробной информации.
`TS2307` и другие `TSxxxx` классифицируются как TypeScript, а не как module.

### Heap out of memory

Команда для увеличения памяти Node.js:

```bash
NODE_OPTIONS=--max-old-space-size=4096
```

### Module Federation

- Проверка `remoteEntry.js` доступности
- Проверка что remote-приложение запущено
- Настройка shared dependencies

### React element type

Проверка корректности импорта компонентов.

## Внутренний плагин

`SmartErrorsPlugin` — внутренний helper для форматирования stats-ошибок. В дефолтный rspack-config он не подключается: вывод уже делается в watch-хуках (`handleCompilationResult` / `printBuildError`). Публичного export-пути `arui-scripts/plugins/smart-errors-plugin` нет.

## Файлы модуля

- `src/commands/util/error-formatter.ts` — форматирование ошибок
- `src/commands/util/error-patterns.ts` — паттерны ошибок и подсказки
- `src/commands/util/error-category.ts` — определение категории ошибки
- `src/commands/util/error-location.ts` — извлечение location из ошибки
- `src/plugins/smart-errors-plugin.ts` — внутренний helper / optional rspack plugin
14 changes: 0 additions & 14 deletions packages/arui-scripts/src/commands/start/print-compiler-output.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { getErrorCategory, getErrorTitle } from '../error-category';

describe('error-category', () => {
describe('getErrorCategory', () => {
it('returns module category for "Cannot find module" error', () => {
const error = { message: "Cannot find module 'lodash'" };

const result = getErrorCategory(error);

expect(result).toBe('module');
});

it('returns module category for "Cannot find file" error', () => {
const error = { message: 'Cannot find file ./utils.ts' };

const result = getErrorCategory(error);

expect(result).toBe('module');
});

it('returns module category for "Can\'t resolve" bundler error', () => {
const error = {
message: "Module not found: Error: Can't resolve './Button' in '/src/components'",
};

const result = getErrorCategory(error);

expect(result).toBe('module');
});

it('returns typescript category for TS error codes', () => {
const error = { message: 'TS2322: Type "string" is not assignable to type "number"' };

const result = getErrorCategory(error);

expect(result).toBe('typescript');
});

it('returns typescript category for TS2307 cannot find module', () => {
const error = {
message:
"TS2307: Cannot find module 'lodash' or its corresponding type declarations.",
};

const result = getErrorCategory(error);

expect(result).toBe('typescript');
});

it('returns runtime category for TypeError', () => {
const error = { message: 'TypeError: Cannot read properties of undefined' };

const result = getErrorCategory(error);

expect(result).toBe('runtime');
});

it('returns runtime category for ReferenceError', () => {
const error = { message: 'ReferenceError: foo is not defined' };

const result = getErrorCategory(error);

expect(result).toBe('runtime');
});

it('returns css category for CSS errors', () => {
const error = { message: 'Unknown word (css烘托)' };

const result = getErrorCategory(error);

expect(result).toBe('css');
});

it('returns syntax category for SyntaxError, not css', () => {
const error = { message: 'SyntaxError: Unexpected token' };

const result = getErrorCategory(error);

expect(result).toBe('syntax');
});

it('returns configuration category for heap out of memory', () => {
const error = { message: 'FATAL ERROR: JavaScript heap out of memory' };

const result = getErrorCategory(error);

expect(result).toBe('configuration');
});

it('does not treat short "config" substring as configuration', () => {
const error = { message: "Can't resolve './config'" };

const result = getErrorCategory(error);

expect(result).toBe('module');
});

it('returns unknown for unknown errors', () => {
const error = { message: 'Something went wrong' };

const result = getErrorCategory(error);

expect(result).toBe('unknown');
});
});

describe('getErrorTitle', () => {
it('returns title by category, not by file extension', () => {
const error = { message: 'error', moduleName: '/path/to/file.ts' };

expect(getErrorTitle(error, 'module')).toBe('Module Error');
expect(getErrorTitle(error, 'typescript')).toBe('TypeScript Error');
expect(
getErrorTitle({ message: 'error', moduleName: '/path/to/styles.css' }, 'module'),
).toBe('Module Error');
});

it('returns Module Error for module category', () => {
const error = { message: 'error', moduleName: undefined };
const category = 'module';

const result = getErrorTitle(error, category);

expect(result).toBe('Module Error');
});

it('returns Runtime Error for runtime category', () => {
const error = { message: 'error', moduleName: undefined };
const category = 'runtime';

const result = getErrorTitle(error, category);

expect(result).toBe('Runtime Error');
});

it('returns Build Error for unknown category', () => {
const error = { message: 'error', moduleName: undefined };
const category = 'unknown';

const result = getErrorTitle(error, category);

expect(result).toBe('Build Error');
});

it('returns Module Federation Error for module-federation category', () => {
const error = { message: 'error', moduleName: undefined };
const category = 'module-federation';

const result = getErrorTitle(error, category);

expect(result).toBe('Module Federation Error');
});

it('returns Configuration Error for configuration category', () => {
const error = { message: 'error', moduleName: undefined };
const category = 'configuration';

const result = getErrorTitle(error, category);

expect(result).toBe('Configuration Error');
});

it('returns Syntax Error for syntax category', () => {
const error = { message: 'error' };
const category = 'syntax';

const result = getErrorTitle(error, category);

expect(result).toBe('Syntax Error');
});
});
});
Loading
Loading