Tips for monitoring and automatically reloading ts-node when there are changes in TypeScript files

I'm experimenting with setting up a development server for my TypeScript and Angular application without having to transpile the .ts files every time.

After some research, I discovered that I am able to run .ts files using ts-node, but I also want the ability to watch .ts files and automatically reload my app or server. An example of this functionality can be seen in the command gulp watch.

Answer №1

If you want to effortlessly set up your development environment, just use

npm install --save-dev ts-node nodemon
and then execute nodemon with a .ts file:

nodemon app.ts

Past versions:

I faced the same issue in my setup until I discovered that you can customize the behavior of nodemon using its API.

For instance, in the latest version of nodemon:

nodemon --watch "src/**" --ext "ts,json" --ignore "src/**/*.spec.ts" --exec "ts-node src/index.ts"

Alternatively, create a nodemon.json file with these settings:

{
  "watch": ["src"],
  "ext": "ts,json",
  "ignore": ["src/**/*.spec.ts"],
  "exec": "ts-node ./src/index.ts"      // or "npx ts-node src/index.ts"
}

Then simply run nodemon without any arguments.

By following this approach, you can live-reload a ts-node process hassle-free, without concerning yourself with the details of the implementation.


For older versions of nodemon:

nodemon --watch 'src/**/*.ts' --ignore 'src/**/*.spec.ts' --exec 'ts-node' src/index.ts

Or take it up a notch: move nodemon's configuration to a separate nodemon.json file with these specifications, and then just launch nodemon, as suggested by Sandokan:

{
  "watch": ["src/**/*.ts"],
  "ignore": ["src/**/*.spec.ts"],
  "exec": "ts-node ./index.ts"
}

Answer №2

I have made the switch from using nodemon and ts-node to a more superior alternative, ts-node-dev. https://github.com/whitecolor/ts-node-dev

Simply execute ts-node-dev src/index.ts

[EDIT] I should note that since posting this answer, nodemon has significantly improved in terms of configuration and performance. I now utilize both tools on separate projects and am content with their functionality.

Answer №3

Summary of Best Options for Running TypeScript in Node.js

  • nodemon plus ts-node: Stable but requires explicit configuration and can be slow.
  • node-dev plus ts-node: Less configuration than nodemon but still slow.
  • ts-node-dev: Fast but may have reliability issues.

Note: Use tsx or swc for fast transpilation without type checking, as most editors offer built-in type checking capabilities.

(Recommended) tsx

ⓘ TL;DR: fastest with minimal configuration

Tsx provides a fast and easy-to-configure solution for running TypeScript in Node.js:

  1. Install tsx

    npm install --save-dev tsx
    
  2. Update your package.json scripts

    "scripts": {
      "dev": "tsx watch src/index.ts",
    
  3. Run the script

    npm run dev
    

    (Adjust steps for global installation if needed)

Alternative Approaches:

1. nodemon/node-dev + ts-node + swc

ⓘ TL;DR: fast but more configuration required

Combine nodemon/node-dev with ts-node and swc for improved speed:

  1. Install nodemon or node-dev

  2. Set up ts-node with swc integration

  3. Run nodemon or node-dev

2. nodemon/node-dev + ts-node transpileOnly

ⓘ TL;DR: reliable with standard TypeScript transpiler

A faster alternative using standard Ts-node transpiler without swc:

  1. Install nodemon/node-dev

  2. Install ts-node

  3. Enable transpileOnly in tsconfig.json

  4. Start nodemon/node-dev

3. nodemon + tsc --incremental

ⓘ TL;DR: reliable with type checking, more complex

This approach includes type checking but requires more setup:

  1. Install nodemon

  2. Configure tsconfig.json for incremental transpilation

  3. Setup nodemon to run the TypeScript compiler on file changes

Answer №4

Instead of using HeberLZ's solution, you can try a different approach that involves npm scripts.

Below is an example from my own package.json:

  "scripts": {
    "watch": "nodemon -e ts -w ./src -x npm run watch:serve",
    "watch:serve": "ts-node --inspect src/index.ts"
  },
  • The -e flag specifies the extensions to be watched,
  • The -w flag sets the directory to watch,
  • The -x flag executes the specified script.

The --inspect option in the watch:serve script is related to node.js and enables debugging protocol.

Answer №5

I've found success using the following command:

nodemon src/index.ts

It seems that this method has been effective since the implementation of this pull request: https://github.com/remy/nodemon/pull/1552

Answer №6

If you're looking to streamline your development process, consider utilizing ts-node-dev

With ts-node-dev, the target node process is restarted every time a required file changes (similar to standard node-dev), but it also shares the Typescript compilation process between restarts.

Get Started

yarn add ts-node-dev --dev

Your package.json file can be configured like this:

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "tsc": "tsc",
  "dev": "ts-node-dev --respawn --transpileOnly ./src/index.ts",
  "prod": "tsc && node ./build/index.js"
}

Answer №7

If you're dealing with this particular problem, I have developed the tsc-watch library specifically for it. You can easily access it on npm.

An obvious scenario where you could use it is:

tsc-watch server.ts --outDir ./dist --onSuccess "node ./dist/server.js"

Answer №8

To include the command

"watch": "nodemon --exec ts-node -- ./src/index.ts"
in the scripts part of your package.json.

Answer №9

I believe it's best to avoid using ts-node and instead always run from the dist folder.

To achieve this, simply configure your package.json with the following settings:

....
"main": "dist/server.js",
"scripts": {
  "build": "tsc",
  "prestart": "npm run build",
  "start": "node .",
  "dev": "nodemon"
},
....

Next, include a nodemon.json configuration file:

{
  "watch": ["src"],
  "ext": "ts",
  "ignore": ["src/**/*.spec.ts"],
  "exec": "npm restart"
}

In this setup, I utilize "exec": "npm restart"
This ensures that all ts files will be recompiled to js files before restarting the server.

To run in a development environment, use the command:

npm run dev

By following this configuration, you can always run the application from the distributed files without relying on ts-node.

Answer №10

i tried using the following script:

"start": "nodemon --watch 'src/**/*.ts' --ignore 'src/**/*.spec.ts' --exec ts-node src/index.ts"

when I ran 'yarn start', an error occurred with the message stating that it did not recognize 'ts-node'

Answer №11

Standard Solution

Starting from Node.js version v16.19.0, the CLI introduces a convenient --watch option, eliminating the need for external dependencies such as nodemon.

To run TypeScript code, leverage the popular package ts-node. Below is an example of how to configure it:

// package.json
{
    "scripts": {
        "dev": "node --watch --loader=ts-node/esm ./src/app.ts"
    },
    "devDependencies": {
        "ts-node": "~10.9.0"
    }
}

Alternative Approach

If you're open to exploring other options, consider checking out tsx, although it may not be as mature as ts-node.

Please note that tsx does not currently support emitDecoratorMetadata, which is essential for projects utilizing decorators. Despite this limitation, tsx offers quicker compilation (powered by esbuild backend):

// package.json
{
    "scripts": {
        "dev": "tsx watch ./src/app.ts"
    },
    "devDependencies": {
        "tsx": "~4.6.0"
    }
}

Answer №12

An alternative approach is to start by compiling the code in watch mode using tsc -w and then running nodemon on the generated JavaScript files. This technique offers a comparable speed to ts-node-dev while providing a more production-ready environment.

 "scripts": {
    "watch": "tsc -w",
    "dev": "nodemon dist/index.js"
  },

Answer №13

Step one - Start by installing the packages listed below in your project dependencies

npm i -D @types/express @types/node nodemon ts-node tsc typescript

You can also use yarn:

yarn add -D @types/express @types/node nodemon ts-node tsc typescript

Step two - Add the following configuration to your tsconfig.json file

{
  "compilerOptions": {
    "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */,
    "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
    "lib": [
      "DOM",
      "ES2017"
    ] /* Specify library files to be included in the compilation. */,
    "sourceMap": true /* Generates corresponding '.map' file. */,
    "outDir": "./dist" /* Redirect output structure to the directory. */,
    "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,

    "strict": true /* Enable all strict type-checking options. */,
    "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
    "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
    "skipLibCheck": true /* Skip type checking of declaration files. */,
    "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
  },
  "exclude": ["node_modules"],
  "include": ["./src"]
}

Step three - Implement the following scripts in your package.json file

"scripts": {
    "start": "node ./dist/server.js",
    "dev": "nodemon -L ./src/server.ts && tsc -w"
},

Answer №14

Include the following code in your package.json file:

scripts {
"dev": "nodemon --watch '**/*.ts' --exec 'ts-node' index.ts"
}

In order for this to work, you must also install ts-node as a dev-dependency

yarn add ts-node -D

To start the development server, run yarn dev

Answer №15

STEP 1: To get started, you need to install nodemon and ts-node. If you have already installed them, you can skip this step.

npm install --save-dev nodemon ts-node

STEP 2: Next, configure the start script in your package.json file.

"start": "nodemon ./src/app.ts"

Nodemon now automatically detects TypeScript files in your project and uses the ts-node command. Simply run npm start to compile, watch, and reload your application.

If you encounter errors regarding TypeScript modules not being found in your project, simply run the following command in your project folder.

npm link typescript

Answer №16

Encountered an error with code: 'ERR_UNKNOWN_FILE_EXTENSION'. I required esm support, so to enable ES6 functionality, you can use the following commands:

npm i -D ts-node nodemon

Add the script below to your package.json file:

"dev": "nodemon --exec ts-node-esm ./src/index.ts"

Answer №17

To resolve the issue, simply update these 3 packages:

nodemon, ts-node, typescript
yarn global add nodemon ts-node typescript

Alternatively, you can use npm:

npm install -g nodemon ts-node typescript

Once updated, execute the following command to solve the problem:

nodemon <filename>.ts

Answer №18

Refresh console logs after making changes

Javascript:

"start": "nodemon -x \"clear && node\" index.js",

Typescript:

"start": "nodemon -x \"clear && ts-node\" index.ts",

Answer №19

The simplest solution would be to download Nodemon and execute the following command: "nodemon --exec npx ts-node --esm test.ts"

Answer №20

If you encounter any issues while using

"type": "module"
in your package.json file (as detailed in this GitHub issue), you can resolve them by applying the following configuration:

{
  "watch": ["src"],
  "ext": "ts,json",
  "ignore": ["src/**/*.spec.ts"],
  "exec": "node --loader ts-node/esm --experimental-specifier-resolution ./src/index.ts"
}

You can also use the following command line options:

nodemon --watch "src/**" --ext "ts,json" --ignore "src/**/*.spec.ts" --exec "node --loader ts-node/esm --experimental-specifier-resolution src/index.ts"

Answer №21

To activate the --poll feature on your package.json file, simply add the option within your scripts section. The --poll flag instructs ts-node-dev to actively monitor source code files for changes by intermittently scanning them, rather than relying on the file system's change notifications. This ensures that any modifications made to the files are promptly detected, even in cases where the file system may not reliably report changes.

   "start": "ts-node-dev --poll src/index.ts"

Answer №22

Utilize ts-node-dev version 2.0.0+ with the following command:

ts-node-dev --respawn ./src/index.ts

*Note: In case of an error stating "command not found", you can execute it directly from node-modules as follows:

./node_modules/.bin/ts-node-dev --respawn ./src/index.ts

Answer №23

If you're looking to integrate tsc and the payload more tightly without resorting to running them in parallel, there's an alternative approach that involves incorporating them together. You can achieve this by creating a Node.js script that waits for the TypeScript compiler to finish building before initiating your process.

For one of my projects, I devised the following solution (note: this requires the installation of the tree-kill package):

#!/usr/bin/env node

import { spawn } from 'node:child_process';
import { join } from 'node:path';
import { createInterface } from 'node:readline';
import process from 'node:process';
import kill from 'tree-kill';

const cwd = process.cwd();
const tscConfigPath = join(cwd, 'tsconfig.build.json');
const tscArgs = ['tsc', '--build', '--watch', '--pretty', tscConfigPath];
const command = process.argv.slice(2);

// adjust params above as necessary

const tsc = spawn('yarn', tscArgs, { // change if not using yarn
  stdio: ['ignore', 'pipe', 'inherit'],
  cwd,
});

let proc;

const startCommand = () => {
  proc && kill(proc.pid);
  proc = spawn(command[0], command.slice(1), { stdio: 'inherit', cwd });
};

const rl = createInterface({
  input: tsc.stdout,
  terminal: false,
});

rl.on('line', (line) => {
  console.log(line);
  if (line.includes('Found 0 errors. Watching for file changes.')) {
    startCommand();
  }
});

tsc.on('exit', (code) => {
  console.log('tsc exited with code', code);
  proc && kill(proc.pid);
  process.exit(code);
});

process.on('SIGINT', () => {
  kill(tsc.pid);
  proc && kill(proc.pid);
  process.exit(0);
});

process.on('exit', () => {
  kill(tsc.pid);
  proc && kill(proc.pid);
});


I implement it in other packages within my monorepo like so in the package.json configuration:

"scripts": {
  "start:dev": "run-on-tsc-build yarn node dist/main.js"
}

This method functions by waiting for the message "Found 0 errors. Watching for file changes." from TypeScript before executing the specified command.

Answer №24

Utilizing nodemon in conjunction with ts-node:

nodemon --watch source --ext ts,json --exec "node --loader ts-node/esm ./source/index.ts"

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I transfer information from a map to a child component?

I'm attempting to transfer a variable from a parent component to a child component using React and Typescript. In my Table component (parent), I have the following map. It sets the 'data' variable as the value of the last element in the arr ...

What is the significance of var-less variables in TypeScript class definitions?

Why is it that when creating a component class in Angular2, we don't need to use var when declaring a new variable? For example: @Component({ selector: 'my-app', template: ` <h1>{{title}}</h1> ` }) export class AppCo ...

Using a try block inside another try block to handle various errors is a common practice in JavaScript

In an effort to efficiently debug my code and identify the location of errors, I have implemented a try-catch within a try block. Here is a snippet of the code: for (const searchUrl of savedSearchUrls) { console.log("here"); // function will get ...

JEST: Troubleshooting why a test case within a function is not receiving input from the constructor

When writing test cases wrapped inside a class, I encountered an issue where the URL value was not being initialized due to dependencies in the beforeAll/beforeEach block. This resulted in the failure of the test case execution as the URL value was not acc ...

Step-by-step guide on activating a button only when all form fields are validated

My very first Angular 5 project. I've gone through resources like: https://angular.io/guide/form-validation and various search results I looked up, only to realize that they are all outdated. In my form, I have several input fields such as: <for ...

Tips for accessing other environment variables within the environment.ts file in an Angular project

Currently, I am working on modifying the 'environment.ts' file within an Angular project to include additional properties. The current setup looks like this: export const environment = { production: false, apiUrl: 'http://example.com&ap ...

Using Typescript with React functional components: the proper way to invoke a child method from a parent function

My current setup is quite simple: <Page> <Modal> <Form /> </Modal> </Page> All components mentioned are functional components. Within <Modal />, there is a close function defined like this: const close = () => ...

Oops! There was an error: Unable to find a solution for all the parameters needed by CountdownComponent: (?)

I'm currently working on creating a simple countdown component for my app but I keep encountering an error when I try to run it using ng serve. I would really appreciate some assistance as I am stuck. app.module.ts import { BrowserModule } from &apo ...

Using React MUI Select in combination with react-hook-form does not seem to be compatible with Cypress testing

Within my React application, I have implemented a form that includes a dropdown select. Depending on the option selected from the dropdown, different input fields are rendered. const [templateType, setTemplateType] = useState(""); const { regi ...

Injecting singletons in a circular manner with Inversify

Is it possible to use two singletons and enable them to call each other in the following manner? import 'reflect-metadata'; import { Container, inject, injectable } from 'inversify'; let container = new Container(); @injectable() cla ...

Tips for showcasing styled text in Vue using API data

I'm having trouble formatting text in Vue. Within a component, I have a textarea that stores a string with backspaces, etc ... in an API like this: A cellar but not only...\n\nWelcome to the Nature & Wine cellar, a true Ali-baba's cave ...

Adding an Icon to the Angular Material Snackbar in Angular 5: A Step-by-Step Guide

I recently started using Angular and have incorporated Angular Material Design for my UI elements. Within my application, I am utilizing a snackbar component. However, I am facing difficulty in adding an icon inside the snackbar despite trying various so ...

What is the best approach to breaking down attributes upon import according to the theme?

Hey there! Here's the thing - I have this file called <code>colors.ts:

export const black = '#0C0C0C'; export const blue = '#22618E'; Whenever I need to use a color, I import it like so: import {black} from 'Shared& ...

Typescript - Troubleshooting undefined error with static variables

My node API app is developed using express and typescript. The static variable of the Configuration Class is initialized with required configuration before starting the server. However, when I try to use this static variable in a separate TypeScript class ...

What is the reason behind Angular generating files with 'es5' and 'es2015' extensions instead of 'es6' (or no extension)?

Recently, I installed the Angular CLI (@angular/cli 9.0.1). My goal was to create a new Angular Element, package it, and then integrate it into another application. Following several blog tutorials, I found that they all mentioned the final step of creati ...

What is the best way to use an Observable to interrogate a fork/join operation?

I have a forkjoin set up to check for the presence of a person in two different data stores. If the person is not found in either store, I want to perform a delete action which should return true if successful, and false otherwise. However, my current impl ...

The ngx-treeview is displaying an inaccurate tree structure. Can you pinpoint where the issue lies?

I have structured my JSON data following the format used in ngx-treeview. Here is the JSON file I am working with: [ { "internalDisabled": false, "internalChecked": false, "internalCollapsed": false, "text": "JOURNEY", "value": 1 } ...

Having difficulty transferring navigation props between screens using react-navigation

Within my ContactList component, I have utilized a map to render various items. Each item includes a thumbnail and the desired functionality is that upon clicking on the thumbnail, the user should be directed to a new screen referred to as UserDetailsScree ...

Incorporating a component specified in a .jsx file into a TypeScript file

We recently acquired a react theme for our web application, but ran into issues transpiling the components. After resolving that problem, we are now facing type-related challenges. It seems that TypeScript is struggling because the props do not have a def ...

Sending an onclick event to a child class through React and TypeScript

I'm currently working through the Facebook React tutorial with Typescript for the first time. I need to pass an onClick event to the 'Square' component, which is implemented using Typescript and interfaces for state and props. How can I mod ...