From 3372cb78978270ea9885893e0772c8a77f8d841e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20L=C3=B3pez?= Date: Thu, 5 May 2022 10:06:21 +0200 Subject: [PATCH] make @grafana/ui run properly in SSR environments (#46288) * allow SSR * fix rollup commonjs default flag changed breaking in SSR * revert wrong change * avoid using dynamic imports * fix test * allow icon load in packaged version * fix SelectBase to run on SSR * add extra check for fixing tests * revert wrong change * allow SSR * revert wrong change * don't include emotion in the bundle * fix wrong merge changes * remove unneeded icon change * use forked version of uplot * remove unneeded bundle exceptions * fix typescript issues * update to latest uplot --- packages/grafana-ui/rollup.config.ts | 3 +++ .../ClickOutsideWrapper/ClickOutsideWrapper.tsx | 2 +- packages/grafana-ui/src/components/Icon/iconBundle.ts | 2 +- .../JSONFormatter/json_explorer/json_explorer.ts | 2 +- packages/grafana-ui/src/components/Select/SelectBase.tsx | 2 +- packages/grafana-ui/src/utils/debug.ts | 8 +++++--- packages/grafana-ui/src/utils/dom.ts | 2 +- packages/grafana-ui/src/utils/measureText.ts | 9 +++++++-- 8 files changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/grafana-ui/rollup.config.ts b/packages/grafana-ui/rollup.config.ts index a19e76cb0eb..9a1d647c43c 100644 --- a/packages/grafana-ui/rollup.config.ts +++ b/packages/grafana-ui/rollup.config.ts @@ -35,10 +35,13 @@ const buildCjsPackage = ({ env }) => { 'moment', 'jquery', // required to use jquery.plot, which is assigned externally 'react-inlinesvg', // required to mock Icon svg loading in tests + '@emotion/react', + '@emotion/css', ], plugins: [ commonjs({ include: /node_modules/, + ignoreTryCatch: false, }), resolve(), svg({ stringify: true }), diff --git a/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx index e976629d1c6..12a22968f3a 100644 --- a/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx +++ b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx @@ -24,7 +24,7 @@ interface State { export class ClickOutsideWrapper extends PureComponent { static defaultProps = { includeButtonPress: true, - parent: window, + parent: typeof window !== 'undefined' ? window : null, useCapture: false, }; myRef = createRef(); diff --git a/packages/grafana-ui/src/components/Icon/iconBundle.ts b/packages/grafana-ui/src/components/Icon/iconBundle.ts index 88e9fb7c5ac..8bea9dba083 100644 --- a/packages/grafana-ui/src/components/Icon/iconBundle.ts +++ b/packages/grafana-ui/src/components/Icon/iconBundle.ts @@ -170,7 +170,7 @@ export function initIconCache() { // This function needs to be called after index.js loads to give the // application time to modify __webpack_public_path__ with a CDN path - const grafanaPublicPath = (window as any).__grafana_public_path__; + const grafanaPublicPath = typeof window !== 'undefined' && (window as any).__grafana_public_path__; if (grafanaPublicPath) { iconRoot = grafanaPublicPath + 'img/icons/'; } diff --git a/packages/grafana-ui/src/components/JSONFormatter/json_explorer/json_explorer.ts b/packages/grafana-ui/src/components/JSONFormatter/json_explorer/json_explorer.ts index c6eecd5da31..8deb06ed099 100644 --- a/packages/grafana-ui/src/components/JSONFormatter/json_explorer/json_explorer.ts +++ b/packages/grafana-ui/src/components/JSONFormatter/json_explorer/json_explorer.ts @@ -14,7 +14,7 @@ const JSON_DATE_REGEX = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/; const MAX_ANIMATED_TOGGLE_ITEMS = 10; const requestAnimationFrame = - window.requestAnimationFrame || + (typeof window !== 'undefined' && window.requestAnimationFrame) || ((cb: () => void) => { cb(); return 0; diff --git a/packages/grafana-ui/src/components/Select/SelectBase.tsx b/packages/grafana-ui/src/components/Select/SelectBase.tsx index 9bf6d40fadb..28a41837458 100644 --- a/packages/grafana-ui/src/components/Select/SelectBase.tsx +++ b/packages/grafana-ui/src/components/Select/SelectBase.tsx @@ -228,7 +228,7 @@ export function SelectBase({ menuPlacement: menuPlacement === 'auto' && closeToBottom ? 'top' : menuPlacement, menuPosition, menuShouldBlockScroll: true, - menuPortalTarget: menuShouldPortal ? document.body : undefined, + menuPortalTarget: menuShouldPortal && typeof document !== 'undefined' ? document.body : undefined, menuShouldScrollIntoView: false, onBlur, onChange: onChangeWithEmpty, diff --git a/packages/grafana-ui/src/utils/debug.ts b/packages/grafana-ui/src/utils/debug.ts index 4b60bb998bf..a4fdf99cb8c 100644 --- a/packages/grafana-ui/src/utils/debug.ts +++ b/packages/grafana-ui/src/utils/debug.ts @@ -15,8 +15,10 @@ export function attachDebugger(key: string, thebugger?: any, logger?: Logger) { } // @ts-ignore - let debugGlobal = window['_debug'] ?? {}; + let debugGlobal = (typeof window !== 'undefined' && window['_debug']) ?? {}; debugGlobal[key] = completeDebugger; - // @ts-ignore - window['_debug'] = debugGlobal; + if (typeof window !== 'undefined') { + // @ts-ignore + window['_debug'] = debugGlobal; + } } diff --git a/packages/grafana-ui/src/utils/dom.ts b/packages/grafana-ui/src/utils/dom.ts index c81d80af9d8..0b5e74fce22 100644 --- a/packages/grafana-ui/src/utils/dom.ts +++ b/packages/grafana-ui/src/utils/dom.ts @@ -1,5 +1,5 @@ // Node.closest() polyfill -if ('Element' in window && !Element.prototype.closest) { +if (typeof window !== 'undefined' && 'Element' in window && !Element.prototype.closest) { Element.prototype.closest = function (this: any, s: string) { const matches = (this.document || this.ownerDocument).querySelectorAll(s); let el = this; diff --git a/packages/grafana-ui/src/utils/measureText.ts b/packages/grafana-ui/src/utils/measureText.ts index caf76afb1de..321178967fa 100644 --- a/packages/grafana-ui/src/utils/measureText.ts +++ b/packages/grafana-ui/src/utils/measureText.ts @@ -1,4 +1,4 @@ -const context = document.createElement('canvas').getContext('2d')!; +let _context: CanvasRenderingContext2D; const cache = new Map(); const cacheLimit = 500; let ctxFontStyle = ''; @@ -7,7 +7,10 @@ let ctxFontStyle = ''; * @internal */ export function getCanvasContext() { - return context; + if (!_context) { + _context = document.createElement('canvas').getContext('2d')!; + } + return _context; } /** @@ -22,6 +25,8 @@ export function measureText(text: string, fontSize: number): TextMetrics { return fromCache; } + const context = getCanvasContext(); + if (ctxFontStyle !== fontStyle) { context.font = ctxFontStyle = fontStyle; }