From ef0aece367a7bf657695ceee030a75cff3f4d2b9 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Wed, 18 Jan 2023 13:59:14 +0100 Subject: [PATCH 1/8] helper for window object --- src/utils/browser.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/utils/browser.ts diff --git a/src/utils/browser.ts b/src/utils/browser.ts new file mode 100644 index 000000000..d2fcb3689 --- /dev/null +++ b/src/utils/browser.ts @@ -0,0 +1,30 @@ +export function getBrowserWindow() { + let windowObject; + + try { + windowObject ||= globalThis.window; + } catch { + // do nothing + } + + try { + windowObject ||= global.window; + } catch { + // do nothing + } + + try { + windowObject ||= window; + } catch { + // do nothing + } + + return windowObject; +} + +export function isBrowser() { + const window = getBrowserWindow() + + return window !== undefined + && typeof window === 'object'; +} \ No newline at end of file From 5c9e830107f0fe88f713ad7dc5fffec5cccbb3e8 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Wed, 18 Jan 2023 14:17:05 +0100 Subject: [PATCH 2/8] add a helper to know if we are inside of a browser or not --- index.ts | 4 +++- src/protocols/abstract/Realtime.ts | 10 +++++----- src/utils/browser.ts | 15 +++++++++++---- src/utils/debug.js | 9 ++++++--- test/mocks/window.mock.js | 7 ++++--- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/index.ts b/index.ts index 12c30507a..b26814f02 100644 --- a/index.ts +++ b/index.ts @@ -1,7 +1,9 @@ +import { isBrowser } from 'src/utils/browser'; + // defined by webpack plugin declare var BUILT: any; -if (typeof window !== 'undefined' && typeof BUILT === 'undefined') { +if (isBrowser() && typeof BUILT === 'undefined') { throw new Error('It looks like you are using the Nodejs version of Kuzzle SDK ' + 'in a browser. ' + 'It is strongly recommended to use the browser-specific build instead. ' + diff --git a/src/protocols/abstract/Realtime.ts b/src/protocols/abstract/Realtime.ts index 929976568..807bc4e38 100644 --- a/src/protocols/abstract/Realtime.ts +++ b/src/protocols/abstract/Realtime.ts @@ -2,6 +2,7 @@ import { KuzzleAbstractProtocol } from "./Base"; import * as DisconnectionOrigin from "../DisconnectionOrigin"; +import { getBrowserWindow, isBrowser } from "src/utils/browser"; export abstract class BaseProtocolRealtime extends KuzzleAbstractProtocol { protected _reconnectionDelay: number; @@ -83,12 +84,11 @@ export abstract class BaseProtocolRealtime extends KuzzleAbstractProtocol { this.retrying = true; if ( - window !== null && - typeof window === "object" && - typeof window!.navigator === "object" && - window!.navigator.onLine === false + isBrowser() && + typeof getBrowserWindow()!.navigator === "object" && + getBrowserWindow()!.navigator.onLine === false ) { - window!.addEventListener( + getBrowserWindow()!.addEventListener( "online", () => { this.retrying = false; diff --git a/src/utils/browser.ts b/src/utils/browser.ts index d2fcb3689..f7a2cae23 100644 --- a/src/utils/browser.ts +++ b/src/utils/browser.ts @@ -1,6 +1,12 @@ -export function getBrowserWindow() { - let windowObject; - +let windowObject: Window | undefined; + +let cachedWindowObject = false; + +export function getBrowserWindow(): Window | undefined { + if (cachedWindowObject) { + return windowObject; + } + try { windowObject ||= globalThis.window; } catch { @@ -19,10 +25,11 @@ export function getBrowserWindow() { // do nothing } + cachedWindowObject = true; return windowObject; } -export function isBrowser() { +export function isBrowser(): boolean { const window = getBrowserWindow() return window !== undefined diff --git a/src/utils/debug.js b/src/utils/debug.js index cb504a59a..2e3845f28 100644 --- a/src/utils/debug.js +++ b/src/utils/debug.js @@ -1,5 +1,7 @@ let NODE_DEBUG; +const { isBrowser, getBrowserWindow } = require("./browser"); + /* eslint no-undef: 0 */ function shouldDebug() { @@ -13,7 +15,7 @@ function shouldDebug() { * If something went wrong, be sure to return false to avoid any error. */ try { - if (typeof window === "undefined") { + if (!isBrowser()) { // Avoid multiple calls to process.env if (!NODE_DEBUG) { NODE_DEBUG = (process.env.DEBUG || "").includes("kuzzle-sdk"); @@ -21,7 +23,8 @@ function shouldDebug() { return NODE_DEBUG; } - + + const window = getBrowserWindow(); return ( window.debugKuzzleSdk || (window.location && @@ -49,7 +52,7 @@ function debug(message, obj) { if (obj) { // Browser console can print directly objects - const toPrint = typeof window === "undefined" ? JSON.stringify(obj) : obj; + const toPrint = isBrowser() ? JSON.stringify(obj) : obj; // eslint-disable-next-line no-console console.log(toPrint); diff --git a/test/mocks/window.mock.js b/test/mocks/window.mock.js index 0aef3f625..7a285f7b5 100644 --- a/test/mocks/window.mock.js +++ b/test/mocks/window.mock.js @@ -1,12 +1,13 @@ const sinon = require("sinon"), { KuzzleEventEmitter } = require("../../src/core/KuzzleEventEmitter"); +const { getBrowserWindow } = require("../../src/utils/browser"); // A class to mock the global window object class WindowMock extends KuzzleEventEmitter { constructor() { super(); - if (typeof window !== "undefined") { + if (typeof getBrowserWindow() !== "undefined") { throw new Error( 'Cannot mock add a global "window" object: already defined' ); @@ -21,11 +22,11 @@ class WindowMock extends KuzzleEventEmitter { } static restore() { - delete global.window; + delete getBrowserWindow().window; } static inject() { - Object.defineProperty(global, "window", { + Object.defineProperty(getBrowserWindow(), "window", { value: new this(), enumerable: false, writable: false, From f42f9c571717e8c584c178abab78e7376f9b7619 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Wed, 18 Jan 2023 14:37:54 +0100 Subject: [PATCH 3/8] lint --- src/protocols/abstract/Realtime.ts | 7 ++++--- src/utils/browser.ts | 7 +++---- src/utils/debug.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/protocols/abstract/Realtime.ts b/src/protocols/abstract/Realtime.ts index 807bc4e38..775349298 100644 --- a/src/protocols/abstract/Realtime.ts +++ b/src/protocols/abstract/Realtime.ts @@ -83,12 +83,13 @@ export abstract class BaseProtocolRealtime extends KuzzleAbstractProtocol { if (this.autoReconnect && !this.retrying && !this.stopRetryingToConnect) { this.retrying = true; + const window = getBrowserWindow(); if ( isBrowser() && - typeof getBrowserWindow()!.navigator === "object" && - getBrowserWindow()!.navigator.onLine === false + typeof window.navigator === "object" && + window.navigator.onLine === false ) { - getBrowserWindow()!.addEventListener( + window.addEventListener( "online", () => { this.retrying = false; diff --git a/src/utils/browser.ts b/src/utils/browser.ts index f7a2cae23..9a1cd263c 100644 --- a/src/utils/browser.ts +++ b/src/utils/browser.ts @@ -30,8 +30,7 @@ export function getBrowserWindow(): Window | undefined { } export function isBrowser(): boolean { - const window = getBrowserWindow() + const window = getBrowserWindow(); - return window !== undefined - && typeof window === 'object'; -} \ No newline at end of file + return window !== undefined && window !== null && typeof window === "object"; +} diff --git a/src/utils/debug.js b/src/utils/debug.js index 2e3845f28..3ebbe6db6 100644 --- a/src/utils/debug.js +++ b/src/utils/debug.js @@ -23,7 +23,7 @@ function shouldDebug() { return NODE_DEBUG; } - + const window = getBrowserWindow(); return ( window.debugKuzzleSdk || From aa29cc1d3be9d8a2ea472b81922050309f510f72 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Wed, 18 Jan 2023 14:51:43 +0100 Subject: [PATCH 4/8] fix import --- src/protocols/abstract/Realtime.ts | 2 +- test/mocks/window.mock.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/abstract/Realtime.ts b/src/protocols/abstract/Realtime.ts index 775349298..9911f516a 100644 --- a/src/protocols/abstract/Realtime.ts +++ b/src/protocols/abstract/Realtime.ts @@ -2,7 +2,7 @@ import { KuzzleAbstractProtocol } from "./Base"; import * as DisconnectionOrigin from "../DisconnectionOrigin"; -import { getBrowserWindow, isBrowser } from "src/utils/browser"; +import { getBrowserWindow, isBrowser } from "../../utils/browser"; export abstract class BaseProtocolRealtime extends KuzzleAbstractProtocol { protected _reconnectionDelay: number; diff --git a/test/mocks/window.mock.js b/test/mocks/window.mock.js index 7a285f7b5..d4967f020 100644 --- a/test/mocks/window.mock.js +++ b/test/mocks/window.mock.js @@ -22,11 +22,11 @@ class WindowMock extends KuzzleEventEmitter { } static restore() { - delete getBrowserWindow().window; + delete global.window; } static inject() { - Object.defineProperty(getBrowserWindow(), "window", { + Object.defineProperty(global, "window", { value: new this(), enumerable: false, writable: false, From 3ba9ad84c21ae3a4a7a8bbccf3a48043f3e63dc3 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Wed, 18 Jan 2023 14:54:19 +0100 Subject: [PATCH 5/8] fix inverted check --- src/utils/debug.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/debug.js b/src/utils/debug.js index 3ebbe6db6..7e1116634 100644 --- a/src/utils/debug.js +++ b/src/utils/debug.js @@ -52,7 +52,7 @@ function debug(message, obj) { if (obj) { // Browser console can print directly objects - const toPrint = isBrowser() ? JSON.stringify(obj) : obj; + const toPrint = !isBrowser() ? JSON.stringify(obj) : obj; // eslint-disable-next-line no-console console.log(toPrint); From 94f8e3399d10826c82e3fe163f4548d30bb49967 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Wed, 18 Jan 2023 14:57:09 +0100 Subject: [PATCH 6/8] fix test --- src/utils/browser.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/utils/browser.ts b/src/utils/browser.ts index 9a1cd263c..db8695f60 100644 --- a/src/utils/browser.ts +++ b/src/utils/browser.ts @@ -1,32 +1,32 @@ -let windowObject: Window | undefined; - -let cachedWindowObject = false; - export function getBrowserWindow(): Window | undefined { - if (cachedWindowObject) { - return windowObject; - } + let windowObject: Window | undefined; try { windowObject ||= globalThis.window; + if (windowObject) { + return windowObject; + } } catch { - // do nothing + // Check next variable } try { windowObject ||= global.window; + if (windowObject) { + return windowObject; + } } catch { - // do nothing + // Check next variable } try { windowObject ||= window; + if (windowObject) { + return windowObject; + } } catch { - // do nothing + // return undefined } - - cachedWindowObject = true; - return windowObject; } export function isBrowser(): boolean { From 01781795487c18456f5357cc5143dc82db38ada9 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Wed, 18 Jan 2023 15:02:00 +0100 Subject: [PATCH 7/8] fix test --- test/mocks/window.mock.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/mocks/window.mock.js b/test/mocks/window.mock.js index d4967f020..0aef3f625 100644 --- a/test/mocks/window.mock.js +++ b/test/mocks/window.mock.js @@ -1,13 +1,12 @@ const sinon = require("sinon"), { KuzzleEventEmitter } = require("../../src/core/KuzzleEventEmitter"); -const { getBrowserWindow } = require("../../src/utils/browser"); // A class to mock the global window object class WindowMock extends KuzzleEventEmitter { constructor() { super(); - if (typeof getBrowserWindow() !== "undefined") { + if (typeof window !== "undefined") { throw new Error( 'Cannot mock add a global "window" object: already defined' ); From c2ad8ca8caad0588860b875882206040353db65c Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Wed, 18 Jan 2023 15:06:41 +0100 Subject: [PATCH 8/8] F U --- index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.ts b/index.ts index b26814f02..8cd3c1731 100644 --- a/index.ts +++ b/index.ts @@ -1,4 +1,4 @@ -import { isBrowser } from 'src/utils/browser'; +import { isBrowser } from './src/utils/browser'; // defined by webpack plugin declare var BUILT: any;