From d77cbd2c5aa237dd5d285ff6c52ff6ae0f9c6fbb Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 11 Aug 2022 18:49:56 +0200 Subject: [PATCH 1/7] Enable @typescript-eslint/no-use-before-define typedefs and enums --- .eslintrc.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index b2508a20109d..94c13432d0e4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -71,8 +71,8 @@ "functions": false, "classes": false, "variables": false, - "enums": false, - "typedefs": false + "enums": true, + "typedefs": true } ], "no-unused-vars": "off", From e1e9866c77c5bb74d788511df0f8178f56fd879b Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 11 Aug 2022 19:08:00 +0200 Subject: [PATCH 2/7] Enable variables --- .eslintrc.json | 2 +- .../build/analysis/get-page-static-info.ts | 3 +- .../webpack/plugins/middleware-plugin.ts | 58 ++--- packages/next/client/future/image.tsx | 220 ++++++++--------- packages/next/client/image.tsx | 228 +++++++++--------- packages/next/client/index.tsx | 26 +- packages/next/client/use-intersection.tsx | 7 +- packages/next/pages/_error.tsx | 80 +++--- packages/next/server/render.tsx | 95 ++++---- packages/next/server/server-route-utils.ts | 56 ++--- packages/next/server/web/sandbox/context.ts | 14 +- .../src/internal/ReactDevOverlay.tsx | 20 +- 12 files changed, 404 insertions(+), 405 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 94c13432d0e4..48265b1a66af 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -70,7 +70,7 @@ { "functions": false, "classes": false, - "variables": false, + "variables": true, "enums": true, "typedefs": true } diff --git a/packages/next/build/analysis/get-page-static-info.ts b/packages/next/build/analysis/get-page-static-info.ts index af30649b7edc..d2692d1450d2 100644 --- a/packages/next/build/analysis/get-page-static-info.ts +++ b/packages/next/build/analysis/get-page-static-info.ts @@ -226,6 +226,7 @@ function getMiddlewareRegExpStrings( } } +let warnedAboutExperimentalEdgeApiFunctions = false function warnAboutExperimentalEdgeApiFunctions() { if (warnedAboutExperimentalEdgeApiFunctions) { return @@ -234,8 +235,6 @@ function warnAboutExperimentalEdgeApiFunctions() { warnedAboutExperimentalEdgeApiFunctions = true } -let warnedAboutExperimentalEdgeApiFunctions = false - const warnedUnsupportedValueMap = new Map() function warnAboutUnsupportedValue( pageFilePath: string, diff --git a/packages/next/build/webpack/plugins/middleware-plugin.ts b/packages/next/build/webpack/plugins/middleware-plugin.ts index f688d4e32e9d..76bca9ee85ed 100644 --- a/packages/next/build/webpack/plugins/middleware-plugin.ts +++ b/packages/next/build/webpack/plugins/middleware-plugin.ts @@ -135,6 +135,35 @@ function getCodeAnalizer(params: { } = params const { hooks } = parser + /** + * For an expression this will check the graph to ensure it is being used + * by exports. Then it will store in the module buildInfo a boolean to + * express that it contains dynamic code and, if it is available, the + * module path that is using it. + */ + const handleExpression = () => { + if (!isInMiddlewareLayer(parser)) { + return + } + + wp.optimize.InnerGraph.onUsage(parser.state, (used = true) => { + const buildInfo = getModuleBuildInfo(parser.state.module) + if (buildInfo.usingIndirectEval === true || used === false) { + return + } + + if (!buildInfo.usingIndirectEval || used === true) { + buildInfo.usingIndirectEval = used + return + } + + buildInfo.usingIndirectEval = new Set([ + ...Array.from(buildInfo.usingIndirectEval), + ...Array.from(used), + ]) + }) + } + /** * This expression handler allows to wrap a dynamic code expression with a * function call where we can warn about dynamic code not being allowed @@ -216,35 +245,6 @@ function getCodeAnalizer(params: { } } - /** - * For an expression this will check the graph to ensure it is being used - * by exports. Then it will store in the module buildInfo a boolean to - * express that it contains dynamic code and, if it is available, the - * module path that is using it. - */ - const handleExpression = () => { - if (!isInMiddlewareLayer(parser)) { - return - } - - wp.optimize.InnerGraph.onUsage(parser.state, (used = true) => { - const buildInfo = getModuleBuildInfo(parser.state.module) - if (buildInfo.usingIndirectEval === true || used === false) { - return - } - - if (!buildInfo.usingIndirectEval || used === true) { - buildInfo.usingIndirectEval = used - return - } - - buildInfo.usingIndirectEval = new Set([ - ...Array.from(buildInfo.usingIndirectEval), - ...Array.from(used), - ]) - }) - } - /** * Declares an environment variable that is being used in this module * through this static analysis. diff --git a/packages/next/client/future/image.tsx b/packages/next/client/future/image.tsx index 57e07805dd5f..10cac772bd82 100644 --- a/packages/next/client/future/image.tsx +++ b/packages/next/client/future/image.tsx @@ -319,6 +319,116 @@ function handleLoading( }) } +const ImageElement = ({ + imgAttributes, + heightInt, + widthInt, + qualityInt, + className, + imgStyle, + blurStyle, + isLazy, + fill, + placeholder, + loading, + srcString, + config, + unoptimized, + loader, + onLoadingCompleteRef, + setBlurComplete, + setShowAltText, + onLoad, + onError, + noscriptSizes, + ...rest +}: ImageElementProps) => { + loading = isLazy ? 'lazy' : loading + return ( + <> + { + if (process.env.NODE_ENV !== 'production') { + if (img && !srcString) { + console.error(`Image is missing required "src" property:`, img) + } + } + if (img?.complete) { + handleLoading( + img, + srcString, + placeholder, + onLoadingCompleteRef, + setBlurComplete + ) + } + }, + [srcString, placeholder, onLoadingCompleteRef, setBlurComplete] + )} + onLoad={(event) => { + const img = event.currentTarget as ImgElementWithDataProp + handleLoading( + img, + srcString, + placeholder, + onLoadingCompleteRef, + setBlurComplete + ) + if (onLoad) { + onLoad(event) + } + }} + onError={(event) => { + // if the real image fails to load, this will ensure "alt" is visible + setShowAltText(true) + if (placeholder === 'blur') { + // If the real image fails to load, this will still remove the placeholder. + setBlurComplete(true) + } + if (onError) { + onError(event) + } + }} + /> + {placeholder === 'blur' && ( + + )} + + ) +} + export default function Image({ src, sizes, @@ -690,116 +800,6 @@ export default function Image({ ) } -const ImageElement = ({ - imgAttributes, - heightInt, - widthInt, - qualityInt, - className, - imgStyle, - blurStyle, - isLazy, - fill, - placeholder, - loading, - srcString, - config, - unoptimized, - loader, - onLoadingCompleteRef, - setBlurComplete, - setShowAltText, - onLoad, - onError, - noscriptSizes, - ...rest -}: ImageElementProps) => { - loading = isLazy ? 'lazy' : loading - return ( - <> - { - if (process.env.NODE_ENV !== 'production') { - if (img && !srcString) { - console.error(`Image is missing required "src" property:`, img) - } - } - if (img?.complete) { - handleLoading( - img, - srcString, - placeholder, - onLoadingCompleteRef, - setBlurComplete - ) - } - }, - [srcString, placeholder, onLoadingCompleteRef, setBlurComplete] - )} - onLoad={(event) => { - const img = event.currentTarget as ImgElementWithDataProp - handleLoading( - img, - srcString, - placeholder, - onLoadingCompleteRef, - setBlurComplete - ) - if (onLoad) { - onLoad(event) - } - }} - onError={(event) => { - // if the real image fails to load, this will ensure "alt" is visible - setShowAltText(true) - if (placeholder === 'blur') { - // If the real image fails to load, this will still remove the placeholder. - setBlurComplete(true) - } - if (onError) { - onError(event) - } - }} - /> - {placeholder === 'blur' && ( - - )} - - ) -} - function defaultLoader({ config, src, diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx index 62cdcd9d84f3..20e17aff73e3 100644 --- a/packages/next/client/image.tsx +++ b/packages/next/client/image.tsx @@ -349,6 +349,120 @@ function handleLoading( }) } +const ImageElement = ({ + imgAttributes, + heightInt, + widthInt, + qualityInt, + layout, + className, + imgStyle, + blurStyle, + isLazy, + placeholder, + loading, + srcString, + config, + unoptimized, + loader, + onLoadingCompleteRef, + setBlurComplete, + setIntersection, + onLoad, + onError, + isVisible, + noscriptSizes, + ...rest +}: ImageElementProps) => { + loading = isLazy ? 'lazy' : loading + return ( + <> + { + if (process.env.NODE_ENV !== 'production') { + if (img && !srcString) { + console.error(`Image is missing required "src" property:`, img) + } + } + setIntersection(img) + if (img?.complete) { + handleLoading( + img, + srcString, + layout, + placeholder, + onLoadingCompleteRef, + setBlurComplete + ) + } + }, + [ + setIntersection, + srcString, + layout, + placeholder, + onLoadingCompleteRef, + setBlurComplete, + ] + )} + onLoad={(event) => { + const img = event.currentTarget as ImgElementWithDataProp + handleLoading( + img, + srcString, + layout, + placeholder, + onLoadingCompleteRef, + setBlurComplete + ) + if (onLoad) { + onLoad(event) + } + }} + onError={(event) => { + if (placeholder === 'blur') { + // If the real image fails to load, this will still remove the placeholder. + setBlurComplete(true) + } + if (onError) { + onError(event) + } + }} + /> + {(isLazy || placeholder === 'blur') && ( + + )} + + ) +} + export default function Image({ src, sizes, @@ -846,120 +960,6 @@ export default function Image({ ) } -const ImageElement = ({ - imgAttributes, - heightInt, - widthInt, - qualityInt, - layout, - className, - imgStyle, - blurStyle, - isLazy, - placeholder, - loading, - srcString, - config, - unoptimized, - loader, - onLoadingCompleteRef, - setBlurComplete, - setIntersection, - onLoad, - onError, - isVisible, - noscriptSizes, - ...rest -}: ImageElementProps) => { - loading = isLazy ? 'lazy' : loading - return ( - <> - { - if (process.env.NODE_ENV !== 'production') { - if (img && !srcString) { - console.error(`Image is missing required "src" property:`, img) - } - } - setIntersection(img) - if (img?.complete) { - handleLoading( - img, - srcString, - layout, - placeholder, - onLoadingCompleteRef, - setBlurComplete - ) - } - }, - [ - setIntersection, - srcString, - layout, - placeholder, - onLoadingCompleteRef, - setBlurComplete, - ] - )} - onLoad={(event) => { - const img = event.currentTarget as ImgElementWithDataProp - handleLoading( - img, - srcString, - layout, - placeholder, - onLoadingCompleteRef, - setBlurComplete - ) - if (onLoad) { - onLoad(event) - } - }} - onError={(event) => { - if (placeholder === 'blur') { - // If the real image fails to load, this will still remove the placeholder. - setBlurComplete(true) - } - if (onError) { - onError(event) - } - }} - /> - {(isLazy || placeholder === 'blur') && ( - - )} - - ) -} - function normalizeSrc(src: string): string { return src[0] === '/' ? src.slice(1) : src } diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 535584636276..fd44ba7a7b34 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -80,6 +80,7 @@ let headManager: { getIsSsr?: () => boolean } let initialMatchesMiddleware = false +let lastAppProps: AppProps let lastRenderReject: (() => void) | null let webpackHMR: any @@ -395,6 +396,18 @@ export async function hydrate(opts?: { beforeRender?: () => Promise }) { await window.__NEXT_PRELOADREADY(initialData.dynamicIds) } + const wrapApp = + (App: AppComponent) => + (wrappedAppProps: Record): JSX.Element => { + const appProps: AppProps = { + ...wrappedAppProps, + Component: CachedComponent, + err: initialData.err, + router, + } + return {renderApp(App, appProps)} + } + router = createRouter(initialData.page, initialData.query, asPath, { initialProps: initialData.props, pageLoader, @@ -663,18 +676,6 @@ function renderApp(App: AppComponent, appProps: AppProps) { return } -const wrapApp = - (App: AppComponent) => - (wrappedAppProps: Record): JSX.Element => { - const appProps: AppProps = { - ...wrappedAppProps, - Component: CachedComponent, - err: initialData.err, - router, - } - return {renderApp(App, appProps)} - } - let RSCComponent: (props: any) => JSX.Element if (process.env.__NEXT_RSC) { const getCacheKey = () => { @@ -818,7 +819,6 @@ if (process.env.__NEXT_RSC) { } } -let lastAppProps: AppProps function doRender(input: RenderRouteInfo): Promise { let { App, Component, props, err, __N_RSC }: RenderRouteInfo = input let styleSheets: StyleSheetTuple[] | undefined = diff --git a/packages/next/client/use-intersection.tsx b/packages/next/client/use-intersection.tsx index 3f93811acaff..f13dd22f0b5c 100644 --- a/packages/next/client/use-intersection.tsx +++ b/packages/next/client/use-intersection.tsx @@ -72,6 +72,9 @@ export function useIntersection({ return [setElement, visible, resetVisible] } +const observers = new Map() +const idList: Identifier[] = [] + function observe( element: Element, callback: ObserveCallback, @@ -99,10 +102,6 @@ function observe( } } -const observers = new Map() - -const idList: Identifier[] = [] - function createObserver(options: UseIntersectionObserverInit): Observer { const id = { root: options.root || null, diff --git a/packages/next/pages/_error.tsx b/packages/next/pages/_error.tsx index 3a512cb70f7d..3cc85fb0a16f 100644 --- a/packages/next/pages/_error.tsx +++ b/packages/next/pages/_error.tsx @@ -24,6 +24,46 @@ function _getInitialProps({ return { statusCode } } +const styles: { [k: string]: React.CSSProperties } = { + error: { + fontFamily: + '-apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif', + height: '100vh', + textAlign: 'center', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + }, + + desc: { + display: 'inline-block', + textAlign: 'left', + lineHeight: '49px', + height: '49px', + verticalAlign: 'middle', + }, + + h1: { + display: 'inline-block', + margin: 0, + marginRight: '20px', + padding: '0 23px 0 0', + fontSize: '24px', + fontWeight: 500, + verticalAlign: 'top', + lineHeight: '49px', + }, + + h2: { + fontSize: '14px', + fontWeight: 'normal', + lineHeight: '49px', + margin: 0, + padding: 0, + }, +} + /** * `Error` component used for handling errors. */ @@ -94,43 +134,3 @@ export default class Error

extends React.Component

{ ) } } - -const styles: { [k: string]: React.CSSProperties } = { - error: { - fontFamily: - '-apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif', - height: '100vh', - textAlign: 'center', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - }, - - desc: { - display: 'inline-block', - textAlign: 'left', - lineHeight: '49px', - height: '49px', - verticalAlign: 'middle', - }, - - h1: { - display: 'inline-block', - margin: 0, - marginRight: '20px', - padding: '0 23px 0 0', - fontSize: '24px', - fontWeight: 500, - verticalAlign: 'top', - lineHeight: '49px', - }, - - h2: { - fontSize: '14px', - fontWeight: 'normal', - lineHeight: '49px', - margin: 0, - padding: 0, - }, -} diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index 1bc29fbc3361..093db7c9fa88 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -573,40 +573,9 @@ export async function renderToHTML( isPreview, getRequestMeta(req, '__nextIsLocaleDomain') ) - const jsxStyleRegistry = createStyleRegistry() - const ctx = { - err, - req: isAutoExport ? undefined : req, - res: isAutoExport ? undefined : res, - pathname, - query, - asPath, - locale: renderOpts.locale, - locales: renderOpts.locales, - defaultLocale: renderOpts.defaultLocale, - AppTree: (props: any) => { - return ( - - {renderPageTree(App, OriginComponent, { ...props, router })} - - ) - }, - defaultGetInitialProps: async ( - docCtx: DocumentContext, - options: { nonce?: string } = {} - ): Promise => { - const enhanceApp = (AppComp: any) => { - return (props: any) => - } - - const { html, head } = await docCtx.renderPage({ enhanceApp }) - const styles = jsxStyleRegistry.styles({ nonce: options.nonce }) - jsxStyleRegistry.flush() - return { html, head, styles } - }, - } - let props: any + let scriptLoader: any = {} + const jsxStyleRegistry = createStyleRegistry() const ampState = { ampFirst: pageConfig.amp === true, hasQuery: Boolean(query.amp), @@ -615,10 +584,8 @@ export async function renderToHTML( // Disable AMP under the web environment const inAmpMode = process.env.NEXT_RUNTIME !== 'edge' && isInAmpMode(ampState) - - const reactLoadableModules: string[] = [] - let head: JSX.Element[] = defaultHead(inAmpMode) + const reactLoadableModules: string[] = [] let initialScripts: any = {} if (hasPageScripts) { @@ -628,16 +595,6 @@ export async function renderToHTML( .map((script: any) => script.props) } - let scriptLoader: any = {} - const nextExport = - !isSSG && (renderOpts.nextExport || (dev && (isAutoExport || isFallback))) - - const styledJsxFlushEffect = () => { - const styles = jsxStyleRegistry.styles() - jsxStyleRegistry.flush() - return <>{styles} - } - const AppContainer = ({ children }: { children: JSX.Element }) => ( @@ -700,6 +657,50 @@ export async function renderToHTML( ) } + const ctx = { + err, + req: isAutoExport ? undefined : req, + res: isAutoExport ? undefined : res, + pathname, + query, + asPath, + locale: renderOpts.locale, + locales: renderOpts.locales, + defaultLocale: renderOpts.defaultLocale, + AppTree: (props: any) => { + return ( + + {renderPageTree(App, OriginComponent, { ...props, router })} + + ) + }, + defaultGetInitialProps: async ( + docCtx: DocumentContext, + options: { nonce?: string } = {} + ): Promise => { + const enhanceApp = (AppComp: any) => { + return (props: any) => + } + + const { html, head: renderPageHead } = await docCtx.renderPage({ + enhanceApp, + }) + const styles = jsxStyleRegistry.styles({ nonce: options.nonce }) + jsxStyleRegistry.flush() + return { html, head: renderPageHead, styles } + }, + } + let props: any + + const nextExport = + !isSSG && (renderOpts.nextExport || (dev && (isAutoExport || isFallback))) + + const styledJsxFlushEffect = () => { + const styles = jsxStyleRegistry.styles() + jsxStyleRegistry.flush() + return <>{styles} + } + props = await loadGetInitialProps(App, { AppTree: ctx.AppTree, Component, @@ -1299,7 +1300,7 @@ export async function renderToHTML( } const { docProps } = (documentInitialPropsRes as any) || {} - const documentElement = () => { + const documentElement = (htmlProps: any) => { if (process.env.NEXT_RUNTIME === 'edge') { return (Document as any)() } else { diff --git a/packages/next/server/server-route-utils.ts b/packages/next/server/server-route-utils.ts index c21f07a98bcf..4ad6b3469fbb 100644 --- a/packages/next/server/server-route-utils.ts +++ b/packages/next/server/server-route-utils.ts @@ -98,6 +98,34 @@ export const createHeaderRoute = ({ } } +// since initial query values are decoded by querystring.parse +// we need to re-encode them here but still allow passing through +// values from rewrites/redirects +export const stringifyQuery = (req: BaseNextRequest, query: ParsedUrlQuery) => { + const initialQuery = getRequestMeta(req, '__NEXT_INIT_QUERY') || {} + const initialQueryValues: Array = + Object.values(initialQuery) + + return stringifyQs(query, undefined, undefined, { + encodeURIComponent(value) { + if ( + value in initialQuery || + initialQueryValues.some((initialQueryVal: string | string[]) => { + // `value` always refers to a query value, even if it's nested in an array + return Array.isArray(initialQueryVal) + ? initialQueryVal.includes(value) + : initialQueryVal === value + }) + ) { + // Encode keys and values from initial query + return encodeURIComponent(value) + } + + return value + }, + }) +} + export const createRedirectRoute = ({ rule, restrictedRedirectPaths, @@ -151,31 +179,3 @@ export const createRedirectRoute = ({ }, } } - -// since initial query values are decoded by querystring.parse -// we need to re-encode them here but still allow passing through -// values from rewrites/redirects -export const stringifyQuery = (req: BaseNextRequest, query: ParsedUrlQuery) => { - const initialQuery = getRequestMeta(req, '__NEXT_INIT_QUERY') || {} - const initialQueryValues: Array = - Object.values(initialQuery) - - return stringifyQs(query, undefined, undefined, { - encodeURIComponent(value) { - if ( - value in initialQuery || - initialQueryValues.some((initialQueryVal: string | string[]) => { - // `value` always refers to a query value, even if it's nested in an array - return Array.isArray(initialQueryVal) - ? initialQueryVal.includes(value) - : initialQueryVal === value - }) - ) { - // Encode keys and values from initial query - return encodeURIComponent(value) - } - - return value - }, - }) -} diff --git a/packages/next/server/web/sandbox/context.ts b/packages/next/server/web/sandbox/context.ts index 4aa5ff42a26a..b641c2e3a61f 100644 --- a/packages/next/server/web/sandbox/context.ts +++ b/packages/next/server/web/sandbox/context.ts @@ -20,6 +20,13 @@ interface ModuleContext { warnedEvals: Set } +/** + * A Map of cached module contexts indexed by the module name. It allows + * to have a different cache scoped per module name or depending on the + * provided module key on creation. + */ +const moduleContexts = new Map() + /** * For a given path a context, this function checks if there is any module * context that contains the path with an older content and, if that's the @@ -37,13 +44,6 @@ export function clearModuleContext(path: string, content: Buffer | string) { } } -/** - * A Map of cached module contexts indexed by the module name. It allows - * to have a different cache scoped per module name or depending on the - * provided module key on creation. - */ -const moduleContexts = new Map() - interface ModuleContextOptions { moduleName: string onWarning: (warn: Error) => void diff --git a/packages/react-dev-overlay/src/internal/ReactDevOverlay.tsx b/packages/react-dev-overlay/src/internal/ReactDevOverlay.tsx index d125ccc93bf1..21279b730bd5 100644 --- a/packages/react-dev-overlay/src/internal/ReactDevOverlay.tsx +++ b/packages/react-dev-overlay/src/internal/ReactDevOverlay.tsx @@ -50,6 +50,16 @@ function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState { type ErrorType = 'runtime' | 'build' +const shouldPreventDisplay = ( + errorType?: ErrorType | null, + preventType?: ErrorType[] | null +) => { + if (!preventType || !errorType) { + return false + } + return preventType.includes(errorType) +} + const ReactDevOverlay: React.FunctionComponent = function ReactDevOverlay({ children, preventDisplay, @@ -115,14 +125,4 @@ const ReactDevOverlay: React.FunctionComponent = function ReactDevOverlay({ ) } -const shouldPreventDisplay = ( - errorType?: ErrorType | null, - preventType?: ErrorType[] | null -) => { - if (!preventType || !errorType) { - return false - } - return preventType.includes(errorType) -} - export default ReactDevOverlay From 592d70cf3d9cd39e741905faf9229f664c9b4ebd Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 11 Aug 2022 19:21:14 +0200 Subject: [PATCH 3/7] Move in client/index --- .eslintrc.json | 2 +- .../build/analysis/extract-const-value.ts | 3 +- packages/next/client/index.tsx | 24 +-- packages/next/lib/is-serializable-props.ts | 20 +-- packages/next/pages/_document.tsx | 156 +++++++++--------- 5 files changed, 103 insertions(+), 102 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 48265b1a66af..cda24c1d8079 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -69,7 +69,7 @@ "warn", { "functions": false, - "classes": false, + "classes": true, "variables": true, "enums": true, "typedefs": true diff --git a/packages/next/build/analysis/extract-const-value.ts b/packages/next/build/analysis/extract-const-value.ts index e067b1c73eeb..a08c9d40b9a9 100644 --- a/packages/next/build/analysis/extract-const-value.ts +++ b/packages/next/build/analysis/extract-const-value.ts @@ -15,6 +15,8 @@ import type { VariableDeclaration, } from '@swc/core' +export class NoSuchDeclarationError extends Error {} + /** * Extracts the value of an exported const variable named `exportedName` * (e.g. "export const config = { runtime: 'experimental-edge' }") from swc's AST. @@ -138,7 +140,6 @@ export class UnsupportedValueError extends Error { this.path = codePath } } -export class NoSuchDeclarationError extends Error {} function extractValue(node: Node, path?: string[]): any { if (isNullLiteral(node)) { diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index fd44ba7a7b34..9b5086028300 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -289,6 +289,18 @@ export async function initialize(opts: { webpackHMR?: any } = {}): Promise<{ return { assetPrefix: prefix } } +const wrapApp = + (App: AppComponent) => + (wrappedAppProps: Record): JSX.Element => { + const appProps: AppProps = { + ...wrappedAppProps, + Component: CachedComponent, + err: initialData.err, + router, + } + return {renderApp(App, appProps)} + } + export async function hydrate(opts?: { beforeRender?: () => Promise }) { let initialErr = initialData.err @@ -396,18 +408,6 @@ export async function hydrate(opts?: { beforeRender?: () => Promise }) { await window.__NEXT_PRELOADREADY(initialData.dynamicIds) } - const wrapApp = - (App: AppComponent) => - (wrappedAppProps: Record): JSX.Element => { - const appProps: AppProps = { - ...wrappedAppProps, - Component: CachedComponent, - err: initialData.err, - router, - } - return {renderApp(App, appProps)} - } - router = createRouter(initialData.page, initialData.query, asPath, { initialProps: initialData.props, pageLoader, diff --git a/packages/next/lib/is-serializable-props.ts b/packages/next/lib/is-serializable-props.ts index e42407efc85f..77a8025e7559 100644 --- a/packages/next/lib/is-serializable-props.ts +++ b/packages/next/lib/is-serializable-props.ts @@ -5,6 +5,16 @@ import { const regexpPlainIdentifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/ +export class SerializableError extends Error { + constructor(page: string, method: string, path: string, message: string) { + super( + path + ? `Error serializing \`${path}\` returned from \`${method}\` in "${page}".\nReason: ${message}` + : `Error serializing props returned from \`${method}\` in "${page}".\nReason: ${message}` + ) + } +} + export function isSerializableProps( page: string, method: string, @@ -131,13 +141,3 @@ export function isSerializableProps( return isSerializable(new Map(), input, '') } - -export class SerializableError extends Error { - constructor(page: string, method: string, path: string, message: string) { - super( - path - ? `Error serializing \`${path}\` returned from \`${method}\` in "${page}".\nReason: ${message}` - : `Error serializing props returned from \`${method}\` in "${page}".\nReason: ${message}` - ) - } -} diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx index a5e24bed21dc..bc51644d9325 100644 --- a/packages/next/pages/_document.tsx +++ b/packages/next/pages/_document.tsx @@ -346,77 +346,6 @@ function getScripts( }) } -/** - * `Document` component handles the initial `document` markup and renders only on the server side. - * Commonly used for implementing server side rendering for `css-in-js` libraries. - */ -export default class Document

extends Component { - /** - * `getInitialProps` hook returns the context object with the addition of `renderPage`. - * `renderPage` callback executes `React` rendering logic synchronously to support server-rendering wrappers - */ - static getInitialProps(ctx: DocumentContext): Promise { - return ctx.defaultGetInitialProps(ctx) - } - - render() { - return ( - - - -

- - - - ) - } -} - -// Add a special property to the built-in `Document` component so later we can -// identify if a user customized `Document` is used or not. -const InternalFunctionDocument: DocumentType = - function InternalFunctionDocument() { - return ( - - - -
- - - - ) - } -;(Document as any)[NEXT_BUILTIN_DOCUMENT] = InternalFunctionDocument - -export function Html( - props: React.DetailedHTMLProps< - React.HtmlHTMLAttributes, - HTMLHtmlElement - > -) { - const { - inAmpMode, - docComponentsRendered, - locale, - scriptLoader, - __NEXT_DATA__, - } = useContext(HtmlContext) - - docComponentsRendered.Html = true - handleDocumentScriptLoaderItems(scriptLoader, __NEXT_DATA__, props) - - return ( - - ) -} - function AmpStyles({ styles, }: { @@ -938,13 +867,6 @@ export class Head extends Component { } } -export function Main() { - const { docComponentsRendered } = useContext(HtmlContext) - docComponentsRendered.Main = true - // @ts-ignore - return -} - export class NextScript extends Component { static contextType = HtmlContext @@ -1106,6 +1028,84 @@ export class NextScript extends Component { } } +/** + * `Document` component handles the initial `document` markup and renders only on the server side. + * Commonly used for implementing server side rendering for `css-in-js` libraries. + */ +export default class Document

extends Component { + /** + * `getInitialProps` hook returns the context object with the addition of `renderPage`. + * `renderPage` callback executes `React` rendering logic synchronously to support server-rendering wrappers + */ + static getInitialProps(ctx: DocumentContext): Promise { + return ctx.defaultGetInitialProps(ctx) + } + + render() { + return ( + + + +

+ + + + ) + } +} + +// Add a special property to the built-in `Document` component so later we can +// identify if a user customized `Document` is used or not. +const InternalFunctionDocument: DocumentType = + function InternalFunctionDocument() { + return ( + + + +
+ + + + ) + } +;(Document as any)[NEXT_BUILTIN_DOCUMENT] = InternalFunctionDocument + +export function Html( + props: React.DetailedHTMLProps< + React.HtmlHTMLAttributes, + HTMLHtmlElement + > +) { + const { + inAmpMode, + docComponentsRendered, + locale, + scriptLoader, + __NEXT_DATA__, + } = useContext(HtmlContext) + + docComponentsRendered.Html = true + handleDocumentScriptLoaderItems(scriptLoader, __NEXT_DATA__, props) + + return ( + + ) +} + +export function Main() { + const { docComponentsRendered } = useContext(HtmlContext) + docComponentsRendered.Main = true + // @ts-ignore + return +} + function getAmpPath(ampPath: string, asPath: string): string { return ampPath || `${asPath}${asPath.includes('?') ? '&' : '?'}amp=1` } From 14b6105eb45ab87b3b4a1d6f2907d8b9e9657888 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 11 Aug 2022 19:32:16 +0200 Subject: [PATCH 4/7] Revert "Move in client/index" This reverts commit 592d70cf3d9cd39e741905faf9229f664c9b4ebd. --- .eslintrc.json | 2 +- .../build/analysis/extract-const-value.ts | 3 +- packages/next/client/index.tsx | 24 +-- packages/next/lib/is-serializable-props.ts | 20 +-- packages/next/pages/_document.tsx | 156 +++++++++--------- 5 files changed, 102 insertions(+), 103 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index cda24c1d8079..48265b1a66af 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -69,7 +69,7 @@ "warn", { "functions": false, - "classes": true, + "classes": false, "variables": true, "enums": true, "typedefs": true diff --git a/packages/next/build/analysis/extract-const-value.ts b/packages/next/build/analysis/extract-const-value.ts index a08c9d40b9a9..e067b1c73eeb 100644 --- a/packages/next/build/analysis/extract-const-value.ts +++ b/packages/next/build/analysis/extract-const-value.ts @@ -15,8 +15,6 @@ import type { VariableDeclaration, } from '@swc/core' -export class NoSuchDeclarationError extends Error {} - /** * Extracts the value of an exported const variable named `exportedName` * (e.g. "export const config = { runtime: 'experimental-edge' }") from swc's AST. @@ -140,6 +138,7 @@ export class UnsupportedValueError extends Error { this.path = codePath } } +export class NoSuchDeclarationError extends Error {} function extractValue(node: Node, path?: string[]): any { if (isNullLiteral(node)) { diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 9b5086028300..fd44ba7a7b34 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -289,18 +289,6 @@ export async function initialize(opts: { webpackHMR?: any } = {}): Promise<{ return { assetPrefix: prefix } } -const wrapApp = - (App: AppComponent) => - (wrappedAppProps: Record): JSX.Element => { - const appProps: AppProps = { - ...wrappedAppProps, - Component: CachedComponent, - err: initialData.err, - router, - } - return {renderApp(App, appProps)} - } - export async function hydrate(opts?: { beforeRender?: () => Promise }) { let initialErr = initialData.err @@ -408,6 +396,18 @@ export async function hydrate(opts?: { beforeRender?: () => Promise }) { await window.__NEXT_PRELOADREADY(initialData.dynamicIds) } + const wrapApp = + (App: AppComponent) => + (wrappedAppProps: Record): JSX.Element => { + const appProps: AppProps = { + ...wrappedAppProps, + Component: CachedComponent, + err: initialData.err, + router, + } + return {renderApp(App, appProps)} + } + router = createRouter(initialData.page, initialData.query, asPath, { initialProps: initialData.props, pageLoader, diff --git a/packages/next/lib/is-serializable-props.ts b/packages/next/lib/is-serializable-props.ts index 77a8025e7559..e42407efc85f 100644 --- a/packages/next/lib/is-serializable-props.ts +++ b/packages/next/lib/is-serializable-props.ts @@ -5,16 +5,6 @@ import { const regexpPlainIdentifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/ -export class SerializableError extends Error { - constructor(page: string, method: string, path: string, message: string) { - super( - path - ? `Error serializing \`${path}\` returned from \`${method}\` in "${page}".\nReason: ${message}` - : `Error serializing props returned from \`${method}\` in "${page}".\nReason: ${message}` - ) - } -} - export function isSerializableProps( page: string, method: string, @@ -141,3 +131,13 @@ export function isSerializableProps( return isSerializable(new Map(), input, '') } + +export class SerializableError extends Error { + constructor(page: string, method: string, path: string, message: string) { + super( + path + ? `Error serializing \`${path}\` returned from \`${method}\` in "${page}".\nReason: ${message}` + : `Error serializing props returned from \`${method}\` in "${page}".\nReason: ${message}` + ) + } +} diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx index bc51644d9325..a5e24bed21dc 100644 --- a/packages/next/pages/_document.tsx +++ b/packages/next/pages/_document.tsx @@ -346,6 +346,77 @@ function getScripts( }) } +/** + * `Document` component handles the initial `document` markup and renders only on the server side. + * Commonly used for implementing server side rendering for `css-in-js` libraries. + */ +export default class Document

extends Component { + /** + * `getInitialProps` hook returns the context object with the addition of `renderPage`. + * `renderPage` callback executes `React` rendering logic synchronously to support server-rendering wrappers + */ + static getInitialProps(ctx: DocumentContext): Promise { + return ctx.defaultGetInitialProps(ctx) + } + + render() { + return ( + + + +

+ + + + ) + } +} + +// Add a special property to the built-in `Document` component so later we can +// identify if a user customized `Document` is used or not. +const InternalFunctionDocument: DocumentType = + function InternalFunctionDocument() { + return ( + + + +
+ + + + ) + } +;(Document as any)[NEXT_BUILTIN_DOCUMENT] = InternalFunctionDocument + +export function Html( + props: React.DetailedHTMLProps< + React.HtmlHTMLAttributes, + HTMLHtmlElement + > +) { + const { + inAmpMode, + docComponentsRendered, + locale, + scriptLoader, + __NEXT_DATA__, + } = useContext(HtmlContext) + + docComponentsRendered.Html = true + handleDocumentScriptLoaderItems(scriptLoader, __NEXT_DATA__, props) + + return ( + + ) +} + function AmpStyles({ styles, }: { @@ -867,6 +938,13 @@ export class Head extends Component { } } +export function Main() { + const { docComponentsRendered } = useContext(HtmlContext) + docComponentsRendered.Main = true + // @ts-ignore + return +} + export class NextScript extends Component { static contextType = HtmlContext @@ -1028,84 +1106,6 @@ export class NextScript extends Component { } } -/** - * `Document` component handles the initial `document` markup and renders only on the server side. - * Commonly used for implementing server side rendering for `css-in-js` libraries. - */ -export default class Document

extends Component { - /** - * `getInitialProps` hook returns the context object with the addition of `renderPage`. - * `renderPage` callback executes `React` rendering logic synchronously to support server-rendering wrappers - */ - static getInitialProps(ctx: DocumentContext): Promise { - return ctx.defaultGetInitialProps(ctx) - } - - render() { - return ( - - - -

- - - - ) - } -} - -// Add a special property to the built-in `Document` component so later we can -// identify if a user customized `Document` is used or not. -const InternalFunctionDocument: DocumentType = - function InternalFunctionDocument() { - return ( - - - -
- - - - ) - } -;(Document as any)[NEXT_BUILTIN_DOCUMENT] = InternalFunctionDocument - -export function Html( - props: React.DetailedHTMLProps< - React.HtmlHTMLAttributes, - HTMLHtmlElement - > -) { - const { - inAmpMode, - docComponentsRendered, - locale, - scriptLoader, - __NEXT_DATA__, - } = useContext(HtmlContext) - - docComponentsRendered.Html = true - handleDocumentScriptLoaderItems(scriptLoader, __NEXT_DATA__, props) - - return ( - - ) -} - -export function Main() { - const { docComponentsRendered } = useContext(HtmlContext) - docComponentsRendered.Main = true - // @ts-ignore - return -} - function getAmpPath(ampPath: string, asPath: string): string { return ampPath || `${asPath}${asPath.includes('?') ? '&' : '?'}amp=1` } From 4e14053e27cd6bcd37b0a06795b8f1bdfa166736 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 11 Aug 2022 19:41:52 +0200 Subject: [PATCH 5/7] Move wrapApp --- packages/next/client/index.tsx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index fd44ba7a7b34..9b5086028300 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -289,6 +289,18 @@ export async function initialize(opts: { webpackHMR?: any } = {}): Promise<{ return { assetPrefix: prefix } } +const wrapApp = + (App: AppComponent) => + (wrappedAppProps: Record): JSX.Element => { + const appProps: AppProps = { + ...wrappedAppProps, + Component: CachedComponent, + err: initialData.err, + router, + } + return {renderApp(App, appProps)} + } + export async function hydrate(opts?: { beforeRender?: () => Promise }) { let initialErr = initialData.err @@ -396,18 +408,6 @@ export async function hydrate(opts?: { beforeRender?: () => Promise }) { await window.__NEXT_PRELOADREADY(initialData.dynamicIds) } - const wrapApp = - (App: AppComponent) => - (wrappedAppProps: Record): JSX.Element => { - const appProps: AppProps = { - ...wrappedAppProps, - Component: CachedComponent, - err: initialData.err, - router, - } - return {renderApp(App, appProps)} - } - router = createRouter(initialData.page, initialData.query, asPath, { initialProps: initialData.props, pageLoader, From 055fd1a721524e25916fb6c07a4e1c3d1c2c3520 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 11 Aug 2022 19:43:22 +0200 Subject: [PATCH 6/7] Revert "Revert "Move in client/index"" This reverts commit 14b6105eb45ab87b3b4a1d6f2907d8b9e9657888. --- .eslintrc.json | 2 +- .../build/analysis/extract-const-value.ts | 3 +- packages/next/lib/is-serializable-props.ts | 20 +-- packages/next/pages/_document.tsx | 156 +++++++++--------- 4 files changed, 91 insertions(+), 90 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 48265b1a66af..cda24c1d8079 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -69,7 +69,7 @@ "warn", { "functions": false, - "classes": false, + "classes": true, "variables": true, "enums": true, "typedefs": true diff --git a/packages/next/build/analysis/extract-const-value.ts b/packages/next/build/analysis/extract-const-value.ts index e067b1c73eeb..a08c9d40b9a9 100644 --- a/packages/next/build/analysis/extract-const-value.ts +++ b/packages/next/build/analysis/extract-const-value.ts @@ -15,6 +15,8 @@ import type { VariableDeclaration, } from '@swc/core' +export class NoSuchDeclarationError extends Error {} + /** * Extracts the value of an exported const variable named `exportedName` * (e.g. "export const config = { runtime: 'experimental-edge' }") from swc's AST. @@ -138,7 +140,6 @@ export class UnsupportedValueError extends Error { this.path = codePath } } -export class NoSuchDeclarationError extends Error {} function extractValue(node: Node, path?: string[]): any { if (isNullLiteral(node)) { diff --git a/packages/next/lib/is-serializable-props.ts b/packages/next/lib/is-serializable-props.ts index e42407efc85f..77a8025e7559 100644 --- a/packages/next/lib/is-serializable-props.ts +++ b/packages/next/lib/is-serializable-props.ts @@ -5,6 +5,16 @@ import { const regexpPlainIdentifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/ +export class SerializableError extends Error { + constructor(page: string, method: string, path: string, message: string) { + super( + path + ? `Error serializing \`${path}\` returned from \`${method}\` in "${page}".\nReason: ${message}` + : `Error serializing props returned from \`${method}\` in "${page}".\nReason: ${message}` + ) + } +} + export function isSerializableProps( page: string, method: string, @@ -131,13 +141,3 @@ export function isSerializableProps( return isSerializable(new Map(), input, '') } - -export class SerializableError extends Error { - constructor(page: string, method: string, path: string, message: string) { - super( - path - ? `Error serializing \`${path}\` returned from \`${method}\` in "${page}".\nReason: ${message}` - : `Error serializing props returned from \`${method}\` in "${page}".\nReason: ${message}` - ) - } -} diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx index a5e24bed21dc..bc51644d9325 100644 --- a/packages/next/pages/_document.tsx +++ b/packages/next/pages/_document.tsx @@ -346,77 +346,6 @@ function getScripts( }) } -/** - * `Document` component handles the initial `document` markup and renders only on the server side. - * Commonly used for implementing server side rendering for `css-in-js` libraries. - */ -export default class Document

extends Component { - /** - * `getInitialProps` hook returns the context object with the addition of `renderPage`. - * `renderPage` callback executes `React` rendering logic synchronously to support server-rendering wrappers - */ - static getInitialProps(ctx: DocumentContext): Promise { - return ctx.defaultGetInitialProps(ctx) - } - - render() { - return ( - - - -

- - - - ) - } -} - -// Add a special property to the built-in `Document` component so later we can -// identify if a user customized `Document` is used or not. -const InternalFunctionDocument: DocumentType = - function InternalFunctionDocument() { - return ( - - - -
- - - - ) - } -;(Document as any)[NEXT_BUILTIN_DOCUMENT] = InternalFunctionDocument - -export function Html( - props: React.DetailedHTMLProps< - React.HtmlHTMLAttributes, - HTMLHtmlElement - > -) { - const { - inAmpMode, - docComponentsRendered, - locale, - scriptLoader, - __NEXT_DATA__, - } = useContext(HtmlContext) - - docComponentsRendered.Html = true - handleDocumentScriptLoaderItems(scriptLoader, __NEXT_DATA__, props) - - return ( - - ) -} - function AmpStyles({ styles, }: { @@ -938,13 +867,6 @@ export class Head extends Component { } } -export function Main() { - const { docComponentsRendered } = useContext(HtmlContext) - docComponentsRendered.Main = true - // @ts-ignore - return -} - export class NextScript extends Component { static contextType = HtmlContext @@ -1106,6 +1028,84 @@ export class NextScript extends Component { } } +/** + * `Document` component handles the initial `document` markup and renders only on the server side. + * Commonly used for implementing server side rendering for `css-in-js` libraries. + */ +export default class Document

extends Component { + /** + * `getInitialProps` hook returns the context object with the addition of `renderPage`. + * `renderPage` callback executes `React` rendering logic synchronously to support server-rendering wrappers + */ + static getInitialProps(ctx: DocumentContext): Promise { + return ctx.defaultGetInitialProps(ctx) + } + + render() { + return ( + + + +

+ + + + ) + } +} + +// Add a special property to the built-in `Document` component so later we can +// identify if a user customized `Document` is used or not. +const InternalFunctionDocument: DocumentType = + function InternalFunctionDocument() { + return ( + + + +
+ + + + ) + } +;(Document as any)[NEXT_BUILTIN_DOCUMENT] = InternalFunctionDocument + +export function Html( + props: React.DetailedHTMLProps< + React.HtmlHTMLAttributes, + HTMLHtmlElement + > +) { + const { + inAmpMode, + docComponentsRendered, + locale, + scriptLoader, + __NEXT_DATA__, + } = useContext(HtmlContext) + + docComponentsRendered.Html = true + handleDocumentScriptLoaderItems(scriptLoader, __NEXT_DATA__, props) + + return ( + + ) +} + +export function Main() { + const { docComponentsRendered } = useContext(HtmlContext) + docComponentsRendered.Main = true + // @ts-ignore + return +} + function getAmpPath(ampPath: string, asPath: string): string { return ampPath || `${asPath}${asPath.includes('?') ? '&' : '?'}amp=1` } From a66c52ec23804baeeb275eb76d710b3961c0c2c9 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 11 Aug 2022 20:59:15 +0200 Subject: [PATCH 7/7] Fix classes cases --- packages/next/pages/_document.tsx | 752 +++++++++--------- packages/next/server/base-server.ts | 38 +- packages/next/server/dev/hot-middleware.ts | 66 +- .../server/dev/on-demand-entry-handler.ts | 116 +-- packages/next/server/web/adapter.ts | 50 +- packages/next/types/webpack.d.ts | 8 +- 6 files changed, 515 insertions(+), 515 deletions(-) diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx index bc51644d9325..91268630de9b 100644 --- a/packages/next/pages/_document.tsx +++ b/packages/next/pages/_document.tsx @@ -88,397 +88,139 @@ function hasComponentProps(child: any): child is React.ReactElement { return !!child && !!child.props } -function handleDocumentScriptLoaderItems( - scriptLoader: { beforeInteractive?: any[] }, - __NEXT_DATA__: NEXT_DATA, - props: any -): void { - if (!props.children) return +function AmpStyles({ + styles, +}: { + styles?: React.ReactElement[] | React.ReactFragment +}) { + if (!styles) return null - const scriptLoaderItems: ScriptProps[] = [] + // try to parse styles from fragment for backwards compat + const curStyles: React.ReactElement[] = Array.isArray(styles) + ? (styles as React.ReactElement[]) + : [] + if ( + // @ts-ignore Property 'props' does not exist on type ReactElement + styles.props && + // @ts-ignore Property 'props' does not exist on type ReactElement + Array.isArray(styles.props.children) + ) { + const hasStyles = (el: React.ReactElement) => + el?.props?.dangerouslySetInnerHTML?.__html + // @ts-ignore Property 'props' does not exist on type ReactElement + styles.props.children.forEach((child: React.ReactElement) => { + if (Array.isArray(child)) { + child.forEach((el) => hasStyles(el) && curStyles.push(el)) + } else if (hasStyles(child)) { + curStyles.push(child) + } + }) + } - const children = Array.isArray(props.children) - ? props.children - : [props.children] + /* Add custom styles before AMP styles to prevent accidental overrides */ + return ( +