Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodejs, TypeScript, ts-node-dev & top-level await

Tags:

I have spent an hour now searching for a solution to a new error after needing top-level await. Everything else I have tried so far did not solve the error such as adding "type": "module" to the package.json file.

The message of the error is Cannot use import statement outside a module when starting the service. If I revert the change "module": "ESNext", to "module": "commonjs",, it works fine (except the await keywords have to be removed and somehow refactored to work without await).

In addition, I use ts-node-dev to run the service which can be seen in the package.json file.

  • The new package I need is kafkajs.
  • node version: v14.9.0
  • TypeScript version: 4.0

package.json

{   "name": "",   "version": "1.0.0",   "description": "microservice",   "main": "src/index.ts",   "author": "",   "type": "module",   "license": "MIT",   "scripts": {     "dev": "NODE_ENV=development tsnd --respawn --files src/index.ts",     "prod": "NODE_ENV=production tsnd --respawn --transpile-only --files src/index.ts",     "test": "mocha --exit -r ts-node/register tests/**/*.spec.ts",     "eslint": "eslint src/**/*.ts"   }, 

tsconfig.json

{   "compilerOptions": {     "target": "ES2020",     "module": "ESNext",     "moduleResolution": "node",     "outDir": "dist",     "sourceMap": true,     "esModuleInterop": true,     "allowSyntheticDefaultImports": true,     "experimentalDecorators": true,     "emitDecoratorMetadata": true   },   "ts-node": {     "files": true,     "transpileOnly": true   },   "include": ["src/**/*.ts", "declariations/**.d.ts"],   "exclude": ["node_modules", ".vscode"] } 
like image 747
Heitx Avatar asked Oct 30 '20 14:10

Heitx


People also ask

Does ts-node require TypeScript?

ts-node is a TypeScript execution engine and REPL for Node. js. It JIT transforms TypeScript into JavaScript, enabling you to directly execute TypeScript on Node. js without precompiling.

Does ts-node use Tsconfig?

ts-node supports a variety of options which can be specified via tsconfig.

How do I run a ts file in node?

We can use the ts-node package to execute TypeScript files from the command line. Install it with npm or other package manager. After that, simply execute the TypeScript files with the command: ts-node filename.

Can Nodemon run TypeScript?

As of v1. 19.0, nodemon has inbuilt support for TypeScript files with help from ts-node that requires no manual configuration. By default, nodemon uses the node CLI as an execution program for running JavaScript files; for TypeScript files, nodemon uses ts-node as the execution program instead.


2 Answers

TL;DR: Don't use ECMAScript modules with ts-node or ts-node-dev (yet); just refactor the top-level await out

Today I tumbled down the same rabbit hole, starting with the innocuous error:

Top-level 'await' expressions are only allowed when the 'module' option is set to 'esnext' or 'system', and the 'target' option is set to 'es2017' or higher. 

As a result, I felt inclined to edit my tsconfig.json and set module to esnext, which in turn forced me to set moduleResolution to node and finally add type: module to my package.json. What I failed to realize (and IMO they shouldn't suggest this in the error message-- you can just simply refactor the top-level await out), that this switches the module resolution strategy of NodeJS from CommonJS to ESM. This is actually a big deal for many reasons:

  • ESM support is still experimental in ts-node
  • Mixing CJS and ESM modules may lead to problems
  • There are open issues with ESM support in NodeJS itself

I feel that at this time (december 2020) the NodeJS ecosystem is still in transition from the classic CommonJS modules to the new ECMAScript modules. As a result other tech like ts-node or ts-node-dev are transitioning as well and support can be flaky. My advice is to stick with CommonJS until the dust has settled and these things "just work" out of the box.

like image 68
Martin Devillers Avatar answered Oct 07 '22 00:10

Martin Devillers


I know, the question is quite old already, but for people passing by this issue like I did earlier today:

I just managed to get it to work. Not with ts-node-dev directly, but with the combination of nodemon and ts-node.

You need to install nodemon and ts-node and then, assuming your entry file is src/index.ts, you can use this command:

nodemon --ext ts --loader ts-node/esm --experimental-specifier-resolution node src 

(Tested with Node v16.13.0)

This was the key post for me to figure it out: https://github.com/TypeStrong/ts-node/issues/1007

like image 27
Ricki-BumbleDev Avatar answered Oct 07 '22 01:10

Ricki-BumbleDev