Bootcamp i backendudvikling med Node.js · Lektion

Migrering fra CommonJS til native ES-moduler

Konvertér require/module.exports til import/export, og håndtér faldgruber ved dual packages og interoperabilitet.

Lektion 1 af 413 trin

Migrering fra CommonJS til native ES-moduler er en gratis Bootcamp i backendudvikling med Node.js-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Bootcamp i backendudvikling med Node.js, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Bootcamp i backendudvikling med Node.js-kurset indeholder 4 lektioner i alt.

To modulsystemer, én kørselstid

Node.js brugte historisk CommonJS (CJS): du indlæser kode med require() og eksponerer den med module.exports. Moderne JavaScript har en indbygget standard, ES Modules (ESM), der bruger import og export.

  • CommonJS indlæser moduler synkront under kørsel.
  • ESM analyseres statisk, indlæses asynkront og er den officielle ECMAScript-standard.

Node understøtter nu begge dele, men der gælder regler for at blande dem. I denne lektion lærer du trin for trin at migrere et backend-projekt fra CJS til naturlig ESM på en ren måde.

// CommonJS (old)
const fs = require('fs');
module.exports = { readConfig };

// ES Modules (new)
import fs from 'fs';
export { readConfig };

Fortæl Node, at du mener ESM

Node afgør, hvordan en fil skal behandles, ud fra filendelsen og den nærmeste package.json:

  • "type": "module" i package.json → .js-filer behandles som ESM.
  • Intet type-felt (eller "commonjs") → .js-filer er CommonJS.
  • .mjs er altid ESM, og .cjs er altid CommonJS, uanset type.

Det reneste migreringstrin er at tilføje "type": "module" én gang og derefter rette de filer, som det skaber problemer for.

{
  "name": "my-api",
  "version": "1.0.0",
  "type": "module",
  "main": "src/server.js",
  "scripts": {
    "start": "node src/server.js"
  }
}

Konverter eksporteringer

Erstat module.exports og exports.foo med export-sætninger.

  • module.exports = X (enkelt værdi) → export default X.
  • exports.foo = ... (flere navngivne værdier) → export const foo = ... eller en samlet export { foo, bar }.

Foretræk navngivne eksporteringer til hjælpefunktioner, så brugere får autoudfyldning og tydeligere importeringer.

// Before (CJS)
// module.exports.add = (a, b) => a + b;
// module.exports.PI = 3.14159;

// After (ESM)
export const add = (a, b) => a + b;
export const PI = 3.14159;

console.log(add(2, 3)); // 5
console.log(PI);        // 3.14159

Konverter importeringer

Erstat require() med import. Tilpas til eksportstilen:

  • Navngivet: const { add } = require('./math') → import { add } from './math.js'.
  • Standard: const express = require('express') → import express from 'express'.

Vigtig regel: I ESM skal relative importeringer af dine egne filer indeholde filendelsen (.js). Node gætter ikke endelsen for dig, som CommonJS gjorde.

// Before (CJS)
// const { add } = require('./math');

// After (ESM) — note the explicit .js extension
import { add } from './math.js';

console.log(add(10, 5)); // 15

Ikke flere __dirname eller __filename

ESM stiller ikke CommonJS-globale variablerne __dirname og __filename til rådighed. Hvis din backend opbygger filstier (konfiguration, uploads, skabeloner), skal du genskabe dem ud fra import.meta.url.

Moderne Node (20.11+) stiller også import.meta.dirname og import.meta.filename direkte til rådighed, hvilket er den enkleste løsning fremover.

import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

// Classic portable approach
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const configPath = join(__dirname, 'config.json');
console.log(configPath);

// Node 20.11+ shortcut:
// const dir = import.meta.dirname;

Importering af JSON og indbyggede moduler

Her er yderligere to ændringer, der ofte giver backend-projekter problemer:

  • JSON: require('./data.json') fungerer ikke længere direkte. Brug en importattribut: import data from './data.json' with { type: 'json' }.
  • Kernemoduler: Foretræk præfikset node: (f.eks. import { readFile } from 'node:fs/promises'). Det er entydigt og fremtidssikret.

Hvis du sigter mod en ældre Node-version, undgår læsning af JSON via fs helt problemer med kompatibilitet for attributsyntaks.

import { readFile } from 'node:fs/promises';

// Robust, version-agnostic way to load JSON in ESM
const raw = await readFile(new URL('./pkg.json', import.meta.url));
const pkg = JSON.parse(raw);
console.log(pkg.name);

await på øverste niveau er en superkraft

En reel forbedring, som ESM giver backend-kode, er await på øverste niveau. I CommonJS skulle du pakke asynkron opstart ind i en IIFE. I et ESM-modul kan du bruge await direkte på øverste niveau.

Det gør databaseforbindelser, hentning af konfiguration og opvarmningslogik meget renere i serverens startfiler.

// ESM entry file
async function connectDb() {
  await new Promise((r) => setTimeout(r, 50));
  return { status: 'connected' };
}

const db = await connectDb(); // top-level await — no IIFE needed
console.log('DB:', db.status);

Interoperabilitet: ESM importerer CommonJS

Du vil stadig være afhængig af npm-pakker, der kun understøtter CJS. Den gode nyhed er, at ESM kan importere CommonJS. Node pakker pakkens module.exports ind som standardeksporten.

  • Brug import pkg from 'cjs-lib' for at hente module.exports.
  • Node forsøger også at finde navngivne eksporteringer, men det kan mislykkes for kompleks CJS — destrukturer i stedet standardeksporten.
// 'lodash' is CommonJS; the whole export object is the default
import _ from 'lodash';

const { chunk } = _; // safe: destructure from default
console.log(chunk([1, 2, 3, 4], 2)); // [[1,2],[3,4]]

Interoperabilitet: CommonJS indlæser ESM

Den omvendte retning er vanskeligere. En CommonJS-fil kan ikke synkront bruge require() til at indlæse et ESM-modul (ældre Node-versioner udløser ERR_REQUIRE_ESM). Muligheder:

  • Brug en dynamisk import(), som returnerer et Promise — det fungerer inde i asynkrone funktioner i CJS.
  • Node 22+ tilføjede eksperimentel synkron require() af ESM, men stol ikke på det i kode, der skal være portabel.

Denne asymmetri er hovedårsagen til, at teams migrerer hele kodebasen til ESM i stedet for at blande systemerne.

// Inside a CommonJS file:
async function run() {
  // dynamic import works even from CJS
  const { add } = await import('./math.mjs');
  console.log(add(4, 6)); // 10
}

run();

Udgivelse af dobbelte pakker

Hvis du udgiver et bibliotek, bruger nogle brugere ESM, mens andre bruger CJS. Den moderne løsning er feltet exports med betingede eksporteringer, så begge builds leveres.

  • import-betingelse → ESM-startpunktet.
  • require-betingelse → CJS-startpunktet.

Pas på risikoen ved dobbelte pakker: Hvis begge builds indlæses, får du to kopier af modulets tilstand (f.eks. to separate singletoner). Placér tilstandsafhængig logik i ét internt modul, som begge builds importerer.

{
  "name": "my-lib",
  "type": "module",
  "main": "./dist/index.cjs",
  "module": "./dist/index.js",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    }
  }
}

En pragmatisk migreringstjekliste

En pålidelig rækkefølge for et eksisterende backend-projekt:

  • Tilføj "type": "module" til package.json.
  • Omdøb alle filer, der skal forblive CJS, til .cjs.
  • Konvertér require/module.exports til import/export.
  • Tilføj .js-endelser til alle relative importeringer.
  • Erstat __dirname/__filename med import.meta-hjælpere.
  • Ret JSON-importeringer og interoperabilitet med CJS-standardeksportering.
  • Kør testpakken, og lad fejlene pege på resterende require-kald.

Værktøjer som cjstoesm eller codemods kan automatisere de fleste redigeringer, men gennemgå altid diffen.

Hurtigt tjek

Du konverterer en backend-fil til ESM og tilføjer "type": "module". Pludselig udløser en importering af din egen hjælpefunktion ERR_MODULE_NOT_FOUND. Hvad er den mest sandsynlige løsning?

Opsummering

Du har migreret en Node.js-backend fra CommonJS til naturlige ES-moduler. Vigtigste pointer:

  • Tilvælg systemet med "type": "module", og brug .cjs/.mjs til at tilsidesætte det pr. fil.
  • Erstat require/module.exports med import/export, og medtag altid .js-endelsen i relative importeringer.
  • Genskab __dirname via import.meta.url (eller brug import.meta.dirname).
  • ESM kan importere CJS (som standardeksportering); CJS skal bruge dynamisk import() til ESM.
  • await på øverste niveau forenkler asynkron opstart.
  • Brug betingede exports til biblioteker, og pas på risikoen ved dobbelte pakker.

Med disse regler kan du trygt modernisere enhver Node-tjeneste til standardiserede ES-moduler.

Gratis at komme i gang

Lær JavaScript med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
22
Lektioner
92

Ofte stillede spørgsmål

Er lektionen “Migrering fra CommonJS til native ES-moduler” gratis?

Ja — hele teksten til “Migrering fra CommonJS til native ES-moduler” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Bootcamp i backendudvikling med Node.js-kurset, skal du opgradere til CoddyKit PRO. Bootcamp i backendudvikling med Node.js-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Migrering fra CommonJS til native ES-moduler”?

Konvertér require/module.exports til import/export, og håndtér faldgruber ved dual packages og interoperabilitet. Du øver dig i Bootcamp i backendudvikling med Node.js med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Bootcamp i backendudvikling med Node.js?

Der kræves ingen tidligere erfaring. Bootcamp i backendudvikling med Node.js på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.

Hvor lang tid tager lektionen “Migrering fra CommonJS til native ES-moduler”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Bootcamp i backendudvikling med Node.js-lektion?

Ja. Alle Bootcamp i backendudvikling med Node.js-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Migrering fra CommonJS til native ES-moduler
  2. Konfiguration af tsconfig til Node-backendprojekter
  3. Typesikker miljøkonfiguration og runtime-validering
  4. Hurtig iteration med tsx, hot reload og source maps
← Tilbage til Bootcamp i backendudvikling med Node.js