diff --git a/node_package/src/Authenticity.ts b/node_package/src/Authenticity.ts index ec1dea86a4..82c7484aed 100644 --- a/node_package/src/Authenticity.ts +++ b/node_package/src/Authenticity.ts @@ -3,7 +3,7 @@ import type { AuthenticityHeaders } from './types/index'; export default { authenticityToken(): string | null { const token = document.querySelector('meta[name="csrf-token"]'); - if (token && (token instanceof window.HTMLMetaElement)) { + if (token instanceof HTMLMetaElement) { return token.content; } return null; diff --git a/node_package/src/ComponentRegistry.ts b/node_package/src/ComponentRegistry.ts index 943abde8a4..a8f42dd278 100644 --- a/node_package/src/ComponentRegistry.ts +++ b/node_package/src/ComponentRegistry.ts @@ -1,7 +1,7 @@ import type { RegisteredComponent, ReactComponentOrRenderFunction, RenderFunction } from './types/index'; import isRenderFunction from './isRenderFunction'; -const registeredComponents = new Map(); +const registeredComponents = new Map(); export default { /** @@ -35,8 +35,9 @@ export default { * @returns { name, component, isRenderFunction, isRenderer } */ get(name: string): RegisteredComponent { - if (registeredComponents.has(name)) { - return registeredComponents.get(name); + const registeredComponent = registeredComponents.get(name); + if (registeredComponent !== undefined) { + return registeredComponent; } const keys = Array.from(registeredComponents.keys()).join(', '); diff --git a/node_package/src/StoreRegistry.ts b/node_package/src/StoreRegistry.ts index 92fa4db336..a51e788c0f 100644 --- a/node_package/src/StoreRegistry.ts +++ b/node_package/src/StoreRegistry.ts @@ -3,8 +3,8 @@ import type { StoreGenerator } from './types'; /* eslint-disable @typescript-eslint/no-explicit-any */ type Store = any; -const registeredStoreGenerators = new Map(); -const hydratedStores = new Map(); +const registeredStoreGenerators = new Map(); +const hydratedStores = new Map(); export default { /** @@ -66,8 +66,9 @@ This can happen if you are server rendering and either: * @returns storeCreator with given name */ getStoreGenerator(name: string): StoreGenerator { - if (registeredStoreGenerators.has(name)) { - return registeredStoreGenerators.get(name); + const registeredStoreGenerator = registeredStoreGenerators.get(name); + if (registeredStoreGenerator) { + return registeredStoreGenerator; } const storeKeys = Array.from(registeredStoreGenerators.keys()).join(', '); diff --git a/node_package/src/buildConsoleReplay.ts b/node_package/src/buildConsoleReplay.ts index 38436467d5..6a199e25d5 100644 --- a/node_package/src/buildConsoleReplay.ts +++ b/node_package/src/buildConsoleReplay.ts @@ -1,8 +1,6 @@ import RenderUtils from './RenderUtils'; import scriptSanitizedVal from './scriptSanitizedVal'; -/* eslint-disable @typescript-eslint/no-explicit-any */ - declare global { interface Console { history?: { @@ -13,24 +11,26 @@ declare global { export function consoleReplay(): string { // console.history is a global polyfill used in server rendering. - // $FlowFixMe if (!(console.history instanceof Array)) { return ''; } const lines = console.history.map(msg => { const stringifiedList = msg.arguments.map(arg => { - let val; + let val: string | undefined; try { - val = (typeof arg === 'string' || arg instanceof String) ? arg : JSON.stringify(arg); + // eslint-disable-next-line no-nested-ternary + val = typeof arg === 'string' ? arg : + arg instanceof String ? String(arg) : + JSON.stringify(arg); if (val === undefined) { val = 'undefined'; } - } catch (e: any) { - val = `${e.message}: ${arg}`; + } catch (e) { + val = `${(e as Error).message}: ${arg}`; } - return scriptSanitizedVal(val as string); + return scriptSanitizedVal(val); }); return `console.${msg.level}.apply(console, ${JSON.stringify(stringifiedList)});`; diff --git a/node_package/src/handleError.ts b/node_package/src/handleError.ts index 4c99d57fa3..c52628e5f0 100644 --- a/node_package/src/handleError.ts +++ b/node_package/src/handleError.ts @@ -2,7 +2,7 @@ import React from 'react'; import ReactDOMServer from 'react-dom/server'; import type { ErrorOptions } from './types/index'; -function handleRenderFunctionIssue(options: {e: Error; name?: string}): string { +function handleRenderFunctionIssue(options: ErrorOptions): string { const { e, name } = options; let msg = ''; diff --git a/node_package/src/isRenderFunction.ts b/node_package/src/isRenderFunction.ts index 217c7731e0..21c011fb76 100644 --- a/node_package/src/isRenderFunction.ts +++ b/node_package/src/isRenderFunction.ts @@ -8,11 +8,9 @@ import { ReactComponentOrRenderFunction, RenderFunction } from "./types/index"; * @param component * @returns {boolean} */ -export default function isRenderFunction(component: ReactComponentOrRenderFunction): boolean { +export default function isRenderFunction(component: ReactComponentOrRenderFunction): component is RenderFunction { // No for es5 or es6 React Component - if ( - (component as RenderFunction).prototype && - (component as RenderFunction).prototype.isReactComponent) { + if ((component as RenderFunction).prototype?.isReactComponent) { return false; } @@ -22,7 +20,7 @@ export default function isRenderFunction(component: ReactComponentOrRenderFuncti // If zero or one args, then we know that this is a regular function that will // return a React component - if (component.length >= 2) { + if ((component as RenderFunction).length >= 2) { return true; } diff --git a/node_package/src/serverRenderReactComponent.ts b/node_package/src/serverRenderReactComponent.ts index 422b430c2b..08b618a214 100644 --- a/node_package/src/serverRenderReactComponent.ts +++ b/node_package/src/serverRenderReactComponent.ts @@ -3,11 +3,10 @@ import type { ReactElement } from 'react'; import ComponentRegistry from './ComponentRegistry'; import createReactOutput from './createReactOutput'; -import {isServerRenderHash, isPromise} from - './isServerRenderResult'; +import { isPromise, isServerRenderHash } from './isServerRenderResult'; import buildConsoleReplay from './buildConsoleReplay'; import handleError from './handleError'; -import type { RenderParams, RenderResult, RenderingError } from './types/index'; +import type { RenderParams, RenderResult, RenderingError, ServerRenderResult } from './types'; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -35,37 +34,37 @@ See https://github.com/shakacode/react_on_rails#renderer-functions`); }); const processServerRenderHash = () => { - // We let the client side handle any redirect - // Set hasErrors in case we want to throw a Rails exception - hasErrors = !!(reactRenderingResult as {routeError: Error}).routeError; - - if (hasErrors) { - console.error( - `React Router ERROR: ${JSON.stringify((reactRenderingResult as {routeError: Error}).routeError)}`, - ); - } + // We let the client side handle any redirect + // Set hasErrors in case we want to throw a Rails exception + const { redirectLocation, routeError } = reactRenderingResult as ServerRenderResult; + hasErrors = !!routeError; + + if (hasErrors) { + console.error( + `React Router ERROR: ${JSON.stringify(routeError)}`, + ); + } - if ((reactRenderingResult as {redirectLocation: {pathname: string; search: string}}).redirectLocation) { - if (trace) { - const { redirectLocation } = (reactRenderingResult as {redirectLocation: {pathname: string; search: string}}); - const redirectPath = redirectLocation.pathname + redirectLocation.search; - console.log(`\ + if (redirectLocation) { + if (trace) { + const redirectPath = redirectLocation.pathname + redirectLocation.search; + console.log(`\ ROUTER REDIRECT: ${name} to dom node with id: ${domNodeId}, redirect to ${redirectPath}`, - ); - } - // For redirects on server rendering, we can't stop Rails from returning the same result. - // Possibly, someday, we could have the rails server redirect. - return ''; + ); } - return (reactRenderingResult as { renderedHtml: string }).renderedHtml; + // For redirects on server rendering, we can't stop Rails from returning the same result. + // Possibly, someday, we could have the rails server redirect. + return ''; + } + return (reactRenderingResult as ServerRenderResult).renderedHtml as string; }; const processPromise = () => { if (!renderingReturnsPromises) { - console.error('Your render function returned a Promise, which is only supported by a node renderer, not ExecJS.') + console.error('Your render function returned a Promise, which is only supported by a node renderer, not ExecJS.'); } return reactRenderingResult; - } + }; const processReactElement = () => { try { @@ -105,11 +104,11 @@ as a renderFunction and not a simple React Function Component.`); message: renderError.message, stack: renderError.stack, }; - } + }; - if(renderingReturnsPromises) { + if (renderingReturnsPromises) { const resolveRenderResult = async () => { - let promiseResult; + let promiseResult: RenderResult; try { promiseResult = { @@ -129,7 +128,7 @@ as a renderFunction and not a simple React Function Component.`); }), consoleReplayScript, hasErrors: true, - } + }; renderingError = e; } @@ -143,11 +142,11 @@ as a renderFunction and not a simple React Function Component.`); return resolveRenderResult(); } - const result = { - html: renderResult, + const result: RenderResult = { + html: await renderResult, consoleReplayScript, hasErrors, - } as RenderResult; + }; if (renderingError) { addRenderingErrors(result, renderingError); diff --git a/node_package/src/types/index.ts b/node_package/src/types/index.ts index dd58529c44..49b3e19e9c 100644 --- a/node_package/src/types/index.ts +++ b/node_package/src/types/index.ts @@ -46,7 +46,7 @@ interface RenderFunction { (props?: any, railsContext?: RailsContext, domNodeId?: string): RenderFunctionResult; // We allow specifying that the function is RenderFunction and not a React Function Component // by setting this property - renderFunction?: boolean; + renderFunction?: true; } type ReactComponentOrRenderFunction = ReactComponent | RenderFunction; @@ -87,22 +87,16 @@ export interface CreateParams extends Params { shouldHydrate?: boolean; } -interface FileError extends Error { - fileName: string; - lineNumber: string; -} - export interface ErrorOptions { - e: FileError; + // fileName and lineNumber are non-standard, but useful if present + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/fileName + e: Error & { fileName?: string; lineNumber?: string }; name?: string; jsCode?: string; serverSide: boolean; } -export interface RenderingError { - message: string; - stack: string; -} +export type RenderingError = Pick; export interface RenderResult { html: string | null;