javascript - Hvordan forhindre at typescript transpilerer dynamiske imports til require()?


Jeg lager en discord.js Discord-bot. Nå, av en eller annen grunn, fungerer ikke discord.js med ESM-moduler (et helt separat problem), så bot-appen min bruker CommonJS-moduler. Nå har jeg et annet prosjekt på systemet mitt kalt Lib, som har mange hjelpefunksjoner som jeg planlegger å bruke i flere forskjellige prosjekter, slik at jeg ikke trenger å skrive dem på nytt. Dette Lib-prosjektet bruker ESM-moduler. Siden jeg må importere Lib fra DiscordBot, bruker jeg syntaksen for dynamisk import i typescript. Nå, hver gang jeg transpilerer DiscordBot-prosjektet mitt, blir de dynamiske importene konvertert til noe stygg javascript modulkode, og den stygge modulkoden ender til slutt opp med å bruke require(). Siden require() ikke kan importere ESM-moduler, krasjer boten min.

Jeg prøvde imidlertid å stoppe ts-kompilatoren min, kopiere koden fra ts-filen min som importerer Lib og deretter lime den koden inn i den tilsvarende JS-filen manuelt (og fjerne TS-eksklusive funksjoner som typeannotasjoner og grensesnitt). Så kjørte jeg bot-appen min, og det fungerte helt fint. Men jeg vil ikke måtte gjøre dette hver gang. Så det er tsc-kompileringen som er problemet. Hvordan kan jeg fikse dette?

Svar #1

Så jeg forstår at hensikten er:

  1. Utvikle koden i TypeScript
  2. Kjør den kompilert koden i CommonJS-pakken
  3. Importer og bruk en ES-modul

Alternativ 1:

Hvis "module" i tsconfig.json er satt til "commonjs", finnes det for øyeblikket ingen måte å forhindre at TypeScript transpilerer dynamisk import() til require() - bortsett fra at du skjuler koden i en streng og bruker eval for å kjøre den. Slik:

async function body (pMap:any){
   // do something with module pMap here
}

eval ("import('p-map').then(body)");

Ingen vei, TypeScript transpilere en streng!


Alternativ 2

Sett "module" i tsconfig.json til "es2020". Ved å gjøre dette vil dynamisk import ikke bli transpillert til require(), og du kan bruke dynamisk import for å importere en CommonJS- eller ES-modul. Eller du kan bruke syntaksen const someModule=require("someModule") for å importere en CommonJS-modul (vil ikke bli transpillert til ES6-importsyntaks). Du kan ikke bruke ES6-importsyntaks som import * as someModule from "someModule" eller import someModule from "someModule". Disse syntaksene vil generere ES Module-syntaksimporter ("module" er satt til "es2020") og kan ikke kjøres i CommonJS-pakker.


Nedenfor er litt informasjon:

  • Hvis "module" er satt til "es2020": dynamisk import import() blir ikke transpilerte.

  • Hvis "module" er satt til `"es2015": det oppstår en feil:

    TS1323: Dynamiske importeringer støttes bare når '--module'-flagget er satt til 'es2020', 'esnext', 'commonjs', 'amd', 'system' eller 'umd'.

  • Hvis "module" er satt til "commonjs": dynamiske imports blir transpilert.

Sitat tsconfig.json-referanse for "module"-feltet:

Hvis du lurer på forskjellen mellom ES2015 og ES2020, legger ES2020 til støtte for dynamiske importeringer og import.meta.

Svar #2

Innstillingen node12 som andre snakker om, fungerte ikke for meg, men disse compilerOptions gjorde det, ved bruk av Typescript 4.7.2:

"module": "CommonJS",
"moduleResolution": "Node16",

Dette reddet meg, jeg slapp å migrere alle import require-er til imports for å kunne bruke et ESM npm-bibliotek.

Typescript inndatakilde:

import Redis = require('redis');
import * as _ from 'lodash';

export async function main() {
    const fileType = await import('file-type');
    console.log(fileType, _.get, Redis);
}

CommonJS-utdata:

...
const Redis = require("redis");
const _ = __importStar(require("lodash"));
async function main() {
    const fileType = await import('file-type');
    console.log(fileType, _.get, Redis);
}
exports.main = main;

Relaterte artikler