From 508256d02832f639c1937e4e3435a4b6ee23c1f3 Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Mon, 4 Mar 2019 09:16:52 -0800 Subject: [PATCH] Always load NodeHttpClient to fix SSR (#8047) --- .../ts/signalr/src/DefaultHttpClient.ts | 13 ++---------- .../ts/signalr/src/EmptyNodeHttpClient.ts | 18 ++++++++++++++++ .../clients/ts/signalr/src/NodeHttpClient.ts | 21 +++++++++++++++---- src/SignalR/clients/ts/webpack.config.base.js | 6 ++++-- 4 files changed, 41 insertions(+), 17 deletions(-) create mode 100644 src/SignalR/clients/ts/signalr/src/EmptyNodeHttpClient.ts diff --git a/src/SignalR/clients/ts/signalr/src/DefaultHttpClient.ts b/src/SignalR/clients/ts/signalr/src/DefaultHttpClient.ts index b1f19d401f..732705e76f 100644 --- a/src/SignalR/clients/ts/signalr/src/DefaultHttpClient.ts +++ b/src/SignalR/clients/ts/signalr/src/DefaultHttpClient.ts @@ -4,16 +4,9 @@ import { AbortError } from "./Errors"; import { HttpClient, HttpRequest, HttpResponse } from "./HttpClient"; import { ILogger } from "./ILogger"; +import { NodeHttpClient } from "./NodeHttpClient"; import { XhrHttpClient } from "./XhrHttpClient"; -let nodeHttpClientModule: any; -if (typeof XMLHttpRequest === "undefined") { - // In order to ignore the dynamic require in webpack builds we need to do this magic - // @ts-ignore: TS doesn't know about these names - const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require; - nodeHttpClientModule = requireFunc("./NodeHttpClient"); -} - /** Default implementation of {@link @aspnet/signalr.HttpClient}. */ export class DefaultHttpClient extends HttpClient { private readonly httpClient: HttpClient; @@ -24,10 +17,8 @@ export class DefaultHttpClient extends HttpClient { if (typeof XMLHttpRequest !== "undefined") { this.httpClient = new XhrHttpClient(logger); - } else if (typeof nodeHttpClientModule !== "undefined") { - this.httpClient = new nodeHttpClientModule.NodeHttpClient(logger); } else { - throw new Error("No HttpClient could be created."); + this.httpClient = new NodeHttpClient(logger); } } diff --git a/src/SignalR/clients/ts/signalr/src/EmptyNodeHttpClient.ts b/src/SignalR/clients/ts/signalr/src/EmptyNodeHttpClient.ts new file mode 100644 index 0000000000..c756727cb0 --- /dev/null +++ b/src/SignalR/clients/ts/signalr/src/EmptyNodeHttpClient.ts @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +// This is an empty implementation of the NodeHttpClient that will be included in browser builds so the output file will be smaller + +import { HttpClient, HttpResponse } from "./HttpClient"; +import { ILogger } from "./ILogger"; + +export class NodeHttpClient extends HttpClient { + // @ts-ignore: Need ILogger to compile, but unused variables generate errors + public constructor(logger: ILogger) { + super(); + } + + public send(): Promise { + return Promise.reject(new Error("If using Node either provide an XmlHttpRequest polyfill or consume the cjs or esm script instead of the browser/signalr.js one.")); + } +} diff --git a/src/SignalR/clients/ts/signalr/src/NodeHttpClient.ts b/src/SignalR/clients/ts/signalr/src/NodeHttpClient.ts index bd9f1da86b..45750d4816 100644 --- a/src/SignalR/clients/ts/signalr/src/NodeHttpClient.ts +++ b/src/SignalR/clients/ts/signalr/src/NodeHttpClient.ts @@ -1,23 +1,36 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import * as Request from "request"; +// @ts-ignore: This will be removed from built files and is here to make the types available during dev work +import * as Request from "@types/request"; import { AbortError, HttpError, TimeoutError } from "./Errors"; import { HttpClient, HttpRequest, HttpResponse } from "./HttpClient"; import { ILogger, LogLevel } from "./ILogger"; import { isArrayBuffer } from "./Utils"; +let requestModule: Request.RequestAPI; +if (typeof XMLHttpRequest === "undefined") { + // In order to ignore the dynamic require in webpack builds we need to do this magic + // @ts-ignore: TS doesn't know about these names + const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require; + requestModule = requireFunc("request"); +} + export class NodeHttpClient extends HttpClient { private readonly logger: ILogger; - private readonly request: Request.RequestAPI; + private readonly request: typeof requestModule; private readonly cookieJar: Request.CookieJar; public constructor(logger: ILogger) { super(); + if (typeof requestModule === "undefined") { + throw new Error("The 'request' module could not be loaded."); + } + this.logger = logger; - this.cookieJar = Request.jar(); - this.request = Request.defaults({ jar: this.cookieJar }); + this.cookieJar = requestModule.jar(); + this.request = requestModule.defaults({ jar: this.cookieJar }); } public send(httpRequest: HttpRequest): Promise { diff --git a/src/SignalR/clients/ts/webpack.config.base.js b/src/SignalR/clients/ts/webpack.config.base.js index 8c8f3ac31f..57ac83c6a9 100644 --- a/src/SignalR/clients/ts/webpack.config.base.js +++ b/src/SignalR/clients/ts/webpack.config.base.js @@ -40,7 +40,10 @@ module.exports = function (modulePath, browserBaseName, options) { }, resolve: { extensions: [".ts", ".js"], - alias: options.alias, + alias: { + "./NodeHttpClient": path.resolve(__dirname, "signalr/src/EmptyNodeHttpClient.ts"), + ...options.alias, + } }, output: { filename: `${browserBaseName}.js`, @@ -73,7 +76,6 @@ module.exports = function (modulePath, browserBaseName, options) { }), // ES6 Promise uses this module in certain circumstances but we don't need it. new webpack.IgnorePlugin(/vertx/), - new webpack.IgnorePlugin(/NodeHttpClient/), new webpack.IgnorePlugin(/eventsource/), ], externals: options.externals,