Skip to content

Commit

Permalink
Add new target for middleware (vercel#30299)
Browse files Browse the repository at this point in the history
Co-authored-by: Jiachi Liu <[email protected]>
Co-authored-by: Tobias Koppers <[email protected]>
Co-authored-by: Tim Neutkens <[email protected]>
  • Loading branch information
4 people authored Oct 26, 2021
1 parent da2bb52 commit 5ddee44
Show file tree
Hide file tree
Showing 57 changed files with 1,824 additions and 256 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dev": "lerna run dev --stream --parallel",
"dev2": "while true; do yarn --check-files && yarn dev; done",
"test-types": "yarn tsc",
"test": "yarn jest",
"test-unit": "yarn jest test/unit/",
"testonly": "yarn jest --runInBand",
"testheadless": "cross-env HEADLESS=true yarn testonly",
Expand Down Expand Up @@ -137,9 +138,9 @@
"pretty-ms": "7.0.0",
"random-seed": "0.3.0",
"react": "17.0.2",
"react-18": "npm:react@next",
"react-18": "npm:react@18.0.0-alpha-3c4c1c470-20211021",
"react-dom": "17.0.2",
"react-dom-18": "npm:react-dom@next",
"react-dom-18": "npm:react-dom@18.0.0-alpha-3c4c1c470-20211021",
"react-ssr-prepass": "1.0.8",
"release": "6.3.0",
"request-promise-core": "1.1.2",
Expand Down
82 changes: 74 additions & 8 deletions packages/next/build/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { ClientPagesLoaderOptions } from './webpack/loaders/next-client-pages-lo
import { ServerlessLoaderQuery } from './webpack/loaders/next-serverless-loader'
import { LoadedEnvFiles } from '@next/env'
import { NextConfigComplete } from '../server/config-shared'
import { isFlightPage } from './utils'
import { ssrEntries } from './webpack/plugins/middleware-plugin'
import type { webpack5 } from 'next/dist/compiled/webpack/webpack'
import { MIDDLEWARE_SSR_RUNTIME_WEBPACK } from '../shared/lib/constants'

type ObjectValue<T> = T extends { [key: string]: infer V } ? V : never
type PagesMapping = {
Expand All @@ -22,14 +25,23 @@ type PagesMapping = {
export function createPagesMapping(
pagePaths: string[],
extensions: string[],
isDev: boolean
isDev: boolean,
hasServerComponents: boolean
): PagesMapping {
const previousPages: PagesMapping = {}
const pages: PagesMapping = pagePaths.reduce(
(result: PagesMapping, pagePath): PagesMapping => {
let page = `${pagePath
.replace(new RegExp(`\\.+(${extensions.join('|')})$`), '')
.replace(/\\/g, '/')}`.replace(/\/index$/, '')
let page = pagePath.replace(
new RegExp(`\\.+(${extensions.join('|')})$`),
''
)
if (hasServerComponents && /\.client$/.test(page)) {
// Assume that if there's a Client Component, that there is
// a matching Server Component that will map to the page.
return result
}

page = page.replace(/\\/g, '/').replace(/\/index$/, '')

const pageKey = page === '' ? '/' : page

Expand Down Expand Up @@ -68,6 +80,7 @@ export function createPagesMapping(
type Entrypoints = {
client: webpack5.EntryObject
server: webpack5.EntryObject
serverWeb: webpack5.EntryObject
}

export function createEntrypoints(
Expand All @@ -80,6 +93,7 @@ export function createEntrypoints(
): Entrypoints {
const client: webpack5.EntryObject = {}
const server: webpack5.EntryObject = {}
const serverWeb: webpack5.EntryObject = {}

const hasRuntimeConfig =
Object.keys(config.publicRuntimeConfig).length > 0 ||
Expand Down Expand Up @@ -120,6 +134,8 @@ export function createEntrypoints(
const serverBundlePath = posix.join('pages', bundleFile)

const isLikeServerless = isTargetLikeServerless(target)
const isFlight = isFlightPage(config, absolutePagePath)
const webServerRuntime = !!config.experimental.concurrentFeatures

if (page.match(MIDDLEWARE_ROUTE)) {
const loaderOpts: MiddlewareLoaderOptions = {
Expand All @@ -133,6 +149,27 @@ export function createEntrypoints(
return
}

if (
webServerRuntime &&
!(page === '/_app' || page === '/_error' || page === '/_document') &&
!isApiRoute
) {
ssrEntries.set(clientBundlePath, { requireFlightManifest: isFlight })
serverWeb[serverBundlePath] = finalizeEntrypoint({
name: '[name].js',
value: `next-middleware-ssr-loader?${stringify({
page,
absolutePagePath,
isServerComponent: isFlight,
buildId,
basePath: config.basePath,
assetPrefix: config.assetPrefix,
} as any)}!`,
isServer: false,
isServerWeb: true,
})
}

if (isApiRoute && isLikeServerless) {
const serverlessLoaderOptions: ServerlessLoaderQuery = {
page,
Expand All @@ -143,8 +180,20 @@ export function createEntrypoints(
serverlessLoaderOptions
)}!`
} else if (isApiRoute || target === 'server') {
server[serverBundlePath] = [absolutePagePath]
} else if (isLikeServerless && page !== '/_app' && page !== '/_document') {
if (
!webServerRuntime ||
page === '/_document' ||
page === '/_app' ||
page === '/_error'
) {
server[serverBundlePath] = [absolutePagePath]
}
} else if (
isLikeServerless &&
page !== '/_app' &&
page !== '/_document' &&
!webServerRuntime
) {
const serverlessLoaderOptions: ServerlessLoaderQuery = {
page,
absolutePagePath,
Expand Down Expand Up @@ -182,17 +231,22 @@ export function createEntrypoints(
return {
client,
server,
serverWeb,
}
}

export function finalizeEntrypoint({
name,
value,
isServer,
isMiddleware,
isServerWeb,
}: {
isServer: boolean
name: string
value: ObjectValue<webpack5.EntryObject>
isMiddleware?: boolean
isServerWeb?: boolean
}): ObjectValue<webpack5.EntryObject> {
const entry =
typeof value !== 'object' || Array.isArray(value)
Expand All @@ -209,8 +263,19 @@ export function finalizeEntrypoint({
}
}

if (name.match(MIDDLEWARE_ROUTE)) {
return {
if (isServerWeb) {
const ssrMiddlewareEntry = {
library: {
name: ['_ENTRIES', `middleware_[name]`],
type: 'assign',
},
runtime: MIDDLEWARE_SSR_RUNTIME_WEBPACK,
...entry,
}
return ssrMiddlewareEntry
}
if (isMiddleware) {
const middlewareEntry = {
filename: 'server/[name].js',
layer: 'middleware',
library: {
Expand All @@ -219,6 +284,7 @@ export function finalizeEntrypoint({
},
...entry,
}
return middlewareEntry
}

if (
Expand Down
65 changes: 58 additions & 7 deletions packages/next/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
PAGES_MANIFEST,
PHASE_PRODUCTION_BUILD,
PRERENDER_MANIFEST,
MIDDLEWARE_FLIGHT_MANIFEST,
REACT_LOADABLE_MANIFEST,
ROUTES_MANIFEST,
SERVERLESS_DIRECTORY,
Expand Down Expand Up @@ -141,10 +142,15 @@ export default async function build(
const config: NextConfigComplete = await nextBuildSpan
.traceChild('load-next-config')
.traceAsyncFn(() => loadConfig(PHASE_PRODUCTION_BUILD, dir, conf))

const distDir = path.join(dir, config.distDir)
setGlobal('phase', PHASE_PRODUCTION_BUILD)
setGlobal('distDir', distDir)

const webServerRuntime = !!config.experimental.concurrentFeatures
const hasServerComponents =
webServerRuntime && !!config.experimental.serverComponents

const { target } = config
const buildId: string = await nextBuildSpan
.traceChild('generate-buildid')
Expand Down Expand Up @@ -256,7 +262,6 @@ export default async function build(
const pagePaths: string[] = await nextBuildSpan
.traceChild('collect-pages')
.traceAsyncFn(() => collectPages(pagesDir, config.pageExtensions))

// needed for static exporting since we want to replace with HTML
// files
const allStaticPages = new Set<string>()
Expand All @@ -271,8 +276,14 @@ export default async function build(
const mappedPages = nextBuildSpan
.traceChild('create-pages-mapping')
.traceFn(() =>
createPagesMapping(pagePaths, config.pageExtensions, false)
createPagesMapping(
pagePaths,
config.pageExtensions,
false,
hasServerComponents
)
)

const entrypoints = nextBuildSpan
.traceChild('create-entrypoints')
.traceFn(() =>
Expand Down Expand Up @@ -538,6 +549,9 @@ export default async function build(
path.relative(distDir, manifestPath),
BUILD_MANIFEST,
PRERENDER_MANIFEST,
hasServerComponents
? path.join(SERVER_DIRECTORY, MIDDLEWARE_FLIGHT_MANIFEST + '.js')
: null,
REACT_LOADABLE_MANIFEST,
config.optimizeFonts
? path.join(
Expand Down Expand Up @@ -579,6 +593,20 @@ export default async function build(
rewrites,
runWebpackSpan,
}),
webServerRuntime
? getBaseWebpackConfig(dir, {
buildId,
reactProductionProfiling,
isServer: true,
webServerRuntime: true,
config,
target,
pagesDir,
entrypoints: entrypoints.serverWeb,
rewrites,
runWebpackSpan,
})
: null,
])
)

Expand Down Expand Up @@ -609,9 +637,21 @@ export default async function build(
}
} else {
const serverResult = await runCompiler(configs[1], { runWebpackSpan })
const serverWebResult = configs[2]
? await runCompiler(configs[2], { runWebpackSpan })
: null

result = {
warnings: [...clientResult.warnings, ...serverResult.warnings],
errors: [...clientResult.errors, ...serverResult.errors],
warnings: [
...clientResult.warnings,
...serverResult.warnings,
...(serverWebResult?.warnings || []),
],
errors: [
...clientResult.errors,
...serverResult.errors,
...(serverWebResult?.errors || []),
],
}
}
})
Expand Down Expand Up @@ -839,6 +879,7 @@ export default async function build(
distDir,
config.experimental.gzipSize
)

await Promise.all(
pageKeys.map(async (page) => {
const checkPageSpan = staticCheckSpan.traceChild('check-page', {
Expand All @@ -858,8 +899,13 @@ export default async function build(
let isStatic = false
let isHybridAmp = false
let ssgPageRoutes: string[] | null = null
let isMiddlewareRoute = !!page.match(MIDDLEWARE_ROUTE)

if (!page.match(MIDDLEWARE_ROUTE) && !page.match(RESERVED_PAGE)) {
if (
!isMiddlewareRoute &&
!page.match(RESERVED_PAGE) &&
!webServerRuntime
) {
try {
let isPageStaticSpan =
checkPageSpan.traceChild('is-page-static')
Expand Down Expand Up @@ -923,6 +969,7 @@ export default async function build(
serverPropsPages.add(page)
} else if (
workerResult.isStatic &&
!workerResult.hasFlightData &&
(await customAppGetInitialPropsPromise) === false
) {
staticPages.add(page)
Expand Down Expand Up @@ -966,6 +1013,10 @@ export default async function build(
totalSize: allSize,
static: isStatic,
isSsg,
isWebSsr:
webServerRuntime &&
!isMiddlewareRoute &&
!page.match(RESERVED_PAGE),
isHybridAmp,
ssgPageRoutes,
initialRevalidateSeconds: false,
Expand Down Expand Up @@ -1220,11 +1271,11 @@ export default async function build(
const routeRegex = getRouteRegex(dataRoute.replace(/\.json$/, ''))

dataRouteRegex = normalizeRouteRegex(
routeRegex.re.source.replace(/\(\?:\\\/\)\?\$$/, '\\.json$')
routeRegex.re.source.replace(/\(\?:\\\/\)\?\$$/, `\\.json$`)
)
namedDataRouteRegex = routeRegex.namedRegex!.replace(
/\(\?:\/\)\?\$$/,
'\\.json$'
`\\.json$`
)
routeKeys = routeRegex.routeKeys
} else {
Expand Down
Loading

0 comments on commit 5ddee44

Please sign in to comment.