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

Add initial handling for routing tests #36635

Merged
merged 2 commits into from May 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
115 changes: 88 additions & 27 deletions packages/next/build/entries.ts
Expand Up @@ -10,8 +10,20 @@ import fs from 'fs'
import chalk from 'next/dist/compiled/chalk'
import { posix, join } from 'path'
import { stringify } from 'querystring'
import { API_ROUTE, DOT_NEXT_ALIAS, PAGES_DIR_ALIAS } from '../lib/constants'
import { EDGE_RUNTIME_WEBPACK } from '../shared/lib/constants'
import {
API_ROUTE,
DOT_NEXT_ALIAS,
PAGES_DIR_ALIAS,
ROOT_ALIAS,
ROOT_DIR_ALIAS,
} from '../lib/constants'
import {
CLIENT_STATIC_FILES_RUNTIME_AMP,
CLIENT_STATIC_FILES_RUNTIME_MAIN,
CLIENT_STATIC_FILES_RUNTIME_MAIN_ROOT,
CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH,
EDGE_RUNTIME_WEBPACK,
} from '../shared/lib/constants'
import { MIDDLEWARE_ROUTE } from '../lib/constants'
import { __ApiPreviewProps } from '../server/api-utils'
import { isTargetLikeServerless } from '../server/utils'
Expand All @@ -28,38 +40,49 @@ type ObjectValue<T> = T extends { [key: string]: infer V } ? V : never
* special case because it is the only page where we want to preserve the RSC
* server extension.
*/
export function getPageFromPath(pagePath: string, pageExtensions: string[]) {
export function getPageFromPath(
pagePath: string,
pageExtensions: string[],
isRoot?: boolean
) {
const extensions = pagePath.includes('/_app.server.')
? withoutRSCExtensions(pageExtensions)
: pageExtensions

const page = normalizePathSep(
let page = normalizePathSep(
pagePath.replace(new RegExp(`\\.+(${extensions.join('|')})$`), '')
).replace(/\/index$/, '')
)

if (!isRoot) {
page = page.replace(/\/index$/, '')
}

return page === '' ? '/' : page
}

export function createPagesMapping({
hasServerComponents,
isDev,
isRoot,
pageExtensions,
pagePaths,
}: {
hasServerComponents: boolean
isDev: boolean
isRoot?: boolean
pageExtensions: string[]
pagePaths: string[]
}): { [page: string]: string } {
const previousPages: { [key: string]: string } = {}
const pathAlias = isRoot ? ROOT_DIR_ALIAS : PAGES_DIR_ALIAS
const pages = pagePaths.reduce<{ [key: string]: string }>(
(result, pagePath) => {
// Do not process .d.ts files inside the `pages` folder
if (pagePath.endsWith('.d.ts') && pageExtensions.includes('ts')) {
return result
}

const pageKey = getPageFromPath(pagePath, pageExtensions)
const pageKey = getPageFromPath(pagePath, pageExtensions, isRoot)

// Assume that if there's a Client Component, that there is
// a matching Server Component that will map to the page.
Expand All @@ -80,7 +103,11 @@ export function createPagesMapping({
previousPages[pageKey] = pagePath
}

result[pageKey] = normalizePathSep(join(PAGES_DIR_ALIAS, pagePath))
if (pageKey === 'root') {
result['root'] = normalizePathSep(join(ROOT_ALIAS, pagePath))
} else {
result[pageKey] = normalizePathSep(join(pathAlias, pagePath))
}
return result
},
{}
Expand All @@ -89,6 +116,16 @@ export function createPagesMapping({
// In development we always alias these to allow Webpack to fallback to
// the correct source file so that HMR can work properly when a file is
// added or removed.

if (isRoot) {
if (isDev) {
pages['root'] = `${ROOT_ALIAS}/root`
} else {
pages['root'] = pages['root'] || 'next/dist/pages/root'
}
return pages
}

if (isDev) {
delete pages['/_app']
delete pages['/_app.server']
Expand Down Expand Up @@ -222,6 +259,8 @@ interface CreateEntrypointsParams {
pagesDir: string
previewMode: __ApiPreviewProps
target: 'server' | 'serverless' | 'experimental-serverless-trace'
rootDir?: string
rootPaths?: Record<string, string>
}

export function getEdgeServerEntry(opts: {
Expand Down Expand Up @@ -326,29 +365,45 @@ export function getClientEntry(opts: {
}

export async function createEntrypoints(params: CreateEntrypointsParams) {
const { config, pages, pagesDir, isDev, target } = params
const { config, pages, pagesDir, isDev, target, rootDir, rootPaths } = params
const edgeServer: webpack5.EntryObject = {}
const server: webpack5.EntryObject = {}
const client: webpack5.EntryObject = {}

await Promise.all(
Object.keys(pages).map(async (page) => {
const getEntryHandler =
(mappings: Record<string, string>, isRoot: boolean) =>
async (page: string) => {
const bundleFile = normalizePagePath(page)
const clientBundlePath = posix.join('pages', bundleFile)
const serverBundlePath = posix.join('pages', bundleFile)
const serverBundlePath = posix.join(
isRoot ? (bundleFile === '/root' ? './' : 'root') : 'pages',
bundleFile
)

// Handle paths that have aliases
const pageFilePath = (() => {
const absolutePagePath = mappings[page]
if (absolutePagePath.startsWith(PAGES_DIR_ALIAS)) {
return absolutePagePath.replace(PAGES_DIR_ALIAS, pagesDir)
}

if (absolutePagePath.startsWith(ROOT_DIR_ALIAS) && rootDir) {
return absolutePagePath.replace(ROOT_DIR_ALIAS, rootDir)
}

if (absolutePagePath.startsWith(ROOT_ALIAS) && rootDir) {
return absolutePagePath.replace(ROOT_ALIAS, join(rootDir, '..'))
}

return require.resolve(absolutePagePath)
})()

runDependingOnPageType({
page,
pageRuntime: await getPageRuntime(
!pages[page].startsWith(PAGES_DIR_ALIAS)
? require.resolve(pages[page])
: join(pagesDir, pages[page].replace(PAGES_DIR_ALIAS, '')),
config,
isDev
),
pageRuntime: await getPageRuntime(pageFilePath, config, isDev),
onClient: () => {
client[clientBundlePath] = getClientEntry({
absolutePagePath: pages[page],
absolutePagePath: mappings[page],
page,
})
},
Expand All @@ -357,26 +412,31 @@ export async function createEntrypoints(params: CreateEntrypointsParams) {
if (page !== '/_app' && page !== '/_document') {
server[serverBundlePath] = getServerlessEntry({
...params,
absolutePagePath: pages[page],
absolutePagePath: mappings[page],
page,
})
}
} else {
server[serverBundlePath] = [pages[page]]
server[serverBundlePath] = [mappings[page]]
}
},
onEdgeServer: () => {
edgeServer[serverBundlePath] = getEdgeServerEntry({
...params,
absolutePagePath: pages[page],
absolutePagePath: mappings[page],
bundlePath: clientBundlePath,
isDev: false,
page,
})
},
})
})
)
}

if (rootDir && rootPaths) {
const entryHandler = getEntryHandler(rootPaths, true)
await Promise.all(Object.keys(rootPaths).map(entryHandler))
}
await Promise.all(Object.keys(pages).map(getEntryHandler(pages, false)))

return {
client,
Expand Down Expand Up @@ -450,9 +510,10 @@ export function finalizeEntrypoint({
if (
// Client special cases
name !== 'polyfills' &&
name !== 'main' &&
name !== 'amp' &&
name !== 'react-refresh'
name !== CLIENT_STATIC_FILES_RUNTIME_MAIN &&
name !== CLIENT_STATIC_FILES_RUNTIME_MAIN_ROOT &&
name !== CLIENT_STATIC_FILES_RUNTIME_AMP &&
name !== CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH
) {
return {
dependOn:
Expand Down
40 changes: 40 additions & 0 deletions packages/next/build/index.ts
Expand Up @@ -114,6 +114,7 @@ import { MiddlewareManifest } from './webpack/plugins/middleware-plugin'
import { recursiveCopy } from '../lib/recursive-copy'
import { recursiveReadDir } from '../lib/recursive-readdir'
import { lockfilePatchPromise, teardownTraceSubscriber } from './swc'
import { findPageFile } from '../server/lib/find-page-file'

export type SsgRoute = {
initialRevalidateSeconds: number | false
Expand Down Expand Up @@ -309,6 +310,26 @@ export default async function build(
new RegExp(`\\.(?:${config.pageExtensions.join('|')})$`)
)
)

let rootPaths: string[] | undefined

if (rootDir) {
rootPaths = await nextBuildSpan
.traceChild('collect-root-paths')
.traceAsyncFn(() =>
recursiveReadDir(
rootDir,
new RegExp(`\\.(?:${config.pageExtensions.join('|')})$`)
)
)

const rootFile = await findPageFile(
path.join(rootDir, '..'),
'root',
config.pageExtensions
)
if (rootFile) rootPaths.push(rootFile)
}
// needed for static exporting since we want to replace with HTML
// files

Expand All @@ -332,6 +353,22 @@ export default async function build(
})
)

let mappedRootPaths: ReturnType<typeof createPagesMapping> | undefined

if (rootPaths && rootDir) {
mappedRootPaths = nextBuildSpan
.traceChild('create-root-mapping')
.traceFn(() =>
createPagesMapping({
pagePaths: rootPaths!,
hasServerComponents,
isDev: false,
isRoot: true,
pageExtensions: config.pageExtensions,
})
)
}

const entrypoints = await nextBuildSpan
.traceChild('create-entrypoints')
.traceAsyncFn(() =>
Expand All @@ -344,6 +381,8 @@ export default async function build(
pagesDir,
previewMode: previewProps,
target,
rootDir,
rootPaths: mappedRootPaths,
})
)

Expand Down Expand Up @@ -649,6 +688,7 @@ export default async function build(
rewrites,
runWebpackSpan,
target,
rootDir,
}

const configs = await runWebpackSpan
Expand Down