32

I was trying to use the top level in the project and saw that it was necessary to change the module from tscofnig to esnext or system, but for some reason my ts-node's error. And I already put the type: module I tried to use the flag: --experimental-modules but the error still does not know how to solve.

package.json:

{
  "name": "micro-hr",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "type": "module",
  "scripts": {
    "commit": "git-cz",
    "build": "babel src --extensions \".js,.ts\" --out-dir dist --copy-files --no-copy-ignored",
    "start:dev": "ts-node-dev --experimental-modules --inspect --respawn --transpile-only --ignore-watch node_modules -r tsconfig-paths/register src/index.ts",
    "start:debug": "node start --debug --watch",
    "start:prod": "node dist/index.ts",
    "test": "jest",
    "lint": "eslint --fix",
    "lint2": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config ./ormconfig.ts",
    "migration:generate": "ts-node ./node_modules/typeorm/cli.js migration:generate -n"
  },
  "devDependencies": {
    "@babel/cli": "^7.11.5",
    "@babel/core": "^7.11.5",
    "@babel/node": "^7.10.5",
    "@babel/preset-env": "^7.11.5",
    "@babel/preset-typescript": "^7.10.4",
    "@commitlint/cli": "^9.1.2",
    "@commitlint/config-conventional": "^9.1.2",
    "@types/bcryptjs": "^2.4.2",
    "@types/cookie-parser": "^1.4.2",
    "@types/cors": "^2.8.7",
    "@types/express": "^4.17.8",
    "@types/helmet": "^0.0.48",
    "@types/jest": "^26.0.13",
    "@types/node": "^14.6.4",
    "@types/pino": "^6.3.0",
    "@types/pino-http": "^5.0.5",
    "@types/supertest": "^2.0.10",
    "@typescript-eslint/eslint-plugin": "^4.0.1",
    "@typescript-eslint/parser": "^4.0.1",
    "babel-plugin-module-resolver": "^4.0.0",
    "commitizen": "^4.2.1",
    "cz-conventional-changelog": "^3.3.0",
    "eslint": "^7.8.1",
    "eslint-config-airbnb-base": "^14.2.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-config-standard": "^14.1.1",
    "eslint-import-resolver-typescript": "^2.3.0",
    "eslint-plugin-import": "^2.22.0",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.0.1",
    "husky": "^4.2.5",
    "jest": "^26.4.2",
    "pino-pretty": "^4.2.0",
    "prettier": "^2.1.1",
    "supertest": "^4.0.2",
    "ts-jest": "^26.3.0",
    "ts-node": "^9.0.0",
    "ts-node-dev": "^1.0.0-pre.62",
    "tsconfig-paths": "^3.9.0",
    "tscpaths": "^0.0.9",
    "typescript": "^4.0.2"
  },
  "dependencies": {
    "amqplib": "^0.6.0",
    "assert": "^2.0.0",
    "bcryptjs": "^2.4.3",
    "class-transformer": "^0.3.1",
    "cors": "^2.8.5",
    "dotenv": "^8.2.0",
    "envalid": "^6.0.2",
    "express": "^4.17.1",
    "extendable-error": "^0.1.7",
    "helmet": "^4.1.0",
    "nabbitmq": "^1.0.0",
    "pg": "^8.3.3",
    "pino": "^6.5.1",
    "pino-http": "^5.2.0",
    "reflect-metadata": "^0.1.13",
    "spt-rabbit-helpers": "^1.0.6",
    "tsyringe": "^4.3.0",
    "typeorm": "^0.2.25"
  },
  "config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
  }
}

tsconfig:

{
  "compilerOptions": {
    "target": "es2020",
    "module": "esnext",
    "allowJs": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "strictPropertyInitialization": false,
    "moduleResolution": "node",
    "baseUrl": "./src",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "forceConsistentCasingInFileNames": true,
    "noImplicitAny": true,
    "typeRoots": ["node_modules/@types", "@types"]
  },
  "include": ["src", "__tests__"],
  "exclude": ["node_modules"]
}

main:

import 'reflect-metadata';
import express from 'express';
import { RabbitServer } from 'spt-rabbit-helpers';
import validateEnv from 'utils/validateEnvs';
import {
  RabbitMqConnectionFactory,
  ConsumerFactory,
  PublisherFactory,
  RabbitMqConnection,
} from 'nabbitmq';
import { container, singleton } from 'tsyringe';

const factory = new RabbitMqConnectionFactory();
factory.setUri('amqp://localhost:5672');
const ConsumerConnection = await factory.newConnection();
const PublisherConnection = await factory.newConnection();
container.registerInstance('Consumer_Connection', ConsumerConnection);
container.registerInstance('Publisher_Connection', PublisherConnection);
Ming
  • 1,349
  • 4
  • 13
  • 36
  • 11
    Did you ever solve this? Why does it take a masters degree in javasript to use top level await? – A.com Jul 14 '21 at 13:56

4 Answers4

29

To run ts-node (or plain node for that matter) you need to use "module": "commonjs", "target": "ES2017", otherwise the import/export statements are illegally placed in an IIFE.

So I would suggest using another file called node.tsconfig.json with the following contents:

{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "target": "ES2017" // For NodeJS 8 compat, see https://www.typescriptlang.org/tsconfig#target for more info
    }
}

And then run ts-node with --project ./node.tsconfig.json

Elias Schablowski
  • 2,619
  • 9
  • 19
  • 3
    It should be noted that the project arg in the ts-node command MUST COME BEFORE the script name. e.g. `ts-node --project ./node.tsconfig.json your-script.ts` – Matt Rabe Oct 23 '20 at 19:27
  • 10
    Apparently ts-node also accepts format `{"ts-node": {"compilerOptions": { ... } } }` ...in the main `tsconfig.json` – thejhh Aug 06 '21 at 20:51
  • I couldn't get this answer or the comments to work, even though they looked promising. – Ryan Jul 07 '22 at 23:57
  • 1
    Hi @Ryan, Try Looking at the configuration outputted by `ts-node --showConfig`, maybe ts-node isn’t loading your configuration. – Elias Schablowski Jul 19 '22 at 20:53
  • Thanks. `yarn ts-node --project ./tsconfig.node.json --showConfig` is a good command to know about, but I'm still not sure how to get your answer to work, given that the showConfig seems to say that it's loading my extended config properly. – Ryan Oct 04 '22 at 18:23
  • 3
    I think I was able to solve my problem after reading https://bobbyhadz.com/blog/typescript-cannot-use-import-statement-outside-module. I added this to my tsconfig.json: `"ts-node": { "compilerOptions": { "module": "commonjs", "target": "ES2017" } },` – Ryan Oct 04 '22 at 18:30
27

After a lot of searching, I found this solution works perfect:

https://github.com/TypeStrong/ts-node/issues/922#issuecomment-673155000

Just add a "ts-node" block to your tsconfig.json file as below:

{
  "ts-node": {
    "compilerOptions": {
      "module": "commonjs"
    }
  },
  "compilerOptions": {
    "module": "esnext"
  }
}

And it has been documented in the ts-node official page "Via tsconfig.json" part.

This saved hours of my life.

mytharcher
  • 742
  • 7
  • 18
8

I had the same issue and I fixed it by changing the module in tsconfig.json to commonjs and removing the module key in package.json:

// tsconfig.json
{
    "module": "CommonJS",
}
Abhyudaya Sharma
  • 1,173
  • 12
  • 18
5

If you are using React, "commonjs" can not be set for TypeScript.

tsconfig.json

{
    "compilerOptions": {
        "module": "esnext"
    }
}

package.json

{
    "type": "module",
    "scripts": {
        "tsnode": "node --loader ts-node/esm --no-warnings"
    },
    "dependencies": {
        "ts-node": "^10.4.0"
    }
}

hello.ts

import * as os from "os"
console.log("os", os);

Two ways to execute the TypeScript file:

  • node --loader ts-node/esm --no-warnings hello.ts
  • npm run tsnode hello.ts
BaiJiFeiLong
  • 3,716
  • 1
  • 30
  • 28