Skip to content

Migrate TypeScript Output from CommonJS (CJS) to ES Modules (ESM) #2615

@gerteck

Description

@gerteck

Context

Helpful understanding:

TLDR

  • ESM modules can import CJS modules.
  • CJS modules cannot import ESM modules.
  • MarkBind is built as a CJS module.
  • We cannot use modern ESM-only dependencies. If existing packages migrate to esm, we cannot update dependencies. If we want to integrate new esm-only packages, we also can't do so.
  • Only by migrating, will allow usage of both old CJS and new ESM packages. Hence, for future compatibility + usage of modern JavaScript features, it is a necessary infrastructure change.

Describe the Enhancement

MarkBind's TypeScript configuration currently outputs CommonJS ("module": "commonjs"), a legacy module system. At some point, we should do a rewrite to migrate to a modern ESM-based output ("module": "NodeNext") to align with the evolving JavaScript ecosystem, unlock performance benefits, and ensure future compatibility.

  • Ecosystem Shift: The JavaScript/Node.js ecosystem is standardizing on ES Modules (ESM).
  • Performance & Features: ESM enables advanced optimizations like superior tree-shaking and supports modern language features like Top-Level await, which are impossible with CommonJS output.
  • Forward Compatibility: Using "NodeNext" ensures the project correctly interoperates with both ESM and CJS packages according to Node.js's own modern rules, making it resilient to future ecosystem changes.
    • Newer versions of critical dependencies (e.g., [email protected] (?)) may become pure ESM, causing integration issues to only become more frequent, especially as conduct maintainence and pdate dependencies.
    • Newer packages that we might want to integrate in the future may not support CJS require, and only support being used as a ESM module via import. (Case in point: pagefind). As future batches work to enhance MarkBind, this will be a significant roadblock if not resolved, and workarounds will only add to tech debt.
  • Official Guidance: The TypeScript documentation now explicitly discourages "commonjs" for new projects, recommending "node16"/"nodenext" for Node.js environments.

Proposed Changes

  1. Update tsconfig.json:
  • Change "module": "commonjs" to "module": "NodeNext" or as appropriate.
  • Change "moduleResolution": "node" to "moduleResolution": "NodeNext".
  1. Migrate Legacy JavaScript Files: Convert remaining .js files using require/module.exports (e.g., in src/patches/) to use ESM import/export syntax.
  2. Update package.json: Ensure "type": "module" is set appropriately for the project to be recognized as ESM by Node.js.

Others

Also, don't get confused:

  • Even tho right now in the ts files, we are using import etc. (which is esm syntax), because of the ultimate output as cjs that in the end converts everything to require, we can't use esm only modules.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions