Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion packages/devtools-proxy-support/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ async function importNodeFetch(): Promise<typeof fetch> {
// Node-fetch is an ESM module from 3.x
// Importing ESM modules to CommonJS is possible with a dynamic import.
// However, once this is transpiled with TS, `await import()` changes to `require()`, which fails to load
// the package at runtime.
// the package at runtime for Node < 23.
// The alternative, to transpile with "moduleResolution": "NodeNext", is not always feasible.
// Use this function to safely import the node-fetch package
let module: typeof fetch | { default: typeof fetch };
try {
suppressExperimentalWarningsIfNecessary();
module = await import('node-fetch');
} catch (err: unknown) {
if (
Expand All @@ -37,6 +38,35 @@ async function importNodeFetch(): Promise<typeof fetch> {

return typeof module === 'function' ? module : module.default;
}

let warningsSuppressed = false;

// In Node.js 23 require()ing ESM modules will work, but emit an experimental warning like
// CommonJS module ABC is loading ES Module XYZ using require().
// This function suppresses experimental warnings to avoid those leaking into end users' output.
function suppressExperimentalWarningsIfNecessary() {
const nodeMajorVersion = process.versions.node.split('.').map(Number)[0];
if (nodeMajorVersion >= 23 && !warningsSuppressed) {
const originalEmit = process.emitWarning;
process.emitWarning = (warning, ...args: any[]): void => {
if (args[0] === 'ExperimentalWarning') {
return;
}

if (
typeof args[0] === 'object' &&
args[0].type === 'ExperimentalWarning'
) {
return;
}

originalEmit(warning, ...args);
};

warningsSuppressed = true;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

If this is the approach we're going with – which I think is pretty reasonable – then I'd do that in the mongosh CLI itself, like we already disable warnings for the case of the compiled executable in packages/cli-repl/src/run.ts, because that's where we're expecting overrides for Node.js behavior and other modifications to truly global state, how does that sound to you?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure, that sounds reasonable to me! I guess originally I wanted to put it next to the code that does the requiring shenanigans, but you're right that the warnings being displayed or not is better left to the user-facing application.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I think there's also just going to be more code running into this problem in the future, the more popular ESM gets in our dependencies, not just the code here


let cachedFetch: Promise<typeof fetch> | undefined;

export type { Request, Response, RequestInfo, RequestInit };
Expand Down
Loading