javascriptnode.jstypescriptnpm-scriptsts-node

Node script with Typescript and ts-node: can't get to import anything, no matter the configuration and package type


I have a React Typescript project that has multiple files that share a structure. The code is similar, but quite different between them at some points, and it's pretty common to have to copy-paste files and change bits of information to create some of those new files.

I wanted to create a Node script that, asking the user for some input, would do that automatically. As I don't want to create a package for this (as it's a simple script inside my current project), I just created a folder called scripts and put it there.

So, the project structure is as follows:

- node_modules/
- scripts/
  - myScript/
    - helpers/
    - index.ts
    - package.json
- ...
- src/
- tsconfig.json
- package.json

To be able to execute Typescript, I've installed the ts-node library, and I'm executing this script through an npm script in the main project's package.json:

"run-script": "ts-node ./scripts/myScript"

This project already has code inside its src folder, and this scripts folder is a complement that does not belong to the main application's code, and that's why I keep it separated in an external folder, as it acts more as a helping tool for developers in the team.

The problem

Whenever I try to make an import, I get this error:

throw new ERR_MODULE_NOT_FOUND(
          ^
CustomError: Cannot find module ...

If I use dynamic imports for packages and set esModuleInterop in my tsconfig file, everything works fine. But as soon as I try to import a method with a relative path, it breaks:

const inquirer = (await import('inquirer')).default;
const fs = (await import('fs-extra')).default;
const { getCommonPath } = await import('./helpers/getCommonPath');
Error [ERR_MODULE_NOT_FOUND]: Cannot find module ...

I thought that could have to do with the directory path, but if I use __dirname in the import, it tells me it's not allowed because of the format of the path.

If I try to use non-dynamic imports in stead, I get the following error:

(node:106220) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.

But if I do that, then I get this error:

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for ...

Then I thought that would have to do with ts-node configuration, and I read to use ts-node-esm. But if I do that, then the first error appears again. I've also tried multiple configurations for ts-node (esModuleInterop: true, esm: true, module: CommonJS|ES2020|ESNext...) without luck.

The question

What do I have to do to be able to write a Node script with Typescript that I can execute from a command line that allows imports of both, external libraries and relative paths (that can be Typescript aswell)?

Thank you!


Solution

  • Actually I've been able to make it work finally with normal imports. Steps I've followed. I've followed the documentation of ts-node esm:

      "ts-node": {
        "transpileOnly": true,
        "compilerOptions": {
          "module": "ESNext",
          "esModuleInterop": true
        },
        "esm": true // <--- this is the most important part
      },
      "compilerOptions": {...}
    
    import fs from 'fs-extra';
    import { getSrcPath } from './helpers/getSrcPath.ts';
    
    "run-my-script": "ts-node ./scripts/myScript"