From 05bdd715a8513881902cafc45697e2024834783f Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 10 Nov 2022 03:16:59 +0100 Subject: [PATCH] Use import to load page and layout (#42325) Fixes #42534 * Use eager `import()` to load page/layout to avoid esm module resolution error, eager is to make sure all the sub resources like css are also included * Fix layer detection, should use `module.layer` directly since `module.resourceResolveData` is not alway presented. It lost when switching from `require()` to `import()` for page/layout component ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` --- packages/next/build/webpack-config.ts | 6 +----- .../build/webpack/loaders/next-app-loader.ts | 20 +++++++++---------- .../plugins/flight-client-entry-plugin.ts | 6 ++---- packages/next/server/app-render.tsx | 4 ++-- test/e2e/app-dir/app-alias.test.ts | 3 +++ test/e2e/app-dir/app-alias/next.config.js | 2 +- test/e2e/app-dir/app-alias/package.json | 3 +++ 7 files changed, 22 insertions(+), 22 deletions(-) create mode 100644 test/e2e/app-dir/app-alias/package.json diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 7d22744826b1559..ce9c91b3db12a3c 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -921,11 +921,7 @@ export default async function getBaseWebpackConfig( ...customRootAliases, ...(pagesDir ? { [PAGES_DIR_ALIAS]: pagesDir } : {}), - ...(appDir - ? { - [APP_DIR_ALIAS]: appDir, - } - : {}), + ...(appDir ? { [APP_DIR_ALIAS]: appDir } : {}), [ROOT_DIR_ALIAS]: dir, [DOT_NEXT_ALIAS]: distDir, ...(isClient || isEdgeServer ? getOptimizedAliases() : {}), diff --git a/packages/next/build/webpack/loaders/next-app-loader.ts b/packages/next/build/webpack/loaders/next-app-loader.ts index 7f4f6c58c617abe..86c3aefab317c96 100644 --- a/packages/next/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/build/webpack/loaders/next-app-loader.ts @@ -8,7 +8,7 @@ import { verifyRootLayout } from '../../../lib/verifyRootLayout' import * as Log from '../../../build/output/log' import { APP_DIR_ALIAS } from '../../../lib/constants' -export const FILE_TYPES = { +const FILE_TYPES = { layout: 'layout', template: 'template', error: 'error', @@ -68,7 +68,7 @@ async function createTreeCodeFromPath({ // Use '' for segment as it's the page. There can't be a segment called '' so this is the safest way to add it. props[parallelKey] = `['', {}, { - page: [() => require(${JSON.stringify( + page: [() => import(/* webpackMode: "eager" */ ${JSON.stringify( resolvedPagePath )}), ${JSON.stringify(resolvedPagePath)}]}]` continue @@ -106,7 +106,7 @@ async function createTreeCodeFromPath({ if (filePath === undefined) { return '' } - return `'${file}': [() => require(${JSON.stringify( + return `'${file}': [() => import(/* webpackMode: "eager" */ ${JSON.stringify( filePath )}), ${JSON.stringify(filePath)}],` }) @@ -245,16 +245,16 @@ const nextAppLoader: webpack.LoaderDefinitionFunction<{ export ${treeCode} export const pages = ${JSON.stringify(pages)} - export const AppRouter = require('next/dist/client/components/app-router.js').default - export const LayoutRouter = require('next/dist/client/components/layout-router.js').default - export const RenderFromTemplateContext = require('next/dist/client/components/render-from-template-context.js').default + export { default as AppRouter } from 'next/dist/client/components/app-router' + export { default as LayoutRouter } from 'next/dist/client/components/layout-router' + export { default as RenderFromTemplateContext } from 'next/dist/client/components/render-from-template-context' - export const staticGenerationAsyncStorage = require('next/dist/client/components/static-generation-async-storage').staticGenerationAsyncStorage - export const requestAsyncStorage = require('next/dist/client/components/request-async-storage.js').requestAsyncStorage + export { staticGenerationAsyncStorage } from 'next/dist/client/components/static-generation-async-storage' + export { requestAsyncStorage } from 'next/dist/client/components/request-async-storage' - export const serverHooks = require('next/dist/client/components/hooks-server-context.js') + export * as serverHooks from 'next/dist/client/components/hooks-server-context' - export const renderToReadableStream = require('next/dist/compiled/react-server-dom-webpack/server.browser').renderToReadableStream + export { renderToReadableStream } from 'next/dist/compiled/react-server-dom-webpack/server.browser' export const __next_app_webpack_require__ = __webpack_require__ ` diff --git a/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts b/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts index 2ddbcb163343473..2df42a8d9053362 100644 --- a/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts +++ b/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts @@ -85,13 +85,11 @@ export class FlightClientEntryPlugin { const recordModule = (modId: string, mod: any) => { const modResource = mod.resourceResolveData?.path || mod.resource - if ( - mod.resourceResolveData?.context?.issuerLayer !== - WEBPACK_LAYERS.client - ) { + if (mod.layer !== WEBPACK_LAYERS.client) { return } + // Check mod resource to exclude the empty resource module like virtual module created by next-flight-client-entry-loader if (typeof modId !== 'undefined' && modResource) { // Note that this isn't that reliable as webpack is still possible to assign // additional queries to make sure there's no conflict even using the `named` diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 59a38fe167cd608..b42541e85ec7fda 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -915,7 +915,7 @@ export async function renderToHTMLOrFlight( } if (head) { - const Head = await interopDefault(head[0]()) + const Head = await interopDefault(await head[0]()) return } @@ -993,7 +993,7 @@ export async function renderToHTMLOrFlight( /> )) : null - const Comp = await interopDefault(getComponent()) + const Comp = await interopDefault(await getComponent()) return [Comp, styles] } diff --git a/test/e2e/app-dir/app-alias.test.ts b/test/e2e/app-dir/app-alias.test.ts index 6180195a2f464f7..3b8c434d05079e7 100644 --- a/test/e2e/app-dir/app-alias.test.ts +++ b/test/e2e/app-dir/app-alias.test.ts @@ -22,6 +22,9 @@ describe('app-dir alias handling', () => { '@types/react': 'latest', '@types/node': 'latest', }, + packageJson: { + type: 'module', + }, }) }) afterAll(() => next.destroy()) diff --git a/test/e2e/app-dir/app-alias/next.config.js b/test/e2e/app-dir/app-alias/next.config.js index cfa3ac3d7aa94b3..3d6be3a00f6e38c 100644 --- a/test/e2e/app-dir/app-alias/next.config.js +++ b/test/e2e/app-dir/app-alias/next.config.js @@ -1,4 +1,4 @@ -module.exports = { +export default { experimental: { appDir: true, }, diff --git a/test/e2e/app-dir/app-alias/package.json b/test/e2e/app-dir/app-alias/package.json new file mode 100644 index 000000000000000..3dbc1ca591c0557 --- /dev/null +++ b/test/e2e/app-dir/app-alias/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +}