-
Notifications
You must be signed in to change notification settings - Fork 96
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
Conversation
…gagik/cjs-target
scripts/update-package-info.ts
Outdated
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. |
There was a problem hiding this comment.
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/
Pull Request Test Coverage Report for Build 16804714278Details
💛 - 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", |
There was a problem hiding this comment.
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.
.github/workflows/check.yml
Outdated
@@ -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" |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
@@ -0,0 +1,4 @@ | |||
export { Server, type ServerOptions } from "./server.js"; | |||
export { Telemetry } from "./telemetry/telemetry.js"; |
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this 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.
.github/workflows/check.yml
Outdated
@@ -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" |
There was a problem hiding this comment.
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.
|
||
// 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"); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request implements universal ESM and CommonJS package support for the MongoDB MCP server, enabling compatibility with both module systems while maintaining backwards compatibility.
- Creates separate ESM and CommonJS build configurations with dual TypeScript compilation
- Adds a new library entry point with explicit exports for better module resolution
- Updates all references from the old build output path to the new ESM path for consistency
Reviewed Changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
File | Description |
---|---|
tsconfig.esm.json | New ESM-specific TypeScript configuration targeting esnext modules |
tsconfig.cjs.json | New CommonJS-specific TypeScript configuration targeting commonjs modules |
tsconfig.build.json | Updated base build config to enable declaration files and maps |
tests/integration/build.test.ts | Integration tests to verify both module formats work correctly |
src/lib.ts | New library entry point exporting all public APIs |
src/common/packageInfo.ts | Generated file with hardcoded version to avoid JSON import issues |
scripts/updatePackageVersion.ts | Script to generate packageInfo.ts with current package version |
scripts/createUniversalPackage.ts | Script to create package.json files for each module format |
package.json | Updated with dual exports configuration and new build scripts |
CONTRIBUTING.md | Updated documentation paths to reference ESM build |
.smithery/smithery.yaml | Updated command path to ESM build |
.smithery/Dockerfile | Updated Docker command to use ESM build |
.github/workflows/prepare_release.yaml | Added version update step to release workflow |
.github/workflows/check.yml | Updated CI command path to ESM build |
dfcc23c
to
f8bc161
Compare
ed8766c
to
1ce9aa0
Compare
}); | ||
} | ||
} | ||
this.setupEventListeners(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is technically a side effect in a constructor which we generally avoid but won't tackle this here.
Adds ESM and CommonJS-based exports to the package.
The motivation is largely to add support for VSCode to use the library.
Possible Alternatives
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: