Как следить за ts-node и перезагружать при изменении файлов: гид по ошибкам

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Как заставить 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. Это усложняет отладку.

Блоги

Рекомендаций по книгам