diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts
index b9705c2d0a964a8..7ab24a2f4135f53 100644
--- a/packages/next/build/entries.ts
+++ b/packages/next/build/entries.ts
@@ -17,7 +17,9 @@ type PagesMapping = {
export function createPagesMapping(
pagePaths: string[],
- extensions: string[]
+ extensions: string[],
+ isWebpack5: boolean,
+ isDev: boolean
): PagesMapping {
const previousPages: PagesMapping = {}
const pages: PagesMapping = pagePaths.reduce(
@@ -45,10 +47,18 @@ export function createPagesMapping(
{}
)
- pages['/_app'] = pages['/_app'] || 'next/dist/pages/_app'
- pages['/_error'] = pages['/_error'] || 'next/dist/pages/_error'
- pages['/_document'] = pages['/_document'] || 'next/dist/pages/_document'
-
+ // we alias these in development and allow webpack to
+ // allow falling back to the correct source file so
+ // that HMR can work properly when a file is added/removed
+ if (isWebpack5 && isDev) {
+ pages['/_app'] = `${PAGES_DIR_ALIAS}/_app`
+ pages['/_error'] = `${PAGES_DIR_ALIAS}/_error`
+ pages['/_document'] = `${PAGES_DIR_ALIAS}/_document`
+ } else {
+ pages['/_app'] = pages['/_app'] || 'next/dist/pages/_app'
+ pages['/_error'] = pages['/_error'] || 'next/dist/pages/_error'
+ pages['/_document'] = pages['/_document'] || 'next/dist/pages/_document'
+ }
return pages
}
diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts
index 294bdcf1e621e65..bc8657328fa3150 100644
--- a/packages/next/build/index.ts
+++ b/packages/next/build/index.ts
@@ -255,7 +255,9 @@ export default async function build(
const mappedPages = nextBuildSpan
.traceChild('create-pages-mapping')
- .traceFn(() => createPagesMapping(pagePaths, config.pageExtensions))
+ .traceFn(() =>
+ createPagesMapping(pagePaths, config.pageExtensions, isWebpack5, false)
+ )
const entrypoints = nextBuildSpan
.traceChild('create-entrypoints')
.traceFn(() =>
diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts
index 881b5169ae8f8fd..12106b2e459581e 100644
--- a/packages/next/build/webpack-config.ts
+++ b/packages/next/build/webpack-config.ts
@@ -28,7 +28,6 @@ import {
} from '../shared/lib/constants'
import { execOnce } from '../shared/lib/utils'
import { NextConfigComplete } from '../server/config-shared'
-import { findPageFile } from '../server/lib/find-page-file'
import { WebpackEntrypoints } from './entries'
import * as Log from './output/log'
import { build as buildConfiguration } from './webpack/config'
@@ -413,28 +412,6 @@ export default async function getBaseWebpackConfig(
resolvedBaseUrl = path.resolve(dir, jsConfig.compilerOptions.baseUrl)
}
- let customAppFile: string | null = await findPageFile(
- pagesDir,
- '/_app',
- config.pageExtensions
- )
- let customAppFileExt = customAppFile ? path.extname(customAppFile) : null
- if (customAppFile) {
- customAppFile = path.resolve(path.join(pagesDir, customAppFile))
- }
-
- let customDocumentFile: string | null = await findPageFile(
- pagesDir,
- '/_document',
- config.pageExtensions
- )
- let customDocumentFileExt = customDocumentFile
- ? path.extname(customDocumentFile)
- : null
- if (customDocumentFile) {
- customDocumentFile = path.resolve(path.join(pagesDir, customDocumentFile))
- }
-
function getReactProfilingInProduction() {
if (reactProductionProfiling) {
return {
@@ -444,6 +421,9 @@ export default async function getBaseWebpackConfig(
}
}
+ // tell webpack where to look for _app and _document
+ // using aliases to allow falling back to the default
+ // version when removed or not present
const clientResolveRewrites = require.resolve(
'../shared/lib/router/utils/resolve-rewrites'
)
@@ -451,6 +431,34 @@ export default async function getBaseWebpackConfig(
'../shared/lib/router/utils/resolve-rewrites-noop'
)
+ const customAppAliases: { [key: string]: string[] } = {}
+ const customErrorAlias: { [key: string]: string[] } = {}
+ const customDocumentAliases: { [key: string]: string[] } = {}
+
+ if (dev && isWebpack5) {
+ customAppAliases[`${PAGES_DIR_ALIAS}/_app`] = [
+ ...config.pageExtensions.reduce((prev, ext) => {
+ prev.push(path.join(pagesDir, `_app.${ext}`))
+ return prev
+ }, [] as string[]),
+ 'next/dist/pages/_app.js',
+ ]
+ customAppAliases[`${PAGES_DIR_ALIAS}/_error`] = [
+ ...config.pageExtensions.reduce((prev, ext) => {
+ prev.push(path.join(pagesDir, `_error.${ext}`))
+ return prev
+ }, [] as string[]),
+ 'next/dist/pages/_error.js',
+ ]
+ customDocumentAliases[`${PAGES_DIR_ALIAS}/_document`] = [
+ ...config.pageExtensions.reduce((prev, ext) => {
+ prev.push(path.join(pagesDir, `_document.${ext}`))
+ return prev
+ }, [] as string[]),
+ 'next/dist/pages/_document.js',
+ ]
+ }
+
const resolveConfig = {
// Disable .mjs for node_modules bundling
extensions: isServer
@@ -477,25 +485,9 @@ export default async function getBaseWebpackConfig(
alias: {
next: NEXT_PROJECT_ROOT,
- // fallback to default _app when custom is removed
- ...(dev && customAppFileExt && isWebpack5
- ? {
- [`${PAGES_DIR_ALIAS}/_app${customAppFileExt}`]: [
- path.join(pagesDir, `_app${customAppFileExt}`),
- 'next/dist/pages/_app.js',
- ],
- }
- : {}),
-
- // fallback to default _document when custom is removed
- ...(dev && customDocumentFileExt && isWebpack5
- ? {
- [`${PAGES_DIR_ALIAS}/_document${customDocumentFileExt}`]: [
- path.join(pagesDir, `_document${customDocumentFileExt}`),
- 'next/dist/pages/_document.js',
- ],
- }
- : {}),
+ ...customAppAliases,
+ ...customErrorAlias,
+ ...customDocumentAliases,
[PAGES_DIR_ALIAS]: pagesDir,
[DOT_NEXT_ALIAS]: distDir,
@@ -1567,7 +1559,7 @@ export default async function getBaseWebpackConfig(
webpackConfig = await buildConfiguration(webpackConfig, {
rootDirectory: dir,
- customAppFile,
+ customAppFile: new RegExp(path.join(pagesDir, `_app`)),
isDevelopment: dev,
isServer,
assetPrefix: config.assetPrefix || '',
diff --git a/packages/next/build/webpack/config/blocks/css/index.ts b/packages/next/build/webpack/config/blocks/css/index.ts
index 02f44cf5c70a58e..56dae4c11841d3e 100644
--- a/packages/next/build/webpack/config/blocks/css/index.ts
+++ b/packages/next/build/webpack/config/blocks/css/index.ts
@@ -1,5 +1,4 @@
import curry from 'next/dist/compiled/lodash.curry'
-import path from 'path'
import { webpack, isWebpack5 } from 'next/dist/compiled/webpack/webpack'
import MiniCssExtractPlugin from '../../../plugins/mini-css-extract-plugin'
import { loader, plugin } from '../../helpers'
@@ -275,10 +274,7 @@ export const css = curry(async function css(
use: {
loader: 'error-loader',
options: {
- reason: getGlobalImportError(
- ctx.customAppFile &&
- path.relative(ctx.rootDirectory, ctx.customAppFile)
- ),
+ reason: getGlobalImportError(),
},
},
},
diff --git a/packages/next/build/webpack/config/blocks/css/messages.ts b/packages/next/build/webpack/config/blocks/css/messages.ts
index 787d46750e5ec32..c48912399ed3fbf 100644
--- a/packages/next/build/webpack/config/blocks/css/messages.ts
+++ b/packages/next/build/webpack/config/blocks/css/messages.ts
@@ -1,12 +1,12 @@
import chalk from 'chalk'
-export function getGlobalImportError(file: string | null) {
+export function getGlobalImportError() {
return `Global CSS ${chalk.bold(
'cannot'
)} be imported from files other than your ${chalk.bold(
'Custom index page custom _app
custom _document
+ +