Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nodeJS v19 drops support for --es-module-specifier-resolution=node which makes it harder to run transpiled TypeScript [duplicate]

Typescript is transpiled to JavaScript, so a module routes.ts is converted into routes.js in the directory that tsc puts it. If another module imports names (e.g., "router") from a module, we leave off the suffix as in:

import { router } from './routes'

This worked fine until node stopped using .js as a default suffix. Starting in node V16 (or maybe earlier ?), it was necessary to add the flag --es-module-specifier-resolution=node in order to run the transpiled code with node. In later nodeJS versions this option was downgraded by being silently converted into --experimental-specifier-resolution=node which was then dropped altogether in NodeJS v19.

Now in NodeJS v19, one is supposed to use "custom loaders" instead. Is it really that hard to run transpiled TypeScript code? What is the recommended approach?

(SO: says that this question duplicates the relatd question Appending .js extension on relative import statements during Typescript compilation (ES6 modules), but this question has more information concerning different versions of nodeJS -- it is related, so people might want to check it out.)

like image 454
John Tang Boyland Avatar asked Sep 12 '25 13:09

John Tang Boyland


1 Answers

UPDATE: I've created a package for this purpose and published it to npm. Anyone who's willing to use it can visit its page for more information.

You can still use a custom loader with Node.js v19. Save the following to a file named loader.js in the project directory and then run node with the flag --experimental-loader ./loader.js added.

import {existsSync} from 'fs'
import {basename, dirname, extname, join} from 'path'
import {fileURLToPath} from 'url'

let extensions = ['mjs', 'js', 'json'], resolveDirs = false

let indexFiles = resolveDirs ? extensions.map(e => `index.${e}`) : []
let postfixes = extensions.map(e => `.${e}`).concat(indexFiles.map(p => `/${p}`))
let findPostfix = (specifier, context) => (specifier.endsWith('/') ? indexFiles : postfixes).find(p =>
  existsSync(specifier.startsWith('/') ? specifier + p : join(dirname(fileURLToPath(context.parentURL)), specifier + p))
)

let prefixes = ['/', './', '../']
export function resolve(specifier, context, nextResolve) {
  let postfix = prefixes.some(p => specifier.startsWith(p))
    && !extname(basename(specifier))
    && findPostfix(specifier, context) || ''

  return nextResolve(specifier + postfix)
}
like image 153
barhun Avatar answered Sep 15 '25 03:09

barhun