node.js - nodeJS v19 slutar stödja --es-module-specifier-resolution=node vilket gör det svårare att köra transpilerad TypeScript


Typescript transpileras till JavaScript, så en modul routes.ts konverteras till routes.js i den katalog som tsc placerar den. Om en annan modul importerar namn (t.ex. "router") från en modul, utelämnar vi suffixet som i:

import { router } from './routes'

Detta fungerade bra tills node slutade använda .js som standardändelse. Från och med node V16 (eller kanske tidigare?) blev det nödvändigt att lägga till flaggan --es-module-specifier-resolution=node för att kunna köra den transpilerade koden med node. I senare versioner av nodeJS blev detta alternativ nedgraderat genom att tyst omvandlas till --experimental-specifier-resolution=node, vilket sedan helt försvann i NodeJS v19.

Nu i NodeJS v19 ska man istället använda "custom loaders". Är det verkligen så svårt att köra transpilerad TypeScript-kod? Vad är den rekommenderade metoden?

(SO: säger att denna fråga duplicerar den relaterade frågan Att lägga till .js-tillägg på relativa importuttalanden under Typescript-kompilering (ES6-moduler), men denna fråga har mer information om olika versioner av nodeJS - den är relaterad, så folk kanske vill kolla in den.)

Svar #1

UPPDATERING: Jag har skapat ett paket för detta ändamål och publicerat det på npm. Alla som vill använda det kan besöka dess sida för mer information.

Du kan fortfarande använda en anpassad loader med Node.js v19. Spara följande i en fil med namnet loader.js i projektkatalogen och kör sedan node med flaggan --experimental-loader ./loader.js tillagd.

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)
}

Relaterade artiklar