Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prebundle react for appDir #41337

Merged
merged 44 commits into from Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
acc9a25
Pre copy react
huozhi Oct 10, 2022
0962b64
alias react in all dirs
huozhi Oct 10, 2022
1178a1a
change webpack aliascondition
huozhi Oct 10, 2022
2fd5ea1
add require hook
huozhi Oct 11, 2022
8e14bf1
update precompiled
huozhi Oct 11, 2022
99eea31
fix compiled
huozhi Oct 11, 2022
a50d7f8
fix bundling and aliasing
shuding Oct 11, 2022
cea0cdf
Merge branch 'canary' into app-prebundle-react
huozhi Oct 11, 2022
7f65e0a
Fix typing and jsx-runtime alias
huozhi Oct 12, 2022
addcaa8
fix lint
huozhi Oct 12, 2022
6a6faf4
Merge branch 'canary' into app-prebundle-react
huozhi Oct 12, 2022
a2ee8b2
update precompile
huozhi Oct 12, 2022
9ca203e
conditional require hooks
huozhi Oct 12, 2022
44eeb65
fix loadRequireHook call
huozhi Oct 12, 2022
3670d1d
apply override
huozhi Oct 14, 2022
fd5bf3c
Merge branch 'canary' into app-prebundle-react
huozhi Oct 14, 2022
d9bbc08
hard code import path for app-render
huozhi Oct 14, 2022
3ca7ff6
fix test for oneOf
huozhi Oct 14, 2022
8431c9c
use env for require hook and alias react-dom
huozhi Oct 15, 2022
0e5ddcc
Update react
huozhi Oct 15, 2022
dd92451
Merge branch 'canary' into app-prebundle-react
huozhi Oct 15, 2022
ba6338a
simplify react overriding and update flight
huozhi Oct 15, 2022
79afa9f
fix lock file
huozhi Oct 15, 2022
0628a32
update compiled pkgs
huozhi Oct 15, 2022
770347d
fix compiled rsc renderer and alias react by default in react hook
huozhi Oct 15, 2022
04efb61
fix react and react-dom resolution
huozhi Oct 15, 2022
1985692
revert pnpm version
huozhi Oct 15, 2022
b3f735f
revert default alias and update compiled
huozhi Oct 16, 2022
cf1f39c
fix pre-compiled and resolving
huozhi Oct 17, 2022
65f9259
fix externals for rsc renderer and stick react-server conditon
huozhi Oct 17, 2022
0f898b8
revert changes
huozhi Oct 17, 2022
939f90d
remove extra overriding
huozhi Oct 17, 2022
e93630f
external react-dom for servr renderer
huozhi Oct 17, 2022
db18aa5
fix dev mode and edge react resolution
huozhi Oct 17, 2022
d304670
merge conditions
huozhi Oct 17, 2022
de79698
use react stub
huozhi Oct 18, 2022
e2c5ff8
Merge branch 'canary' into app-prebundle-react
huozhi Oct 18, 2022
50a7755
revert test page
huozhi Oct 18, 2022
fc6e0f0
alias subset, use stub fork for server
huozhi Oct 18, 2022
da2f176
Merge branch 'canary' into app-prebundle-react
ijjk Oct 18, 2022
19a6e5d
update compiled
ijjk Oct 18, 2022
5cbb0f5
dont ncc react
huozhi Oct 18, 2022
4802456
copy react react-dom assets
huozhi Oct 18, 2022
9dca3b9
update test and fix lint
huozhi Oct 18, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 0 additions & 4 deletions package.json
Expand Up @@ -40,11 +40,9 @@
"next-with-deps": "./scripts/next-with-deps.sh",
"next": "node --trace-deprecation --enable-source-maps packages/next/dist/bin/next",
"next-react-17": "__NEXT_REACT_CHANNEL=17 node --trace-deprecation --enable-source-maps -r ./test/lib/react-channel-require-hook.js packages/next/dist/bin/next",
"next-react-exp": "__NEXT_REACT_CHANNEL=exp node --trace-deprecation --enable-source-maps -r ./test/lib/react-channel-require-hook.js packages/next/dist/bin/next",
"next-no-sourcemaps": "node --trace-deprecation packages/next/dist/bin/next",
"clean-trace-jaeger": "rm -rf test/integration/basic/.next && TRACE_TARGET=JAEGER node --trace-deprecation --enable-source-maps packages/next/dist/bin/next build test/integration/basic",
"debug": "node --inspect packages/next/dist/bin/next",
"debug-react-exp": "__NEXT_REACT_CHANNEL=exp node --inspect --trace-deprecation --enable-source-maps -r ./test/lib/react-channel-require-hook.js packages/next/dist/bin/next",
"postinstall": "git config feature.manyFiles true && node scripts/install-native.mjs",
"version": "pnpm install && git add pnpm-lock.yaml",
"prepare": "husky install"
Expand Down Expand Up @@ -183,8 +181,6 @@
"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-a8c16a004-20221012",
"react-exp": "npm:react@0.0.0-experimental-a8c16a004-20221012",
"react-ssr-prepass": "1.0.8",
"react-virtualized": "9.22.3",
"relay-compiler": "13.0.2",
Expand Down
3 changes: 3 additions & 0 deletions packages/next/build/index.ts
Expand Up @@ -300,6 +300,9 @@ export default async function build(

const publicDir = path.join(dir, 'public')
const isAppDirEnabled = !!config.experimental.appDir
if (isAppDirEnabled) {
process.env.HAS_APP_DIR = '1'
}
const { pagesDir, appDir } = findPagesDir(dir, isAppDirEnabled)

const hasPublicDir = await fileExists(publicDir)
Expand Down
12 changes: 9 additions & 3 deletions packages/next/build/utils.ts
@@ -1,7 +1,6 @@
import type { NextConfigComplete } from '../server/config-shared'

import '../server/node-polyfill-fetch'
import loadRequireHook from '../build/webpack/require-hook'
import chalk from 'next/dist/compiled/chalk'
import getGzipSize from 'next/dist/compiled/gzip-size'
import textTable from 'next/dist/compiled/text-table'
Expand Down Expand Up @@ -49,6 +48,15 @@ import { denormalizePagePath } from '../shared/lib/page-path/denormalize-page-pa
import { normalizePagePath } from '../shared/lib/page-path/normalize-page-path'
import { AppBuildManifest } from './webpack/plugins/app-build-manifest-plugin'
import { getRuntimeContext } from '../server/web/sandbox'
import {
loadRequireHook,
overrideBuiltInReactPackages,
} from './webpack/require-hook'

loadRequireHook()
if (process.env.HAS_APP_DIR) {
overrideBuiltInReactPackages()
}

export type ROUTER_TYPE = 'pages' | 'app'

Expand All @@ -69,8 +77,6 @@ const fsStat = (file: string) => {
return (fileStats[file] = fileSize(file))
}

loadRequireHook()

export function unique<T>(main: ReadonlyArray<T>, sub: ReadonlyArray<T>): T[] {
return [...new Set([...main, ...sub])]
}
Expand Down
181 changes: 112 additions & 69 deletions packages/next/build/webpack-config.ts
Expand Up @@ -2,7 +2,7 @@ import ReactRefreshWebpackPlugin from 'next/dist/compiled/@next/react-refresh-ut
import chalk from 'next/dist/compiled/chalk'
import crypto from 'crypto'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import path, { dirname, join as pathJoin, relative as relativePath } from 'path'
import path, { join as pathJoin, relative as relativePath } from 'path'
import { escapeStringRegexp } from '../shared/lib/escape-regexp'
import {
DOT_NEXT_ALIAS,
Expand Down Expand Up @@ -89,9 +89,6 @@ const nodePathList = (process.env.NODE_PATH || '')
.split(process.platform === 'win32' ? ';' : ':')
.filter((p) => !!p)

const reactDir = dirname(require.resolve('react/package.json'))
const reactDomDir = dirname(require.resolve('react-dom/package.json'))

const watchOptions = Object.freeze({
aggregateTimeout: 5,
ignored: ['**/.git/**', '**/.next/**'],
Expand Down Expand Up @@ -125,6 +122,12 @@ function isResourceInPackages(resource: string, packageNames?: string[]) {
)
}

const builtInReactImports = [
'react',
'react/jsx-runtime',
'next/dist/compiled/react-server-dom-webpack/writer.browser.server',
]

export function getDefineEnv({
dev,
config,
Expand Down Expand Up @@ -573,11 +576,6 @@ export default async function getBaseWebpackConfig(
'`experimental.runtime` requires React 18 to be installed.'
)
}
if (hasAppDir) {
throw new Error(
'`experimental.appDir` requires React 18 to be installed.'
)
}
}
}

Expand Down Expand Up @@ -869,11 +867,19 @@ export default async function getBaseWebpackConfig(

next: NEXT_PROJECT_ROOT,

react: reactDir,
'react-dom$': reactDomDir,
'react-dom/server$': `${reactDomDir}/server`,
'react-dom/server.browser$': `${reactDomDir}/server.browser`,
'react-dom/client$': `${reactDomDir}/client`,
...(hasServerComponents
? {
// For react and react-dom, alias them dynamically for server layer
// and others in the loaders configuration
'react-dom/client$': 'next/dist/compiled/react-dom/client',
'react-dom/server$': 'next/dist/compiled/react-dom/server',
'react-dom/server.browser$':
'next/dist/compiled/react-dom/server.browser',
'react/jsx-dev-runtime$':
'next/dist/compiled/react/jsx-dev-runtime',
'react/jsx-runtime$': 'next/dist/compiled/react/jsx-runtime',
}
: undefined),

'styled-jsx/style$': require.resolve(`styled-jsx/style`),
'styled-jsx$': require.resolve(`styled-jsx`),
Expand Down Expand Up @@ -1035,12 +1041,7 @@ export default async function getBaseWebpackConfig(

// Special internal modules that must be bundled for Server Components.
if (layer === WEBPACK_LAYERS.server) {
if (
request === 'react' ||
request === 'react/jsx-runtime' ||
request ===
'next/dist/compiled/react-server-dom-webpack/writer.browser.server'
) {
if (builtInReactImports.includes(request)) {
return
}
}
Expand Down Expand Up @@ -1514,47 +1515,6 @@ export default async function getBaseWebpackConfig(
},
module: {
rules: [
...(hasAppDir && !isClient && !isEdgeServer
? [
{
issuerLayer: WEBPACK_LAYERS.server,
test: (req: string) => {
// If it's not a source code file, or has been opted out of
// bundling, don't resolve it.
if (
!codeCondition.test.test(req) ||
isResourceInPackages(
req,
config.experimental.serverComponentsExternalPackages
)
) {
return false
}

return true
},
resolve: process.env.__NEXT_REACT_CHANNEL
? {
conditionNames: ['react-server', 'node', 'require'],
alias: {
react: `react-${process.env.__NEXT_REACT_CHANNEL}`,
'react-dom': `react-dom-${process.env.__NEXT_REACT_CHANNEL}`,
},
}
: {
conditionNames: ['react-server', 'node', 'require'],
alias: {
// If missing the alias override here, the default alias will be used which aliases
// react to the direct file path, not the package name. In that case the condition
// will be ignored completely.
react: 'react',
'react-dom': 'react-dom',
},
},
},
]
: []),

// TODO: FIXME: do NOT webpack 5 support with this
// x-ref: https://github.com/webpack/webpack/issues/11467
...(!config.experimental.fullySpecified
Expand All @@ -1578,30 +1538,47 @@ export default async function getBaseWebpackConfig(
},
]
: []),
// Alias `next/dynamic` to React.lazy implementation for RSC
...(hasServerComponents
...(hasAppDir && !isClient
? [
{
test: codeCondition.test,
include: [appDir],
issuerLayer: WEBPACK_LAYERS.server,
test: (req: string) => {
// If it's not a source code file, or has been opted out of
// bundling, don't resolve it.
if (
!codeCondition.test.test(req) ||
isResourceInPackages(
req,
config.experimental.serverComponentsExternalPackages
)
) {
return false
}

return true
},
resolve: {
conditionNames: ['react-server', 'node', 'require'],
alias: {
[require.resolve('next/dynamic')]:
'next/dist/client/components/dynamic',
// If missing the alias override here, the default alias will be used which aliases
// react to the direct file path, not the package name. In that case the condition
// will be ignored completely.
react: 'react',
'react-dom': 'react-dom',
},
},
},
]
: []),
...(hasServerComponents && (isNodeServer || isEdgeServer)
...(hasServerComponents && !isClient
? [
// RSC server compilation loaders
{
test: codeCondition.test,
include: [
dir,
// To let the internal client components passing through flight loader
/next[\\/]dist/,
NEXT_PROJECT_ROOT_DIST,
],
issuerLayer: WEBPACK_LAYERS.server,
use: {
Expand All @@ -1610,6 +1587,72 @@ export default async function getBaseWebpackConfig(
},
]
: []),
// Alias `next/dynamic` to React.lazy implementation for RSC
...(hasServerComponents
? [
{
test: codeCondition.test,
include: [appDir],
resolve: {
alias: {
// Alias `next/dynamic` to React.lazy implementation for RSC
[require.resolve('next/dynamic')]: require.resolve(
'next/dist/client/components/dynamic'
),
},
},
},
{
// Alias react-dom for ReactDOM.preload usage.
// Alias react for switching between default set and share subset.
oneOf: [
{
// test: codeCondition.test,
issuerLayer: WEBPACK_LAYERS.server,
test: (req: string) => {
// If it's not a source code file, or has been opted out of
// bundling, don't resolve it.
if (
!codeCondition.test.test(req) ||
isResourceInPackages(
req,
config.experimental.serverComponentsExternalPackages
)
) {
return false
}

return true
},
resolve: {
// It needs `conditionNames` here to require the proper asset,
// when react is acting as dependency of compiled/react-dom.
alias: {
react: 'next/dist/compiled/react/react.shared-subset',
// Use server rendering stub for RSC
// x-ref: https://github.com/facebook/react/pull/25436
'react-dom$':
'next/dist/compiled/react-dom/server-rendering-stub',
},
},
},
{
test: codeCondition.test,
resolve: {
alias: {
react: 'next/dist/compiled/react',
'react-dom$': isClient
? 'next/dist/compiled/react-dom/index'
: 'next/dist/compiled/react-dom/server-rendering-stub',
'react-dom/client$':
'next/dist/compiled/react-dom/client',
},
},
},
],
},
]
: []),
{
test: /\.(js|cjs|mjs)$/,
issuerLayer: WEBPACK_LAYERS.api,
Expand Down