Skip to content

Commit 37dc327

Browse files
Merge pull request #6069 from cloudflare/pbacondarwin/worker-threads-internal-messagechannel
Make node:worker_threads independent of expose_global_message_channel flag
2 parents ee6d283 + 1d8cfaa commit 37dc327

File tree

7 files changed

+66
-7
lines changed

7 files changed

+66
-7
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2017-2022 Cloudflare, Inc.
2+
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3+
// https://opensource.org/licenses/Apache-2.0
4+
5+
// Type definitions for cloudflare-internal:messagechannel
6+
// This internal module exposes MessageChannel and MessagePort for use by
7+
// built-in modules like node:worker_threads, independent of the
8+
// expose_global_message_channel compatibility flag.
9+
10+
declare namespace _default {
11+
const MessageChannel: typeof globalThis.MessageChannel;
12+
const MessagePort: typeof globalThis.MessagePort;
13+
}
14+
export default _default;

src/node/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"cloudflare-internal:sockets": ["./internal/sockets.d.ts"],
1818
"cloudflare-internal:workers": ["./internal/workers.d.ts"],
1919
"cloudflare-internal:tracing": ["./internal/tracing.d.ts"],
20-
"cloudflare-internal:filesystem": ["./internal/filesystem.d.ts"]
20+
"cloudflare-internal:filesystem": ["./internal/filesystem.d.ts"],
21+
"cloudflare-internal:messagechannel": ["./internal/messagechannel.d.ts"]
2122
}
2223
}
2324
}

src/node/worker_threads.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ import type { Readable, Writable } from 'node:stream';
3535
import type { Transferable, WorkerPerformance } from 'node:worker_threads';
3636
import type { CPUProfileHandle, HeapInfo, HeapProfileHandle } from 'node:v8';
3737

38-
export const MessageChannel = globalThis.MessageChannel;
39-
export const MessagePort = globalThis.MessagePort;
38+
// Import MessageChannel and MessagePort from the internal module to avoid
39+
// dependency on the expose_global_message_channel compatibility flag.
40+
import internalMessageChannel from 'cloudflare-internal:messagechannel';
41+
42+
export const MessageChannel = internalMessageChannel.MessageChannel;
43+
export const MessagePort = internalMessageChannel.MessagePort;
4044

4145
// TODO(soon): Use globalThis.BroadcastChannel once it's available.
4246
export class BroadcastChannel {

src/workerd/api/messagechannel.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#include <workerd/api/basics.h>
44
#include <workerd/io/io-context.h>
55
#include <workerd/jsg/jsg.h>
6+
#include <workerd/jsg/modules-new.h>
67
#include <workerd/jsg/ser.h>
8+
#include <workerd/jsg/url.h>
79
#include <workerd/util/weak-refs.h>
810

911
namespace workerd::api {
@@ -169,7 +171,37 @@ class MessageChannel final: public jsg::Object {
169171
jsg::Ref<MessagePort> port2;
170172
};
171173

174+
// Module that exposes MessageChannel and MessagePort for internal use by
175+
// built-in modules like node:worker_threads without requiring the global
176+
// expose_global_message_channel compat flag.
177+
class MessageChannelModule final: public jsg::Object {
178+
public:
179+
MessageChannelModule() = default;
180+
MessageChannelModule(jsg::Lock&, const jsg::Url&) {}
181+
182+
JSG_RESOURCE_TYPE(MessageChannelModule) {
183+
JSG_NESTED_TYPE(MessageChannel);
184+
JSG_NESTED_TYPE(MessagePort);
185+
}
186+
};
187+
188+
template <class Registry>
189+
void registerMessageChannelModule(Registry& registry, auto featureFlags) {
190+
registry.template addBuiltinModule<MessageChannelModule>(
191+
"cloudflare-internal:messagechannel", workerd::jsg::ModuleRegistry::Type::INTERNAL);
192+
}
193+
194+
template <typename TypeWrapper>
195+
kj::Own<jsg::modules::ModuleBundle> getInternalMessageChannelModuleBundle(auto featureFlags) {
196+
jsg::modules::ModuleBundle::BuiltinBuilder builder(
197+
jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN_ONLY);
198+
static const auto kSpecifier = "cloudflare-internal:messagechannel"_url;
199+
builder.addObject<MessageChannelModule, TypeWrapper>(kSpecifier);
200+
return builder.finish();
201+
}
202+
172203
} // namespace workerd::api
173204

174205
#define EW_MESSAGECHANNEL_ISOLATE_TYPES \
175-
api::MessagePort, api::MessageChannel, api::MessagePort::PostMessageOptions
206+
api::MessagePort, api::MessageChannel, api::MessagePort::PostMessageOptions, \
207+
api::MessageChannelModule

src/workerd/api/modules.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <workerd/api/base64.h>
88
#include <workerd/api/filesystem.h>
9+
#include <workerd/api/messagechannel.h>
910
#include <workerd/api/node/node.h>
1011
#include <workerd/api/pyodide/pyodide.h>
1112
#include <workerd/api/rtti.h>
@@ -87,6 +88,7 @@ void registerModules(Registry& registry, auto featureFlags) {
8788
}
8889
registerSocketsModule(registry, featureFlags);
8990
registerBase64Module(registry, featureFlags);
91+
registerMessageChannelModule(registry, featureFlags);
9092
registry.addBuiltinBundle(CLOUDFLARE_BUNDLE);
9193
registerWorkersModule(registry, featureFlags);
9294
registerTracingModule(registry, featureFlags);
@@ -102,6 +104,7 @@ void registerBuiltinModules(jsg::modules::ModuleRegistry::Builder& builder, auto
102104
builder.add(node::getExternalNodeJsCompatModuleBundle(featureFlags));
103105
builder.add(getInternalSocketModuleBundle<TypeWrapper>(featureFlags));
104106
builder.add(getInternalBase64ModuleBundle<TypeWrapper>(featureFlags));
107+
builder.add(getInternalMessageChannelModuleBundle<TypeWrapper>(featureFlags));
105108
builder.add(getInternalRpcModuleBundle<TypeWrapper>(featureFlags));
106109

107110
builder.add(getInternalUnsafeModuleBundle<TypeWrapper>(featureFlags));

src/workerd/api/node/tests/worker_threads-nodejs-test.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,13 @@ export const testWorkerProperties = {
125125

126126
export const testMessageChannelAndPort = {
127127
async test() {
128-
strictEqual(MessageChannel, globalThis.MessageChannel);
129-
strictEqual(MessagePort, globalThis.MessagePort);
128+
// Only check reference equality if the global MessageChannel is exposed.
129+
// The node:worker_threads module now imports from cloudflare-internal:messagechannel
130+
// so it works independently of the expose_global_message_channel compat flag.
131+
if (typeof globalThis.MessageChannel !== 'undefined') {
132+
strictEqual(MessageChannel, globalThis.MessageChannel);
133+
strictEqual(MessagePort, globalThis.MessagePort);
134+
}
130135

131136
const channel = new MessageChannel();
132137
ok(channel instanceof MessageChannel);

src/workerd/api/node/tests/worker_threads-nodejs-test.wd-test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const unitTests :Workerd.Config = (
77
modules = [
88
(name = "worker", esModule = embed "worker_threads-nodejs-test.js")
99
],
10-
compatibilityFlags = ["nodejs_compat", "nodejs_compat_v2", "enable_nodejs_worker_threads_module", "experimental", "global_navigator", "expose_global_message_channel"]
10+
compatibilityFlags = ["nodejs_compat", "nodejs_compat_v2", "enable_nodejs_worker_threads_module", "experimental", "global_navigator"]
1111
)
1212
),
1313
],

0 commit comments

Comments
 (0)