При сборке проектов на TypeScript через Webpack возникает важная
проблема производительности: полноценная проверка типов требует
значительных вычислительных ресурсов. Если использовать только
ts-loader в стандартном режиме, процесс компиляции и type
checking выполняются последовательно внутри одного процесса Webpack. На
крупных проектах это приводит к медленным rebuild-циклам, увеличению
времени HMR и общей деградации DX.
Плагин fork-ts-checker-webpack-plugin решает эту
проблему за счёт вынесения проверки типов и линтинга в отдельный
процесс. Основная сборка Webpack продолжает выполняться независимо, а
анализ TypeScript запускается параллельно.
Главная идея работы:
ts-loader или другой transpiler выполняет только
трансформацию TS → JS;fork-ts-checker-webpack-plugin отдельно запускает
TypeScript compiler API для проверки типов.Такой подход значительно ускоряет сборку.
ts-loader замедляет сборкуПо умолчанию ts-loader выполняет сразу две задачи:
Это означает, что на каждом rebuild Webpack вынужден:
Особенно тяжёлой является именно semantic phase:
На больших монорепозиториях именно эта часть становится узким местом.
Типичная схема работы выглядит так:
Webpack Process
├── transpilation (fast)
├── asset graph
├── chunk generation
└── emit
Forked TypeScript Process
├── semantic diagnostics
├── syntactic diagnostics
├── declaration analysis
└── eslint
Благодаря разделению задач:
npm install -D fork-ts-checker-webpack-plugin typescript
Чаще всего плагин используется совместно с:
npm install -D ts-loader
или:
npm install -D babel-loader @babel/preset-typescript
ts-loaderconst ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
],
},
plugins: [
new ForkTsCheckerWebpackPlugin(),
],
};
Ключевой параметр:
transpileOnly: true
Он отключает проверку типов внутри ts-loader.
После этого:
ts-loader выполняет только transpilation;transpileOnlyЕсли забыть включить:
transpileOnly: true
получается двойная проверка типов:
ts-loader;fork-ts-checker-webpack-plugin.Это приводит к:
Одна из самых популярных современных схем:
TypeScript → Babel → Webpack
В таком режиме:
fork-ts-checker-webpack-plugin выполняет только анализ
типов.Пример:
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-typescript',
],
},
},
},
],
},
plugins: [
new ForkTsCheckerWebpackPlugin(),
],
};
Преимущества такой схемы:
Удаление TypeScript-синтаксиса:
const user: string = 'Alex';
превращается в:
const user = 'Alex';
Проверка корректности типов:
const age: number = '18';
TypeScript обнаруживает ошибку:
Type 'string' is not assignable to type 'number'
fork-ts-checker-webpack-plugin занимается именно второй
частью.
const path = require('path');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.ts',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
extensions: ['.ts', '.js'],
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
},
],
},
plugins: [
new ForkTsCheckerWebpackPlugin(),
],
devtool: 'source-map',
};
tsconfig.jsonПлагин автоматически использует настройки TypeScript:
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Node",
"skipLibCheck": true
}
}
Все ошибки формируются на основе этих правил.
По умолчанию TypeScript разделяет:
Плагин умеет обрабатывать оба типа.
Пример синтаксической ошибки:
const a = ;
Пример semantic ошибки:
const a: number = 'hello';
typescript
секцииПлагин поддерживает глубокую конфигурацию.
Пример:
new ForkTsCheckerWebpackPlugin({
typescript: {
configFile: './tsconfig.json',
},
});
Крупные проекты могут упираться в ограничение памяти Node.js.
Для этого используется:
new ForkTsCheckerWebpackPlugin({
typescript: {
memoryLimit: 4096,
},
});
Значение указывается в мегабайтах.
Типичные симптомы нехватки памяти:
JavaScript heap out of memory
или:
Allocation failed - JavaScript heap out of memory
По умолчанию в development-режиме плагин работает асинхронно.
Это означает:
Поведение регулируется параметром:
new ForkTsCheckerWebpackPlugin({
async: true,
});
Для CI или production build часто используют:
new ForkTsCheckerWebpackPlugin({
async: false,
});
Теперь:
Это особенно важно для production deployment.
Плагин хорошо работает вместе с:
webpack-dev-server;Пример:
devServer: {
hot: true,
}
Ошибки типов появляются:
Современные dev-server конфигурации показывают TypeScript ошибки прямо в браузере.
Например:
ERROR in src/app.ts:15:7
TS2322: Type 'string' is not assignable to type 'number'
Это существенно ускоряет debugging.
Плагин умеет запускать ESLint параллельно с type checking.
Пример:
new ForkTsCheckerWebpackPlugin({
eslint: {
files: './src/**/*.{ts,tsx}',
},
});
Такой режим позволяет:
eslint-webpack-pluginfork-ts-checker-webpack-pluginФокус:
eslint-webpack-pluginФокус:
Часто они используются одновременно.
Плагин полностью поддерживает:
const App: React.FC = () => {
return <div>Hello</div>;
};
Конфигурация:
resolve: {
extensions: ['.tsx', '.ts', '.js'],
}
На monorepo-проектах плагин особенно полезен.
Причины:
Пример структуры:
packages/
core/
ui/
api/
shared/
Плагин поддерживает TypeScript project references.
Пример:
{
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/ui" }
]
}
Это позволяет:
TypeScript поддерживает incremental compilation:
{
"compilerOptions": {
"incremental": true
}
}
Плагин способен использовать преимущества incremental cache.
Результат:
Типичная production-конфигурация:
new ForkTsCheckerWebpackPlugin({
async: false,
});
В CI ошибки типов должны приводить к падению сборки.
Пример:
npm run build
при ошибке:
Build failed with TypeScript errors
На крупных codebase ускорение может быть весьма значительным.
Типичная динамика:
| Конфигурация | Rebuild |
|---|---|
| ts-loader full type check | 15–40 сек |
| transpileOnly + fork plugin | 2–8 сек |
Особенно заметна разница:
Несмотря на преимущества, существуют особенности.
В async режиме bundle может быть создан даже при наличии type errors.
Это иногда приводит к:
Поскольку запускается отдельный процесс:
На слабых машинах это может быть заметно.
tscПлагин интегрирован в Webpack pipeline.
Однако для:
часто всё равно используется отдельный запуск:
tsc --noEmit
Типичная причина:
transpileOnly: true
включён, но плагин не подключён.
В результате TypeScript:
Ошибки перестают обнаруживаться.
Причина:
transpileOnly: false
при использовании плагина.
Результат:
На больших проектах TypeScript analysis может потреблять 100% CPU.
Типичные причины:
Наиболее распространённая production-связка:
Webpack
+ babel-loader
+ @babel/preset-typescript
+ fork-ts-checker-webpack-plugin
или:
Webpack
+ ts-loader (transpileOnly)
+ fork-ts-checker-webpack-plugin
Первая схема обычно быстрее.
Вторая обеспечивает более тесную интеграцию с TypeScript compiler pipeline.
Использование fork-ts-checker-webpack-plugin практически
обязательно при:
На маленьких проектах разница может быть не столь заметной.
Плагин не влияет напрямую на генерацию source maps.
Но благодаря ускорению transpilation можно использовать:
devtool: 'eval-source-map'
без серьёзного ухудшения rebuild performance.
Для анализа bottleneck-проектов часто проверяют:
Особенно важно контролировать:
Files: 5000+
Types: 100000+
Memory: 2GB+
При таких масштабах разделение transpilation и type checking становится критически важным.