From 57702cb2a9a9dba4b552e0007c16449cf36cfb44 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 28 Feb 2022 23:39:51 +0100 Subject: [PATCH] Only warn styles and scripts under next head in concurrent mode (#34897) x-ref: #34021 , #34004 Only log each warning once and only trigger in concurrent mode ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [x] Errors have helpful link attached, see `contributing.md` --- packages/next/client/image.tsx | 12 +-- packages/next/shared/lib/head.tsx | 10 ++- packages/next/shared/lib/utils.ts | 13 +++ .../client-navigation/test/index.test.js | 69 ---------------- .../app}/pages/head-with-json-ld-snippet.js | 0 .../app/pages/head.js | 15 ++++ .../test/index.test.js | 6 +- .../test/streaming.js | 82 ++++++++++++++++++- 8 files changed, 119 insertions(+), 88 deletions(-) rename test/integration/{client-navigation => react-streaming-and-server-components/app}/pages/head-with-json-ld-snippet.js (100%) create mode 100644 test/integration/react-streaming-and-server-components/app/pages/head.js diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx index 03f5438f93612..6fad0b58d355c 100644 --- a/packages/next/client/image.tsx +++ b/packages/next/client/image.tsx @@ -8,6 +8,7 @@ import { } from '../shared/lib/image-config' import { useIntersection } from './use-intersection' import { ImageConfigContext } from '../shared/lib/image-config-context' +import { warnOnce } from '../shared/lib/utils' const configEnv = process.env.__NEXT_IMAGE_OPTS as any as ImageConfigComplete const loadedImageURLs = new Set() @@ -23,17 +24,6 @@ if (typeof window === 'undefined') { ;(global as any).__NEXT_IMAGE_IMPORTED = true } -let warnOnce = (_: string) => {} -if (process.env.NODE_ENV !== 'production') { - const warnings = new Set() - warnOnce = (msg: string) => { - if (!warnings.has(msg)) { - console.warn(msg) - } - warnings.add(msg) - } -} - const VALID_LOADING_VALUES = ['lazy', 'eager', undefined] as const type LoadingValue = typeof VALID_LOADING_VALUES[number] type ImageConfig = ImageConfigComplete & { allSizes: number[] } diff --git a/packages/next/shared/lib/head.tsx b/packages/next/shared/lib/head.tsx index 81d339e21a9f3..d4bbcc64bed22 100644 --- a/packages/next/shared/lib/head.tsx +++ b/packages/next/shared/lib/head.tsx @@ -3,6 +3,7 @@ import Effect from './side-effect' import { AmpStateContext } from './amp-context' import { HeadManagerContext } from './head-manager-context' import { isInAmpMode } from './amp' +import { warnOnce } from './utils' type WithInAmpMode = { inAmpMode?: boolean @@ -161,17 +162,20 @@ function reduceComponents( return React.cloneElement(c, newProps) } } - if (process.env.NODE_ENV === 'development') { + if ( + process.env.NODE_ENV === 'development' && + process.env.__NEXT_CONCURRENT_FEATURES + ) { // omit JSON-LD structured data snippets from the warning if (c.type === 'script' && c.props['type'] !== 'application/ld+json') { const srcMessage = c.props['src'] ? ` + + +

Streaming Head

+ +) diff --git a/test/integration/react-streaming-and-server-components/test/index.test.js b/test/integration/react-streaming-and-server-components/test/index.test.js index d93f233a1aab0..527a17c875179 100644 --- a/test/integration/react-streaming-and-server-components/test/index.test.js +++ b/test/integration/react-streaming-and-server-components/test/index.test.js @@ -151,7 +151,7 @@ describe('Edge runtime - prod', () => { }) basic(context, { env: 'prod' }) - streaming(context) + streaming(context, { env: 'prod' }) rsc(context, { runtime: 'edge', env: 'prod' }) }) @@ -184,14 +184,14 @@ describe('Edge runtime - dev', () => { }) basic(context, { env: 'dev' }) - streaming(context) + streaming(context, { env: 'dev' }) rsc(context, { runtime: 'edge', env: 'dev' }) }) const nodejsRuntimeBasicSuite = { runTests: (context, env) => { basic(context, { env }) - streaming(context) + streaming(context, { env }) rsc(context, { runtime: 'nodejs' }) if (env === 'prod') { diff --git a/test/integration/react-streaming-and-server-components/test/streaming.js b/test/integration/react-streaming-and-server-components/test/streaming.js index 31b6e62591492..edfeccebdcd87 100644 --- a/test/integration/react-streaming-and-server-components/test/streaming.js +++ b/test/integration/react-streaming-and-server-components/test/streaming.js @@ -1,6 +1,6 @@ /* eslint-env jest */ import webdriver from 'next-webdriver' -import { fetchViaHTTP } from 'next-test-utils' +import { fetchViaHTTP, waitFor } from 'next-test-utils' async function resolveStreamResponse(response, onData) { let result = '' @@ -16,7 +16,7 @@ async function resolveStreamResponse(response, onData) { return result } -export default function (context) { +export default function (context, { env }) { it('should support streaming for fizz response', async () => { await fetchViaHTTP(context.appPort, '/streaming', null, {}).then( async (response) => { @@ -99,4 +99,82 @@ export default function (context) { expect(result).toMatch(/<\/body><\/html>/) }) }) + + if (env === 'dev') { + it('should warn when stylesheets or scripts are in head', async () => { + let browser + try { + browser = await webdriver(context.appPort, '/head') + + await browser.waitForElementByCss('h1') + await waitFor(1000) + const browserLogs = await browser.log('browser') + let foundStyles = false + let foundScripts = false + const logs = [] + browserLogs.forEach(({ message }) => { + if (message.includes('Do not add stylesheets using next/head')) { + foundStyles = true + logs.push(message) + } + if (message.includes('Do not add