Как заставить ts-node перезагружаться при изменении файлов: разбор реальных граблей
Представьте: вы пишете сервер на TypeScript, запускаете ts-node, вносите правку — и ничего не происходит. Приходится вручную останавливать процесс, жать Ctrl+C, снова запускать. Знакомо? Эта проблема собрала тысячи просмотров на Stack Overflow, и не зря: настройка watch и reload для ts-node — та ещё головоломка.
В этой статье я не просто дам готовый рецепт. Мы разберём топ ошибок, которые допускают даже опытные разработчики, и я покажу, как их избежать. Вы узнаете, почему ts-node --watch не работает "из коробки", чем ts-node-dev лучше классического подхода, и как не убить производительность сервера в процессе.
Почему ts-node не перезагружается сам по себе?
Давайте сразу расставим точки над i. ts-node — это не dev-сервер. Это транспилятор TypeScript в JavaScript, который запускает код в рантайме Node.js. У него нет встроенного механизма отслеживания изменений файлов (file watcher). Когда вы пишете ts-node app.ts, он просто выполняет файл и завершает работу.
Чтобы получить автоматическую перезагрузку при изменении файлов, вам нужно использовать внешние инструменты. И вот тут начинается самое интересное.
Топ-5 ошибок при настройке watch и reload для ts-node
Я собрал самые частые грабли, на которые наступают разработчики. Пройдёмся по каждой с примерами и решениями.
Ошибка №1: Использование флага --watch без правильного инструмента
Многие пишут в терминале:
ts-node --watch app.ts
И удивляются, что ничего не работает. Дело в том, что у ts-node нет флага --watch в стандартной поставке. Эта команда просто игнорируется или выдаёт ошибку.
Решение: Используйте nodemon в связке с ts-node. Вот правильная команда:
npx nodemon --exec ts-node app.ts
Или, если хотите сохранить в package.json:
{
"scripts": {
"dev": "nodemon --exec ts-node src/index.ts"
}
}
Это заставит nodemon следить за изменениями в файлах и перезапускать ts-node при каждом сохранении.
Ошибка №2: nodemon не видит изменения в .ts файлах
Вы настроили nodemon, сохраняете файл, а он молчит. Почему? По умолчанию nodemon следит только за .js, .json и некоторыми другими расширениями. .ts в списке нет.
Решение: Укажите расширения явно:
nodemon --watch src --ext ts --exec ts-node src/index.ts
Флаг --watch src ограничивает область отслеживания папкой src (чтобы не следить за node_modules). А --ext ts добавляет TypeScript файлы в список отслеживаемых расширений.
Можно также создать nodemon.json:
{
"watch": ["src"],
"ext": "ts",
"exec": "ts-node src/index.ts"
}
Ошибка №3: Конфликт с tsconfig.json — неверный module resolution
Типичная ситуация: вы используете ts-node с nodemon, но при запуске получаете ошибки вроде Cannot find module или Unknown file extension ".ts". Чаще всего проблема в настройках tsconfig.json.
Пример проблемного tsconfig.json:
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"target": "ES2020"
}
}
Проблема: ts-node работает в среде Node.js, а module: "ESNext" с moduleResolution: "bundler" рассчитаны на сборщики вроде Webpack. Node.js не умеет нативно обрабатывать ESM без дополнительных настроек.
Решение: Для проектов с ts-node используйте CommonJS или настройте ESM правильно.
Вариант 1: CommonJS (проще всего)
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"target": "ES2020",
"esModuleInterop": true
}
}
Вариант 2: ESM (современный, но требует настроек)
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "node",
"target": "ES2020",
"esModuleInterop": true
},
"ts-node": {
"esm": true,
"experimentalSpecifierResolution": "node"
}
}
И не забудьте добавить "type": "module" в package.json.
Ошибка №4: Игнорирование ts-node-dev (лучшей альтернативы)
Многие упорно используют nodemon + ts-node, хотя есть более быстрый и умный инструмент — ts-node-dev. Он создан специально для разработки на TypeScript и работает по принципу tsc --watch, но быстрее.
Сравнение скорости:
nodemon + ts-node— перезапускает весь процесс Node.js при каждом изменении. На больших проектах это может занимать 2-5 секунд.ts-node-dev— использует горячую замену модулей (HMR) и перезагружает только изменённые модули. Перезагрузка занимает 0.1-0.5 секунды.
Как использовать ts-node-dev:
npm install ts-node-dev --save-dev
npx ts-node-dev --respawn src/index.ts
Флаг --respawn перезапускает процесс при изменении файлов. Без него ts-node-dev будет работать в режиме "один раз".
Для package.json:
{
"scripts": {
"dev": "ts-node-dev --respawn --transpile-only src/index.ts"
}
}
Флаг --transpile-only отключает проверку типов во время разработки — это ускоряет перезагрузку. Типы проверяйте отдельной командой (например, tsc --noEmit в CI).
Ошибка №5: Забыли про source maps — дебаг превращается в ад
Когда ts-node перезагружает код, ошибки в консоли указывают на строки в скомпилированном JavaScript, а не в исходном TypeScript. Вы видите app.js:25 вместо app.ts:42. Это усложняет отладку.
Блоги
Рекомендаций по книгам
Читайте также
Тестирование в Swift: unit, integration, e2e — полное руководство