ts-loader — официальный загрузчик для интеграции
TypeScript с Webpack. Его задача заключается в передаче .ts
и .tsx файлов компилятору TypeScript внутри процесса сборки
Webpack.
Связка Webpack + TypeScript решает сразу несколько задач:
ts-loader использует реальный компилятор TypeScript
(typescript package), поэтому поведение максимально близко
к обычному tsc.
Минимальный набор пакетов:
npm install --save-dev webpack webpack-cli typescript ts-loader
После установки появляются следующие ключевые зависимости:
| Пакет | Назначение |
|---|---|
| webpack | Сборщик модулей |
| webpack-cli | CLI-интерфейс Webpack |
| typescript | Компилятор TypeScript |
| ts-loader | Интеграция TypeScript с Webpack |
Пример структуры:
project/
├─ src/
│ ├─ index.ts
│ └─ utils.ts
├─ dist/
├─ webpack.config.js
├─ tsconfig.json
├─ package.json
tsconfig.jsonTypeScript требует конфигурационный файл.
Минимальный вариант:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"sourceMap": true,
"outDir": "./dist",
"moduleResolution": "node",
"esModuleInterop": true
},
"include": ["src"]
}
targetОпределяет версию JavaScript после компиляции.
{
"target": "ES2020"
}
Популярные значения:
| Значение | Описание |
|---|---|
| ES5 | Старые браузеры |
| ES2015 | Современный базовый JS |
| ES2020 | Современные возможности |
| ESNext | Максимально новый JS |
moduleДля Webpack почти всегда используется:
{
"module": "ESNext"
}
Webpack самостоятельно анализирует ES-модули.
strictВключает строгую типизацию.
{
"strict": true
}
Активирует:
noImplicitAnystrictNullChecksstrictFunctionTypessourceMapСоздание sourcemap для отладки.
{
"sourceMap": true
}
Позволяет видеть TypeScript-код в DevTools браузера.
moduleResolutionОбычно:
{
"moduleResolution": "node"
}
Используется алгоритм поиска модулей Node.js.
Минимальный конфиг:
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.ts',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true
},
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
devtool: 'source-map'
};
entryТочка входа приложения:
entry: './src/index.ts'
Webpack начинает строить граф зависимостей именно отсюда.
resolve.extensionsПозволяет импортировать модули без расширений.
resolve: {
extensions: ['.ts', '.js']
}
Теперь можно писать:
import { sum } from './utils';
вместо:
import { sum } from './utils.ts';
module.rulesПравила обработки файлов.
{
test: /\.ts$/,
use: 'ts-loader'
}
Логика работы:
.ts файл.ts-loader.ts-loader вызывает TypeScript Compiler API.excludeИсключение лишних директорий:
exclude: /node_modules/
Компиляция зависимостей обычно не требуется.
devtoolSourcemap:
devtool: 'source-map'
Часто используемые режимы:
| Значение | Особенности |
|---|---|
| eval | Очень быстро |
| eval-source-map | Хорошо для dev |
| source-map | Полные sourcemap |
| hidden-source-map | Для production |
| inline-source-map | Карты внутри файла |
src/utils.tsexport function sum(a: number, b: number): number {
return a + b;
}
src/index.tsimport { sum } from './utils';
const result = sum(10, 20);
console.log(result);
{
"scripts": {
"build": "webpack",
"dev": "webpack --watch"
}
}
Автоматическая пересборка:
npm run dev
Webpack отслеживает изменения файлов и пересобирает проект.
ts-loader
внутри Webpackts-loader является bridge-слоем между Webpack и
TypeScript Compiler API.
Схема обработки:
TypeScript File
↓
Webpack Rule
↓
ts-loader
↓
TypeScript Compiler
↓
JavaScript Output
↓
Webpack Bundle
ts-loader от babel-loaderts-loaderОсобенности:
babel-loaderОсобенности:
Одно из главных преимуществ ts-loader — полноценная
проверка типов.
Пример ошибки:
const value: number = 'hello';
Во время сборки:
Type 'string' is not assignable to type 'number'
Webpack завершит сборку ошибкой.
transpileOnlyДля ускорения сборки:
{
test: /\.ts$/,
use: {
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
}
В этом режиме:
Популярная схема оптимизации:
npm install --save-dev fork-ts-checker-webpack-plugin
Конфигурация:
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
}
]
},
plugins: [
new ForkTsCheckerWebpackPlugin()
]
};
| Подход | Скорость |
|---|---|
| Обычный ts-loader | Медленнее |
| transpileOnly + ForkTsChecker | Быстрее |
Type checking выносится в отдельный процесс.
Для React-проектов:
npm install react react-dom
npm install --save-dev @types/react @types/react-dom
{
"compilerOptions": {
"jsx": "react-jsx"
}
}
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
Регулярное выражение:
| Выражение | Файлы |
|---|---|
| /.ts$/ | Только `.ts` | | /.tsx?$/ | .ts и .tsx |
type Props = {
title: string;
};
export function Header({ title }: Props) {
return <h1>{title}</h1>;
}
Иногда проект имеет разные конфигурации:
Пример:
{
loader: 'ts-loader',
options: {
configFile: 'tsconfig.build.json'
}
}
Webpack:
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
TypeScript:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
Использование:
import { api } from '@/services/api';
Иногда используется:
devtool: 'inline-source-map'
Особенности:
Пример production-сборки:
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.ts',
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
},
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'ts-loader',
options: {
transpileOnly: true
}
},
exclude: /node_modules/
}
]
}
};
Ошибка:
Cannot find module './app'
Причины:
resolve.extensions.Причины:
noEmit: true;Проблемный вариант:
{
"noEmit": true
}
Ошибка:
Unexpected token <
Обычно означает:
.tsx не обрабатывается;Популярная архитектура:
TypeScript
↓
ts-loader
↓
babel-loader
↓
Webpack
Пример:
{
test: /\.ts$/,
use: [
'babel-loader',
'ts-loader'
]
}
Порядок выполнения loaders идёт справа налево.
Webpack 5 поддерживает filesystem cache.
module.exports = {
cache: {
type: 'filesystem'
}
};
Это заметно ускоряет повторные сборки.
TypeScript поддерживает incremental build.
{
"compilerOptions": {
"incremental": true
}
}
Создаётся файл:
tsconfig.tsbuildinfo
Он содержит информацию о предыдущей компиляции.
Опция:
options: {
happyPackMode: true
}
Используется вместе с:
Уменьшает часть внутренних проверок ради производительности.
Параллельная обработка:
npm install --save-dev thread-loader
Пример:
{
test: /\.ts$/,
use: [
'thread-loader',
{
loader: 'ts-loader',
options: {
happyPackMode: true
}
}
]
}
Частая архитектура:
webpack.common.js
webpack.dev.js
webpack.prod.js
Общая часть:
module.exports = {
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader'
}
]
}
};
При "type": "module":
import path from 'path';
export default {
entry: './src/index.ts'
};
Для Node.js-проектов:
npm install --save-dev @types/node
И настройка:
{
"compilerOptions": {
"types": ["node"]
}
}
Генерация .d.ts:
{
"declaration": true
}
Результат:
dist/
├─ index.js
├─ index.d.ts
Особенно важно для библиотек.
Для NestJS и других framework:
{
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
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'),
clean: true
},
cache: {
type: 'filesystem'
},
resolve: {
extensions: ['.ts', '.js']
},
devtool: 'eval-source-map',
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
]
}
]
},
plugins: [
new ForkTsCheckerWebpackPlugin()
]
};
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true,
"sourceMap": true,
"incremental": true,
"skipLibCheck": true
},
"include": ["src"]
}
ts-loader особенно полезен в случаях:
Для больших production-проектов наиболее распространённой считается схема:
ts-loader (transpileOnly)
+
ForkTsCheckerWebpackPlugin
Она обеспечивает баланс между скоростью сборки и полноценной проверкой типов.