【问题标题】:nodeJS v19 drops support for --es-module-specifier-resolution=node which makes it harder to run transpiled TypeScriptnodeJS v19 drops support for --es-module-specifier-resolution=node which makes it harder to run transpiled TypeScript
【发布时间】:2022-12-28 00:37:40
【问题描述】:

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?

【问题讨论】:

  • Since the ESM spec requires file extensions with import, I presume nodejs is just moving in the direction of the spec. This sounds like something the TypeScript compiler should fix. I wonder if this is being discussed in the TypeScript world. Have you looked through the TypeScript compile options to see if there's an option to fix this (providing an extension in the generated code)? Or looked where TypeScript issues are discussed?
  • Are you using ES modules or not? If yes, then include the .js extension in your imports and update your TS config as necessary.

标签: node.js typescript


【解决方案1】:

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 = ['/', './', '../']
let resolve = (specifier, context, nextResolve) => {
  if (prefixes.some(p => specifier.startsWith(p)) && !extname(basename(specifier))) {
    let postfix = findPostfix(specifier, context)
    if (postfix) {
      return nextResolve(specifier + postfix)
    }
  }

  return nextResolve(specifier)
}

export {
  resolve
}

【讨论】:

    猜你喜欢
    • 2022-12-26
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 2017-03-26
    • 1970-01-01
    • 2022-12-02
    • 2022-12-27
    • 2022-12-02
    相关资源
    最近更新 更多