Skip to content

Commit

Permalink
Only resolve page runtime for react 18 and error on read failure (#35705
Browse files Browse the repository at this point in the history
)

* Read the proper page file from either pages directory or from node_modules (inernal pages like _app, _document)
* Only reading page runtime when `reactRoot` is enabled, reduce time for react 17 apps
  • Loading branch information
huozhi committed Mar 30, 2022
1 parent 7eee27f commit d95d2d3
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 26 deletions.
30 changes: 19 additions & 11 deletions packages/next/build/entries.ts
@@ -1,4 +1,8 @@
import type { PageRuntime, NextConfigComplete } from '../server/config-shared'
import type {
PageRuntime,
NextConfigComplete,
NextConfig,
} from '../server/config-shared'
import type { webpack5 } from 'next/dist/compiled/webpack/webpack'
import fs from 'fs'
import chalk from 'next/dist/compiled/chalk'
Expand Down Expand Up @@ -105,8 +109,11 @@ const cachedPageRuntimeConfig = new Map<string, [number, PageRuntime]>()
// could be thousands of pages existing.
export async function getPageRuntime(
pageFilePath: string,
globalRuntimeFallback?: 'nodejs' | 'edge'
nextConfig: Partial<NextConfig>
): Promise<PageRuntime> {
if (!nextConfig.experimental?.reactRoot) return undefined

const globalRuntime = nextConfig.experimental?.runtime
const cached = cachedPageRuntimeConfig.get(pageFilePath)
if (cached) {
return cached[1]
Expand All @@ -118,6 +125,7 @@ export async function getPageRuntime(
encoding: 'utf8',
})
} catch (err) {
if (process.env.NODE_ENV === 'production') throw err
return undefined
}

Expand Down Expand Up @@ -183,7 +191,7 @@ export async function getPageRuntime(

if (!pageRuntime) {
if (isRuntimeRequired) {
pageRuntime = globalRuntimeFallback
pageRuntime = globalRuntime
}
}

Expand Down Expand Up @@ -217,6 +225,7 @@ export async function createEntrypoints(
const hasRuntimeConfig =
Object.keys(config.publicRuntimeConfig).length > 0 ||
Object.keys(config.serverRuntimeConfig).length > 0
const hasReactRoot = !!config.experimental.reactRoot

const defaultServerlessOptions = {
absoluteAppPath: pages['/_app'],
Expand All @@ -242,11 +251,9 @@ export async function createEntrypoints(
'base64'
),
i18n: config.i18n ? JSON.stringify(config.i18n) : '',
reactRoot: config.experimental.reactRoot ? 'true' : '',
reactRoot: hasReactRoot ? 'true' : '',
}

const globalRuntime = config.experimental.runtime

await Promise.all(
Object.keys(pages).map(async (page) => {
const absolutePagePath = pages[page]
Expand All @@ -260,11 +267,12 @@ export async function createEntrypoints(
const isReserved = isReservedPage(page)
const isCustomError = isCustomErrorPage(page)
const isFlight = isFlightPage(config, absolutePagePath)
const isEdgeRuntime =
(await getPageRuntime(
join(pagesDir, absolutePagePath.slice(PAGES_DIR_ALIAS.length + 1)),
globalRuntime
)) === 'edge'
const isInternalPages = !absolutePagePath.startsWith(PAGES_DIR_ALIAS)
const pageFilePath = isInternalPages
? require.resolve(absolutePagePath)
: join(pagesDir, absolutePagePath.replace(PAGES_DIR_ALIAS, ''))
const pageRuntime = await getPageRuntime(pageFilePath, config)
const isEdgeRuntime = pageRuntime === 'edge'

if (page.match(MIDDLEWARE_ROUTE)) {
const loaderOpts: MiddlewareLoaderOptions = {
Expand Down
10 changes: 3 additions & 7 deletions packages/next/build/index.ts
Expand Up @@ -971,13 +971,9 @@ export default async function build(
p.startsWith(actualPage + '.') ||
p.startsWith(actualPage + '/index.')
)
const pageRuntime =
hasConcurrentFeatures && pagePath
? await getPageRuntime(
join(pagesDir, pagePath),
config.experimental.runtime
)
: undefined
const pageRuntime = pagePath
? await getPageRuntime(join(pagesDir, pagePath), config)
: undefined

if (
!isMiddlewareRoute &&
Expand Down
2 changes: 1 addition & 1 deletion packages/next/server/dev/hot-reloader.ts
Expand Up @@ -509,7 +509,7 @@ export default class HotReloader {

const pageRuntimeConfig = await getPageRuntime(
absolutePagePath,
this.runtime
this.config
)
const isEdgeSSRPage = pageRuntimeConfig === 'edge' && !isApiRoute

Expand Down
2 changes: 1 addition & 1 deletion packages/next/server/dev/next-dev-server.ts
Expand Up @@ -285,7 +285,7 @@ export default class DevServer extends Server {
invalidatePageRuntimeCache(fileName, safeTime)
const pageRuntimeConfig = await getPageRuntime(
fileName,
this.nextConfig.experimental.runtime
this.nextConfig
)
const isEdgeRuntime = pageRuntimeConfig === 'edge'

Expand Down
2 changes: 1 addition & 1 deletion packages/next/server/dev/on-demand-entry-handler.ts
Expand Up @@ -207,7 +207,7 @@ export default function onDemandEntryHandler(
const isApiRoute = normalizedPage.match(API_ROUTE) && !isMiddleware
const pageRuntimeConfig = await getPageRuntime(
absolutePagePath,
nextConfig.experimental.runtime
nextConfig
)
const isEdgeServer = pageRuntimeConfig === 'edge'

Expand Down
20 changes: 15 additions & 5 deletions test/unit/parse-page-runtime.test.ts
@@ -1,26 +1,36 @@
import { getPageRuntime } from 'next/dist/build/entries'
import type { PageRuntime } from 'next/dist/server/config-shared'
import { join } from 'path'

const fixtureDir = join(__dirname, 'fixtures')

function createNextConfig(runtime?: PageRuntime) {
return {
experimental: { reactRoot: true, runtime },
}
}

describe('parse page runtime config', () => {
it('should parse nodejs runtime correctly', async () => {
const runtime = await getPageRuntime(
join(fixtureDir, 'page-runtime/nodejs.js')
join(fixtureDir, 'page-runtime/nodejs.js'),
createNextConfig()
)
expect(runtime).toBe('nodejs')
})

it('should parse edge runtime correctly', async () => {
const runtime = await getPageRuntime(
join(fixtureDir, 'page-runtime/edge.js')
join(fixtureDir, 'page-runtime/edge.js'),
createNextConfig()
)
expect(runtime).toBe('edge')
})

it('should return undefined if no runtime is specified', async () => {
const runtime = await getPageRuntime(
join(fixtureDir, 'page-runtime/static.js')
join(fixtureDir, 'page-runtime/static.js'),
createNextConfig()
)
expect(runtime).toBe(undefined)
})
Expand All @@ -30,15 +40,15 @@ describe('fallback to the global runtime configuration', () => {
it('should fallback when gSP is defined and exported', async () => {
const runtime = await getPageRuntime(
join(fixtureDir, 'page-runtime/fallback-with-gsp.js'),
'edge'
createNextConfig('edge')
)
expect(runtime).toBe('edge')
})

it('should fallback when gSP is re-exported from other module', async () => {
const runtime = await getPageRuntime(
join(fixtureDir, 'page-runtime/fallback-re-export-gsp.js'),
'edge'
createNextConfig('edge')
)
expect(runtime).toBe('edge')
})
Expand Down

1 comment on commit d95d2d3

@ijjk
Copy link
Member

@ijjk ijjk commented on d95d2d3 Mar 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stats from current release

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
buildDuration 19.7s 20s ⚠️ +312ms
buildDurationCached 7.6s 7.5s -131ms
nodeModulesSize 467 MB 467 MB ⚠️ +809 B
Page Load Tests Overall increase ✓
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
/ failed reqs 0 0
/ total time (seconds) 4.288 4.249 -0.04
/ avg req/sec 583.04 588.33 +5.29
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 2.309 2.164 -0.15
/error-in-render avg req/sec 1082.66 1155.15 +72.49
Client Bundles (main, webpack)
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
925.HASH.js gzip 179 B 179 B
framework-HASH.js gzip 42 kB 42 kB
main-HASH.js gzip 28.4 kB 28.4 kB
webpack-HASH.js gzip 1.44 kB 1.44 kB
Overall change 72.1 kB 72.1 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
_app-HASH.js gzip 1.36 kB 1.36 kB
_error-HASH.js gzip 192 B 192 B
amp-HASH.js gzip 309 B 309 B
css-HASH.js gzip 327 B 327 B
dynamic-HASH.js gzip 3.05 kB 3.05 kB
head-HASH.js gzip 351 B 351 B
hooks-HASH.js gzip 920 B 920 B
image-HASH.js gzip 5.48 kB 5.48 kB
index-HASH.js gzip 263 B 263 B
link-HASH.js gzip 2.26 kB 2.26 kB
routerDirect..HASH.js gzip 320 B 320 B
script-HASH.js gzip 387 B 387 B
withRouter-HASH.js gzip 319 B 319 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 15.7 kB 15.7 kB
Client Build Manifests
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
_buildManifest.js gzip 460 B 460 B
Overall change 460 B 460 B
Rendered Page Sizes
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
index.html gzip 532 B 532 B
link.html gzip 545 B 545 B
withRouter.html gzip 526 B 526 B
Overall change 1.6 kB 1.6 kB

Default Build with SWC (Decrease detected ✓)
General Overall increase ⚠️
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
buildDuration 23.4s 23.5s ⚠️ +98ms
buildDurationCached 7.1s 7.4s ⚠️ +285ms
nodeModulesSize 467 MB 467 MB ⚠️ +809 B
Page Load Tests Overall decrease ⚠️
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
/ failed reqs 0 0
/ total time (seconds) 4.193 4.228 ⚠️ +0.04
/ avg req/sec 596.18 591.28 ⚠️ -4.9
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 2.035 2.115 ⚠️ +0.08
/error-in-render avg req/sec 1228.62 1181.8 ⚠️ -46.82
Client Bundles (main, webpack)
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
925.HASH.js gzip 178 B 178 B
framework-HASH.js gzip 42.3 kB 42.3 kB
main-HASH.js gzip 28.8 kB 28.8 kB
webpack-HASH.js gzip 1.45 kB 1.45 kB
Overall change 72.7 kB 72.7 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
_app-HASH.js gzip 1.35 kB 1.35 kB
_error-HASH.js gzip 179 B 179 B
amp-HASH.js gzip 313 B 313 B
css-HASH.js gzip 324 B 324 B
dynamic-HASH.js gzip 3.04 kB 3.04 kB
head-HASH.js gzip 351 B 351 B
hooks-HASH.js gzip 921 B 921 B
image-HASH.js gzip 5.59 kB 5.59 kB
index-HASH.js gzip 261 B 261 B
link-HASH.js gzip 2.33 kB 2.33 kB
routerDirect..HASH.js gzip 322 B 322 B
script-HASH.js gzip 388 B 388 B
withRouter-HASH.js gzip 317 B 317 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 15.8 kB 15.8 kB
Client Build Manifests
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
_buildManifest.js gzip 459 B 459 B
Overall change 459 B 459 B
Rendered Page Sizes
vercel/next.js canary v12.1.3 vercel/next.js refs/heads/canary Change
index.html gzip 529 B 529 B
link.html gzip 544 B 544 B
withRouter.html gzip 525 B 525 B
Overall change 1.6 kB 1.6 kB

Please sign in to comment.