Skip to content

Commit 976da3e

Browse files
committed
Warn if this argument is passed to .bind of a Server Reference
This won't ever be serialized and is likely just a mistake. This should be covered by the "use server" compiler since it ensures that something that accepts a "this" won't be allowed to compile and if it doesn't accept it, TypeScript should ideally forbid it to be passed.
1 parent c1fd2a9 commit 976da3e

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

packages/react-client/src/ReactFlightReplyClient.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,17 @@ function bind(this: Function): Function {
635635
const newFn = FunctionBind.apply(this, arguments);
636636
const reference = knownServerReferences.get(this);
637637
if (reference) {
638+
if (__DEV__) {
639+
const thisBind = arguments[0];
640+
if (thisBind != null) {
641+
// This doesn't warn in browser environments since it's not instrumented outside
642+
// usedWithSSR. This makes this an SSR only warning which we don't generally do.
643+
// TODO: Consider a DEV only instrumentation in the browser.
644+
console.error(
645+
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
646+
);
647+
}
648+
}
638649
const args = ArraySlice.call(arguments, 1);
639650
let boundPromise = null;
640651
if (reference.bound !== null) {

packages/react-server-dom-webpack/src/ReactFlightWebpackReferences.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ function bind(this: ServerReference<any>): any {
6565
// $FlowFixMe[unsupported-syntax]
6666
const newFn = FunctionBind.apply(this, arguments);
6767
if (this.$$typeof === SERVER_REFERENCE_TAG) {
68+
if (__DEV__) {
69+
const thisBind = arguments[0];
70+
if (thisBind != null) {
71+
console.error(
72+
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
73+
);
74+
}
75+
}
6876
const args = ArraySlice.call(arguments, 1);
6977
return Object.defineProperties((newFn: any), {
7078
$$typeof: {value: SERVER_REFERENCE_TAG},

packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ global.TextDecoder = require('util').TextDecoder;
1919
// TODO: we can replace this with FlightServer.act().
2020
global.setTimeout = cb => cb();
2121

22+
let serverExports;
2223
let clientExports;
2324
let webpackMap;
2425
let webpackModules;
@@ -41,6 +42,7 @@ describe('ReactFlightDOMEdge', () => {
4142

4243
const WebpackMock = require('./utils/WebpackMock');
4344

45+
serverExports = WebpackMock.serverExports;
4446
clientExports = WebpackMock.clientExports;
4547
webpackMap = WebpackMock.webpackMap;
4648
webpackModules = WebpackMock.webpackModules;
@@ -323,4 +325,31 @@ describe('ReactFlightDOMEdge', () => {
323325
});
324326
expect(result).toEqual(buffers);
325327
});
328+
329+
it('warns if passing a this argument to bind() of a server reference', async () => {
330+
const ServerModule = serverExports({
331+
greet: function () {},
332+
});
333+
334+
const ServerModuleImportedOnClient = {
335+
greet: ReactServerDOMClient.createServerReference(
336+
ServerModule.greet.$$id,
337+
async function (ref, args) {},
338+
),
339+
};
340+
341+
expect(() => {
342+
ServerModule.greet.bind({}, 'hi');
343+
}).toErrorDev(
344+
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
345+
{withoutStack: true},
346+
);
347+
348+
expect(() => {
349+
ServerModuleImportedOnClient.greet.bind({}, 'hi');
350+
}).toErrorDev(
351+
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
352+
{withoutStack: true},
353+
);
354+
});
326355
});

0 commit comments

Comments
 (0)