Skip to content

Commit 56d50e6

Browse files
authored
Fix SSR issues for SignalR: require is not defined (#19832)
1 parent 44230d3 commit 56d50e6

File tree

2 files changed

+44
-42
lines changed

2 files changed

+44
-42
lines changed

src/SignalR/clients/ts/signalr/src/FetchHttpClient.ts

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,36 @@ import { HttpClient, HttpRequest, HttpResponse } from "./HttpClient";
99
import { ILogger, LogLevel } from "./ILogger";
1010
import { Platform } from "./Utils";
1111

12-
let abortControllerType: { prototype: AbortController, new(): AbortController };
13-
let fetchType: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
14-
let jar: tough.CookieJar;
15-
if (typeof fetch === "undefined") {
16-
// In order to ignore the dynamic require in webpack builds we need to do this magic
17-
// @ts-ignore: TS doesn't know about these names
18-
const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
19-
20-
// Cookies aren't automatically handled in Node so we need to add a CookieJar to preserve cookies across requests
21-
jar = new (requireFunc("tough-cookie")).CookieJar();
22-
fetchType = requireFunc("node-fetch");
23-
24-
// node-fetch doesn't have a nice API for getting and setting cookies
25-
// fetch-cookie will wrap a fetch implementation with a default CookieJar or a provided one
26-
fetchType = requireFunc("fetch-cookie")(fetchType, jar);
27-
28-
// Node needs EventListener methods on AbortController which our custom polyfill doesn't provide
29-
abortControllerType = requireFunc("abort-controller");
30-
} else {
31-
fetchType = fetch;
32-
abortControllerType = AbortController;
33-
}
34-
3512
export class FetchHttpClient extends HttpClient {
13+
private readonly abortControllerType: { prototype: AbortController, new(): AbortController };
14+
private readonly fetchType: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
15+
private readonly jar?: tough.CookieJar;
16+
3617
private readonly logger: ILogger;
3718

3819
public constructor(logger: ILogger) {
3920
super();
4021
this.logger = logger;
22+
23+
if (typeof fetch === "undefined") {
24+
// In order to ignore the dynamic require in webpack builds we need to do this magic
25+
// @ts-ignore: TS doesn't know about these names
26+
const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
27+
28+
// Cookies aren't automatically handled in Node so we need to add a CookieJar to preserve cookies across requests
29+
this.jar = new (requireFunc("tough-cookie")).CookieJar();
30+
this.fetchType = requireFunc("node-fetch");
31+
32+
// node-fetch doesn't have a nice API for getting and setting cookies
33+
// fetch-cookie will wrap a fetch implementation with a default CookieJar or a provided one
34+
this.fetchType = requireFunc("fetch-cookie")(this.fetchType, this.jar);
35+
36+
// Node needs EventListener methods on AbortController which our custom polyfill doesn't provide
37+
this.abortControllerType = requireFunc("abort-controller");
38+
} else {
39+
this.fetchType = fetch.bind(self);
40+
this.abortControllerType = AbortController;
41+
}
4142
}
4243

4344
/** @inheritDoc */
@@ -54,7 +55,7 @@ export class FetchHttpClient extends HttpClient {
5455
throw new Error("No url defined.");
5556
}
5657

57-
const abortController = new abortControllerType();
58+
const abortController = new this.abortControllerType();
5859

5960
let error: any;
6061
// Hook our abortSignal into the abort controller
@@ -79,7 +80,7 @@ export class FetchHttpClient extends HttpClient {
7980

8081
let response: Response;
8182
try {
82-
response = await fetchType(request.url!, {
83+
response = await this.fetchType(request.url!, {
8384
body: request.content!,
8485
cache: "no-cache",
8586
credentials: request.withCredentials === true ? "include" : "same-origin",
@@ -127,9 +128,9 @@ export class FetchHttpClient extends HttpClient {
127128

128129
public getCookieString(url: string): string {
129130
let cookies: string = "";
130-
if (Platform.isNode) {
131+
if (Platform.isNode && this.jar) {
131132
// @ts-ignore: unused variable
132-
jar.getCookies(url, (e, c) => cookies = c.join("; "));
133+
this.jar.getCookies(url, (e, c) => cookies = c.join("; "));
133134
}
134135
return cookies;
135136
}

src/SignalR/clients/ts/signalr/src/HttpConnection.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { WebSocketTransport } from "./WebSocketTransport";
1414

1515
/** @private */
1616
const enum ConnectionState {
17-
Connecting = "Connecting ",
17+
Connecting = "Connecting",
1818
Connected = "Connected",
1919
Disconnected = "Disconnected",
2020
Disconnecting = "Disconnecting",
@@ -39,16 +39,6 @@ export interface IAvailableTransport {
3939

4040
const MAX_REDIRECTS = 100;
4141

42-
let WebSocketModule: any = null;
43-
let EventSourceModule: any = null;
44-
if (Platform.isNode && typeof require !== "undefined") {
45-
// In order to ignore the dynamic require in webpack builds we need to do this magic
46-
// @ts-ignore: TS doesn't know about these names
47-
const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
48-
WebSocketModule = requireFunc("ws");
49-
EventSourceModule = requireFunc("eventsource");
50-
}
51-
5242
/** @private */
5343
export class HttpConnection implements IConnection {
5444
private connectionState: ConnectionState;
@@ -88,19 +78,30 @@ export class HttpConnection implements IConnection {
8878
throw new Error("withCredentials option was not a 'boolean' or 'undefined' value");
8979
}
9080

81+
let webSocketModule: any = null;
82+
let eventSourceModule: any = null;
83+
84+
if (Platform.isNode && typeof require !== "undefined") {
85+
// In order to ignore the dynamic require in webpack builds we need to do this magic
86+
// @ts-ignore: TS doesn't know about these names
87+
const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
88+
webSocketModule = requireFunc("ws");
89+
eventSourceModule = requireFunc("eventsource");
90+
}
91+
9192
if (!Platform.isNode && typeof WebSocket !== "undefined" && !options.WebSocket) {
9293
options.WebSocket = WebSocket;
9394
} else if (Platform.isNode && !options.WebSocket) {
94-
if (WebSocketModule) {
95-
options.WebSocket = WebSocketModule;
95+
if (webSocketModule) {
96+
options.WebSocket = webSocketModule;
9697
}
9798
}
9899

99100
if (!Platform.isNode && typeof EventSource !== "undefined" && !options.EventSource) {
100101
options.EventSource = EventSource;
101102
} else if (Platform.isNode && !options.EventSource) {
102-
if (typeof EventSourceModule !== "undefined") {
103-
options.EventSource = EventSourceModule;
103+
if (typeof eventSourceModule !== "undefined") {
104+
options.EventSource = eventSourceModule;
104105
}
105106
}
106107

0 commit comments

Comments
 (0)