How to migrate typescript commonjs to esm with vscode

package.json

add following key to package.json

{
  "type": "module",
  "main": "./dist/src/main.js",
  "exports": {
    ".": "./dist/src/main.js"
  },
  "typesVersions": {
    "*": {
      "main.d.ts": ["dist/src/main.d.ts"]
    }
  }
}

Nicer module specifiers for a subtree:

{
  "type": "module",
  "main": "./dist/src/main.js",
  "exports": {
    "./*": "./dist/src/*"
  },
  "typesVersions": {
    "*": {
      "*": ["dist/src/*"]
    }
  }
}

Default typescript documentation

{
    "name": "my-package",
    "type": "module",
    "exports": {
        ".": {
            // Entry-point for `import "my-package"` in ESM
            "import": "./esm/index.js",
            // Entry-point for `require("my-package") in CJS
            "require": "./commonjs/index.cjs",
        },
    },
    // CJS fall-back for older versions of Node.js
    "main": "./commonjs/index.cjs",
}
  • "typesVersions" performs the same mapping as "exports", but for TypeScript's type definitions.

tsconfig.json

match your configuration (points A, B, C)

{
  "compilerOptions": {
    "rootDir": "./",
    "outDir": "./dist",
    "target": "ES2020",
    "lib": [
      "ES2020", "DOM"
    ],
    "module": "ES2020", // (A)
    "moduleResolution": "Node", // (B)
    "strict": true,
    "sourceMap": true,
    // Needed for importing CommonJS modules
    "allowSyntheticDefaultImports": true, // (C)
    // Compile d.ts
    "declaration": true,
  }
}
  • Line A ("module"): We are telling TypeScript to generate ECMAScript modules.
    • "ES6", "ES2015": support for basic ESM features
    • "2020": additionally, support for dynamic imports and import.meta.
  • Line B ("moduleResolution"): This value is needed for Node.js.
  • Line C ("allowSyntheticDefaultImports"): I needed this setting in order to import a legacy CommonJS module. The module.exports were the default export in that case.

VSCode settings.json

open your settings.json or .vscode/settings.json, add following keys

{
  //...
  "javascript.preferences.importModuleSpecifierEnding": "js",
  "typescript.preferences.importModuleSpecifierEnding": "js"
  //...
}

Replace non extension of imports

add filename extensions to existing local imports (within a package):

Method 1

  • Open Search And Replace VSCode
  • Insert below pattern to search input and check Regex Search Flag
(^import.*\/((?!.js).)*)(['"];)$
  • Insert below replacement pattern to replacement input
$1.js$3
  • Insert folder to files to input bar for example src/
  • Replace all
    image

Method 2

  • Search: ^(import [^';]* from '(\./|(\.\./)+)[^';.]*)';
  • Replace: $1.js';