From a23fe4d94088248480805f9f05a7534400614dc6 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Tue, 16 Aug 2022 19:01:03 +0200 Subject: [PATCH 1/4] add next-flight-css-dev-loader --- .../build/webpack/config/blocks/css/index.ts | 35 +++++++++++++------ .../next-flight-client-entry-loader.ts | 6 +++- .../loaders/next-flight-css-dev-loader.ts | 21 +++++++++++ packages/next/server/app-render.tsx | 19 +++++----- .../next/server/node-web-streams-helper.ts | 7 +--- 5 files changed, 61 insertions(+), 27 deletions(-) create mode 100644 packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts diff --git a/packages/next/build/webpack/config/blocks/css/index.ts b/packages/next/build/webpack/config/blocks/css/index.ts index 1177e746a649..2585a2202262 100644 --- a/packages/next/build/webpack/config/blocks/css/index.ts +++ b/packages/next/build/webpack/config/blocks/css/index.ts @@ -275,16 +275,31 @@ export const css = curry(async function css( } if (ctx.isServer) { - fns.push( - loader({ - oneOf: [ - markRemovable({ - test: [regexCssGlobal, regexSassGlobal], - use: require.resolve('next/dist/compiled/ignore-loader'), - }), - ], - }) - ) + if (ctx.experimental.appDir && !ctx.isProduction) { + fns.push( + loader({ + oneOf: [ + markRemovable({ + test: [regexCssGlobal, regexSassGlobal], + use: require.resolve( + '../../../loaders/next-flight-css-dev-loader' + ), + }), + ], + }) + ) + } else { + fns.push( + loader({ + oneOf: [ + markRemovable({ + test: [regexCssGlobal, regexSassGlobal], + use: require.resolve('next/dist/compiled/ignore-loader'), + }), + ], + }) + ) + } } else { fns.push( loader({ diff --git a/packages/next/build/webpack/loaders/next-flight-client-entry-loader.ts b/packages/next/build/webpack/loaders/next-flight-client-entry-loader.ts index e30d5037569d..f168350122d8 100644 --- a/packages/next/build/webpack/loaders/next-flight-client-entry-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-client-entry-loader.ts @@ -21,7 +21,11 @@ export default async function transformSource(this: any): Promise { requests // Filter out css files on the server .filter((request) => (isServer ? !request.endsWith('.css') : true)) - .map((request) => `import(/* webpackMode: "eager" */ '${request}')`) + .map((request) => + request.endsWith('.css') + ? `(() => import(/* webpackMode: "lazy" */ '${request}'))` + : `import(/* webpackMode: "eager" */ '${request}')` + ) .join(';\n') + ` export const __next_rsc__ = { diff --git a/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts b/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts new file mode 100644 index 000000000000..e619d26dc6c1 --- /dev/null +++ b/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts @@ -0,0 +1,21 @@ +import { webpack } from 'next/dist/compiled/webpack/webpack' + +/** + * For server-side CSS imports, we need to ignore the actual module content but + * still trigger the hot-reloading diff mechanism. So here we put the content + * inside a comment. + */ + +const NextServerCSSLoader: webpack.loader.Loader = function ( + this: any, + source: string | Buffer +) { + this.cacheable && this.cacheable() + + return `export default "${(typeof source === 'string' + ? Buffer.from(source) + : source + ).toString('hex')}"` +} + +export default NextServerCSSLoader diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index af038ae9d27e..9afb7138ee8a 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -596,15 +596,15 @@ export async function renderToHTMLOrFlight( firstItem, rootLayoutIncluded, serverStylesheets, - }: // parentSegmentPath, - { + parentSegmentPath, + }: { createSegmentPath: CreateSegmentPath loaderTree: LoaderTree parentParams: { [key: string]: any } rootLayoutIncluded?: boolean firstItem?: boolean serverStylesheets: { [file: string]: string[] } - // parentSegmentPath: string + parentSegmentPath: string }): Promise<{ Component: React.ComponentType }> => { const Loading = loading ? await interopDefault(loading()) : undefined const isLayout = typeof layout !== 'undefined' @@ -624,9 +624,9 @@ export async function renderToHTMLOrFlight( const rootLayoutIncludedAtThisLevelOrAbove = rootLayoutIncluded || rootLayoutAtThisLevel - // const cssSegmentPath = - // !parentSegmentPath && !segment ? '' : parentSegmentPath + '/' + segment - // const stylesheets = serverStylesheets[cssSegmentPath] + const cssSegmentPath = + !parentSegmentPath && !segment ? '' : parentSegmentPath + '/' + segment + const stylesheets = serverStylesheets[cssSegmentPath] /** * Check if the current layout/page is a client component @@ -830,11 +830,11 @@ export async function renderToHTMLOrFlight( return ( <> - {/* {stylesheets + {stylesheets ? stylesheets.map((href) => ( )) - : null} */} + : null} generateStaticHTML: boolean flushEffectHandler?: () => string flushEffectsToHead: boolean - initialStylesheets?: string[] } ): Promise> { const closeTag = '' @@ -291,14 +289,11 @@ export async function continueFromInitialStream( dataStream ? createInlineDataStream(dataStream) : null, suffixUnclosed != null ? createSuffixStream(closeTag) : null, createHeadInjectionTransformStream(() => { - const inlineStyleLinks = (initialStylesheets || []) - .map((href) => ``) - .join('') // TODO-APP: Inject flush effects to end of head in app layout rendering, to avoid // hydration errors. Remove this once it's ready to be handled by react itself. const flushEffectsContent = flushEffectHandler && flushEffectsToHead ? flushEffectHandler() : '' - return inlineStyleLinks + flushEffectsContent + return flushEffectsContent }), ].filter(nonNullable) From 82492917f30ec040f42af776058303944147971c Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 17 Aug 2022 11:37:55 +0200 Subject: [PATCH 2/4] upgrade react and react-dom --- package.json | 4 ++-- packages/next/server/app-render.tsx | 8 ++++++- pnpm-lock.yaml | 24 +++++++++---------- .../app-dir/app/app/css/css-page/style.css | 2 +- test/e2e/app-dir/app/app/css/style.css | 2 +- test/e2e/app-dir/app/app/style.css | 3 +++ 6 files changed, 26 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index cea308b687be..7a13a9ee7910 100644 --- a/package.json +++ b/package.json @@ -177,8 +177,8 @@ "react-17": "npm:react@17.0.2", "react-dom": "18.2.0", "react-dom-17": "npm:react-dom@17.0.2", - "react-dom-exp": "npm:react-dom@0.0.0-experimental-4cd788aef-20220630", - "react-exp": "npm:react@0.0.0-experimental-4cd788aef-20220630", + "react-dom-exp": "npm:react-dom@0.0.0-experimental-6ef466c68-20220816", + "react-exp": "npm:react@0.0.0-experimental-6ef466c68-20220816", "react-ssr-prepass": "1.0.8", "react-virtualized": "9.22.3", "relay-compiler": "13.0.2", diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 0d30a4bf9851..c103daf63ae7 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -826,7 +826,13 @@ export async function renderToHTMLOrFlight( <> {stylesheets ? stylesheets.map((href) => ( - + )) : null} =0.10.0'} dependencies: loose-envify: 1.4.0 @@ -19226,8 +19226,8 @@ packages: xmlchars: 2.2.0 dev: true - /scheduler/0.0.0-experimental-4cd788aef-20220630: - resolution: {integrity: sha512-ywbmX5l/JpTWQbUy9IcHO0fzaHGL/IIgM5lj1IsJA0KYn3IZx6fJkXiVRFFY1GuXAsLsalniC+SM5NLjUED8fg==} + /scheduler/0.0.0-experimental-6ef466c68-20220816: + resolution: {integrity: sha512-3d6wgYQA2rFc62tqtEPJdnd0rxfq8VTk8Toj3v7LEdZ4vB3pACNxthU3E3WPDtXbHAUQ+liMgFwuXxeE+8aDhg==} dependencies: loose-envify: 1.4.0 dev: true diff --git a/test/e2e/app-dir/app/app/css/css-page/style.css b/test/e2e/app-dir/app/app/css/css-page/style.css index 61083abf180c..adc68fa6a4df 100644 --- a/test/e2e/app-dir/app/app/css/css-page/style.css +++ b/test/e2e/app-dir/app/app/css/css-page/style.css @@ -1,3 +1,3 @@ h1 { - color: blueviolet; + color: red; } diff --git a/test/e2e/app-dir/app/app/css/style.css b/test/e2e/app-dir/app/app/css/style.css index efd81fda0528..26994cdddaee 100644 --- a/test/e2e/app-dir/app/app/css/style.css +++ b/test/e2e/app-dir/app/app/css/style.css @@ -1,3 +1,3 @@ .server-css { - color: green; + color: blue; } diff --git a/test/e2e/app-dir/app/app/style.css b/test/e2e/app-dir/app/app/style.css index e69de29bb2d1..0b8fbd008481 100644 --- a/test/e2e/app-dir/app/app/style.css +++ b/test/e2e/app-dir/app/app/style.css @@ -0,0 +1,3 @@ +body { + font-size: xx-large; +} From abc39a4f8bb9176d2cfc525e08ebc1d92f05e545 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 17 Aug 2022 11:39:09 +0200 Subject: [PATCH 3/4] fix type error --- .../build/webpack/loaders/next-flight-css-dev-loader.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts b/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts index e619d26dc6c1..d2f9ab521466 100644 --- a/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts @@ -1,15 +1,10 @@ -import { webpack } from 'next/dist/compiled/webpack/webpack' - /** * For server-side CSS imports, we need to ignore the actual module content but * still trigger the hot-reloading diff mechanism. So here we put the content * inside a comment. */ -const NextServerCSSLoader: webpack.loader.Loader = function ( - this: any, - source: string | Buffer -) { +const NextServerCSSLoader = function (this: any, source: string | Buffer) { this.cacheable && this.cacheable() return `export default "${(typeof source === 'string' From 9d527b4fc2da465a177b198a6813da40d50ba70b Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 17 Aug 2022 12:29:29 +0200 Subject: [PATCH 4/4] add comment --- packages/next/server/app-render.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index c103daf63ae7..2c221e3e75e7 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -829,6 +829,9 @@ export async function renderToHTMLOrFlight(