Skip to content

chore(build): build a universal ESM and CommonJS package #371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 29 commits into
base: main
Choose a base branch
from

Conversation

gagik
Copy link
Collaborator

@gagik gagik commented Jul 15, 2025

Adds ESM and CommonJS-based exports to the package.

The motivation is largely to add support for VSCode to use the library.

Possible Alternatives

  • Target cjs and use gen-esm-wrapper - might be simpler in a sense and more consistent with how we deal with it in i.e. mongosh and other packages. But because we were distributing an ESM package until now, the potential breaking change is a bit worrying.

Inspired by #325

Relevant reading:

const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as PackageJson;

// Define the packageInfo.ts content
const packageInfoContent = `// This file was generated by scripts/update-package-info.ts - Do not edit it manually.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no good way to have __dirname / import.meta.dirname as explored in https://evertpot.com/universal-commonjs-esm-typescript-packages/ and I couldn't think of anything better either. so instead we'll generate the file on-demand. This is similar to how it is done in github.com/mongodb-js/mongosh/

@coveralls
Copy link
Collaborator

coveralls commented Jul 15, 2025

Pull Request Test Coverage Report for Build 16320816887

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 2 of 66 (3.03%) changed or added relevant lines in 6 files are covered.
  • 1 unchanged line in 1 file lost coverage.
  • Overall coverage decreased (-0.5%) to 76.93%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/lib.ts 0 3 0.0%
scripts/updatePackageVersion.ts 0 8 0.0%
scripts/createUniversalPackage.ts 0 11 0.0%
src/index.ts 0 42 0.0%
Files with Coverage Reduction New Missed Lines %
src/index.ts 1 1.92%
Totals Coverage Status
Change from base Build 16292877152: -0.5%
Covered Lines: 2827
Relevant Lines: 3635

💛 - Coveralls

package.json Outdated
"scripts": {
"prepare": "npm run build",
"build:clean": "rm -rf dist",
"build:compile": "tsc --project tsconfig.build.json",
"build:update-package-info": "tsx scripts/update-package-info.ts",
"build:esm": "tsc --project tsconfig.esm.json && echo '{\"type\":\"module\"}' > dist/package.json",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Source: As you can also see that both our cjs and esm packages get a 1-line package.json file with a type property.

This is required because Node needs to know wether files with a .js extensions should be interpreted as CommonJS or ESM. It can’t figure it out after opening it.

Node will look at the nearest package.json to see if the type property was specified.

@gagik gagik changed the title WIP ESM-CJS targetting chore(build): build a universal ESM and CommonJS package Jul 15, 2025
@@ -55,4 +55,4 @@ jobs:
rm -rf node_modules
npm pkg set scripts.prepare="exit 0"
npm install --omit=dev
- run: npx -y @modelcontextprotocol/inspector --cli --method tools/list -- node dist/index.js --connectionString "mongodb://localhost"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm setting to ESM to keep the changes minimal. Doing cjs default won't change our issues with the oidc-plugin, I think the only way to deal with that is to make some changes on the plugin itself to not depend on the require of an ESM module which is a higher Node version feature.

Generally worth checking if we're going to have any problems with dist/index.js going away.

I'd expect the worst being our dev environment configurations no longer being correct.

Otherwise we can also create a index.js alias to point to esm.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is solved, now that you have dist/index.js pointing to esm.

@gagik gagik marked this pull request as ready for review July 15, 2025 15:41
@gagik gagik requested a review from a team as a code owner July 15, 2025 15:41
@@ -0,0 +1,4 @@
export { Server, type ServerOptions } from "./server.js";
export { Telemetry } from "./telemetry/telemetry.js";
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can consider exporting a single class which would make the setup easier but I'll leave that to future followups


// Create a dist/index.js file that imports the ESM index.js file
// To minimize breaking changes from pre-universal package time.
const indexPath = resolve(distDir, "index.js");
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just out of precaution in case some of our deployments end up looking for dist/index.js... can be removed though

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think its fine to have it.

Copy link
Collaborator

@himanshusinghs himanshusinghs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks perfect. Tested it locally with vscode and works as expected 🚀

Totally unrelated but you might wanna cherry-pick the changes in this commit because currently we are shipping some unnecessary files in our final dist.

@@ -55,4 +55,4 @@ jobs:
rm -rf node_modules
npm pkg set scripts.prepare="exit 0"
npm install --omit=dev
- run: npx -y @modelcontextprotocol/inspector --cli --method tools/list -- node dist/index.js --connectionString "mongodb://localhost"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is solved, now that you have dist/index.js pointing to esm.

}
}
},
"main": "./dist/cjs/lib.js",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should add the types as well pointing to "./dist/cjs/lib.d.ts" considering that the main is for older tooling?


// Create a dist/index.js file that imports the ESM index.js file
// To minimize breaking changes from pre-universal package time.
const indexPath = resolve(distDir, "index.js");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think its fine to have it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants