Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 0cb151e

Browse files
authored
nodejs_compat flag (#478)
1 parent a9d4565 commit 0cb151e

File tree

5 files changed

+46
-2
lines changed

5 files changed

+46
-2
lines changed

packages/core/src/plugins/core.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import webStreams from "stream/web";
2525
import { URL, URLSearchParams } from "url";
2626
import { TextDecoder, TextEncoder } from "util";
2727
import {
28+
AdditionalModules,
2829
CompatibilityFlag,
2930
Context,
3031
ModuleRule,
@@ -70,6 +71,7 @@ import {
7071
} from "../standards";
7172
import { assertsInRequest } from "../standards/helpers";
7273
import type { BindingsOptions } from "./bindings";
74+
import { additionalModules } from "./node";
7375

7476
const DEFAULT_MODULE_RULES: ModuleRule[] = [
7577
{ type: "ESModule", include: ["**/*.mjs"] },
@@ -411,6 +413,7 @@ export class CorePlugin extends Plugin<CoreOptions> implements CoreOptions {
411413

412414
readonly upstreamURL?: URL;
413415
readonly #globals: Context;
416+
readonly #additionalModules?: AdditionalModules;
414417

415418
constructor(ctx: PluginContext, options?: CoreOptions) {
416419
super(ctx);
@@ -421,6 +424,11 @@ export class CorePlugin extends Plugin<CoreOptions> implements CoreOptions {
421424
);
422425
}
423426

427+
const nodejsCompat = ctx.compat.isEnabled("nodejs_compat");
428+
if (nodejsCompat) {
429+
this.#additionalModules = additionalModules;
430+
}
431+
424432
const extraGlobals: Context = {};
425433

426434
// Make sure the kFormDataFiles flag is set correctly when constructing
@@ -652,11 +660,13 @@ export class CorePlugin extends Plugin<CoreOptions> implements CoreOptions {
652660

653661
async setup(): Promise<SetupResult> {
654662
const globals = this.#globals;
663+
const additionalModules = this.#additionalModules;
655664

656665
// First, try to load script from string, no need to watch any files
657666
if (this.script !== undefined) {
658667
return {
659668
globals,
669+
additionalModules,
660670
script: { filePath: STRING_SCRIPT_PATH, code: this.script },
661671
};
662672
}
@@ -689,11 +699,16 @@ export class CorePlugin extends Plugin<CoreOptions> implements CoreOptions {
689699
scriptPath = path.resolve(this.ctx.rootPath, scriptPath);
690700
const code = await fs.readFile(scriptPath, "utf8");
691701
watch.push(scriptPath);
692-
return { globals, script: { filePath: scriptPath, code }, watch };
702+
return {
703+
globals,
704+
additionalModules,
705+
script: { filePath: scriptPath, code },
706+
watch,
707+
};
693708
}
694709

695710
// If we couldn't load a script yet, keep watching package.json anyways, it
696711
// might get edited with a path
697-
return { globals, watch };
712+
return { globals, additionalModules, watch };
698713
}
699714
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import async_hooks from "node:async_hooks";
2+
3+
export class AsyncHooksModule {
4+
AsyncLocalStorage = async_hooks.AsyncLocalStorage;
5+
AsyncResource = async_hooks.AsyncResource;
6+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { AsyncHooksModule } from "./async_hooks";
2+
3+
export const additionalModules = {
4+
"node:async_hooks": { default: new AsyncHooksModule() },
5+
};

packages/core/test/plugins/core.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,20 @@ test("CorePlugin: setup: uses actual time if option enabled", async (t) => {
654654
});
655655
});
656656

657+
test("CorePlugin: nodejs_compat compatibiltiy flag includes Node.js modules", async (t) => {
658+
const compat = new Compatibility(undefined, ["nodejs_compat"]);
659+
660+
const plugin = new CorePlugin(
661+
{ ...ctx, compat },
662+
{ compatibilityFlags: ["nodejs_compat"] }
663+
);
664+
const additionalModules = (await plugin.setup()).additionalModules;
665+
t.deepEqual(
666+
Object.keys(additionalModules?.["node:async_hooks"].default ?? {}),
667+
["AsyncLocalStorage", "AsyncResource"]
668+
);
669+
});
670+
657671
// Test stream constructors
658672
test("CorePlugin: setup: ReadableStream/WriteableStream constructors only enabled if compatibility flag enabled", async (t) => {
659673
// Check without "streams_enable_constructors" compatibility flag (should throw)

packages/shared/src/compat.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export interface CompatibilityFeature {
1111
// will get a type error if they try to use an unsupported flag via the API,
1212
// and they won't be logged in the "Enabled Compatibility Flags" section.
1313
export type CompatibilityEnableFlag =
14+
| "nodejs_compat"
1415
| "streams_enable_constructors"
1516
| "transformstream_enable_standard_constructor"
1617
| "r2_list_honor_include"
@@ -31,6 +32,9 @@ export type CompatibilityFlag =
3132
| CompatibilityDisableFlag;
3233

3334
const FEATURES: CompatibilityFeature[] = [
35+
{
36+
enableFlag: "nodejs_compat",
37+
},
3438
{
3539
defaultAsOf: "2022-11-30",
3640
enableFlag: "streams_enable_constructors",

0 commit comments

Comments
 (0)