Skip to content

Commit

Permalink
Eliminate path polyfill and incremental-cache from base server (#39548)
Browse files Browse the repository at this point in the history
Continue to optimize the base server to make it leaner. These are only needed by the Node.js server currently.

Related:
- #39433
- #39045
- #39044
- #39037

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
  • Loading branch information
shuding committed Aug 12, 2022
1 parent 9d1980d commit 0c95a93
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 135 deletions.
6 changes: 4 additions & 2 deletions packages/next/build/webpack-config.ts
Expand Up @@ -7,8 +7,6 @@ import path, { dirname, join as pathJoin, relative as relativePath } from 'path'
import { escapeStringRegexp } from '../shared/lib/escape-regexp'
import {
DOT_NEXT_ALIAS,
NEXT_PROJECT_ROOT,
NEXT_PROJECT_ROOT_DIST_CLIENT,
PAGES_DIR_ALIAS,
ROOT_DIR_ALIAS,
APP_DIR_ALIAS,
Expand Down Expand Up @@ -64,6 +62,10 @@ import { loadBindings } from './swc'
import { clientComponentRegex } from './webpack/loaders/utils'
import { AppBuildManifestPlugin } from './webpack/plugins/app-build-manifest-plugin'

const NEXT_PROJECT_ROOT = pathJoin(__dirname, '..', '..')
const NEXT_PROJECT_ROOT_DIST = pathJoin(NEXT_PROJECT_ROOT, 'dist')
const NEXT_PROJECT_ROOT_DIST_CLIENT = pathJoin(NEXT_PROJECT_ROOT_DIST, 'client')

const watchOptions = Object.freeze({
aggregateTimeout: 5,
ignored: ['**/.git/**', '**/.next/**'],
Expand Down
8 changes: 0 additions & 8 deletions packages/next/lib/constants.ts
@@ -1,12 +1,4 @@
import type { ServerRuntime } from '../types'
import { join } from '../shared/lib/isomorphic/path'

export const NEXT_PROJECT_ROOT = join(__dirname, '..', '..')
export const NEXT_PROJECT_ROOT_DIST = join(NEXT_PROJECT_ROOT, 'dist')
export const NEXT_PROJECT_ROOT_DIST_CLIENT = join(
NEXT_PROJECT_ROOT_DIST,
'client'
)

// Regex for API routes
export const API_ROUTE = /^\/api(?:\/|$)/
Expand Down
61 changes: 20 additions & 41 deletions packages/next/server/base-server.ts
Expand Up @@ -10,7 +10,11 @@ import type { NextConfig, NextConfigComplete } from './config-shared'
import type { NextParsedUrlQuery, NextUrlWithParsedQuery } from './request-meta'
import type { ParsedUrlQuery } from 'querystring'
import type { RenderOpts, RenderOptsPartial } from './render'
import type { ResponseCacheEntry, ResponseCacheValue } from './response-cache'
import type {
ResponseCacheBase,
ResponseCacheEntry,
ResponseCacheValue,
} from './response-cache'
import type { UrlWithParsedQuery } from 'url'
import {
CacheFs,
Expand All @@ -24,7 +28,7 @@ import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plug
import type { BaseNextRequest, BaseNextResponse } from './base-http'
import type { PayloadOptions } from './send-payload'

import { join, resolve } from '../shared/lib/isomorphic/path'
import { join } from '../shared/lib/isomorphic/path'
import { parse as parseQs } from 'querystring'
import { format as formatUrl, parse as parseUrl } from 'url'
import { getRedirectStatus } from '../lib/redirect-status'
Expand All @@ -46,7 +50,6 @@ import { isTargetLikeServerless } from './utils'
import Router from './router'
import { getPathMatch } from '../shared/lib/router/utils/path-match'
import { setRevalidateHeaders } from './send-payload/revalidate-headers'
import { IncrementalCache } from './lib/incremental-cache'
import { execOnce } from '../shared/lib/utils'
import { isBlockedPage, isBot } from './utils'
import RenderResult from './render-result'
Expand All @@ -58,7 +61,6 @@ import * as Log from '../build/output/log'
import { detectDomainLocale } from '../shared/lib/i18n/detect-domain-locale'
import escapePathDelimiters from '../shared/lib/router/utils/escape-path-delimiters'
import { getUtils } from '../build/webpack/loaders/next-serverless-loader/utils'
import ResponseCache from './response-cache'
import isError, { getProperError } from '../lib/is-error'
import { addRequestMeta, getRequestMeta } from './request-meta'
import { createHeaderRoute, createRedirectRoute } from './server-route-utils'
Expand All @@ -72,7 +74,6 @@ import { getLocaleRedirect } from '../shared/lib/i18n/get-locale-redirect'
import { getHostname } from '../shared/lib/get-hostname'
import { parseUrl as parseUrlUtil } from '../shared/lib/router/utils/parse-url'
import { getNextPathnameInfo } from '../shared/lib/router/utils/get-next-pathname-info'
import { normalizePagePath } from '../shared/lib/page-path/normalize-page-path'

export type FindComponentsResult = {
components: LoadComponentsReturnType
Expand Down Expand Up @@ -203,8 +204,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
largePageDataBytes?: number
}
protected serverOptions: ServerOptions
private incrementalCache: IncrementalCache
private responseCache: ResponseCache
private responseCache: ResponseCacheBase
protected router: Router
protected dynamicRoutes?: DynamicRoutes
protected appPathRoutes?: Record<string, string>
Expand Down Expand Up @@ -250,6 +250,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
req: BaseNextRequest,
parsedUrl: NextUrlWithParsedQuery
): void
protected abstract getFallback(page: string): Promise<string>

protected abstract sendRenderResult(
req: BaseNextRequest,
Expand Down Expand Up @@ -285,6 +286,10 @@ export default abstract class Server<ServerOptions extends Options = Options> {
res: BaseNextResponse
): void

protected abstract getResponseCache(options: {
dev: boolean
}): ResponseCacheBase

protected abstract loadEnvConfig(params: {
dev: boolean
forceReload?: boolean
Expand All @@ -303,7 +308,9 @@ export default abstract class Server<ServerOptions extends Options = Options> {
} = options
this.serverOptions = options

this.dir = resolve(dir)
this.dir =
process.env.NEXT_RUNTIME === 'edge' ? dir : require('path').resolve(dir)

this.quiet = quiet
this.loadEnvConfig({ dev })

Expand All @@ -312,7 +319,10 @@ export default abstract class Server<ServerOptions extends Options = Options> {
this.nextConfig = conf as NextConfigComplete
this.hostname = hostname
this.port = port
this.distDir = join(this.dir, this.nextConfig.distDir)
this.distDir =
process.env.NEXT_RUNTIME === 'edge'
? this.nextConfig.distDir
: require('path').join(this.dir, this.nextConfig.distDir)
this.publicDir = this.getPublicDir()
this.hasStaticDir = !minimalMode && this.getHasStaticDir()

Expand Down Expand Up @@ -385,32 +395,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
this.router = new Router(this.generateRoutes())
this.setAssetPrefix(assetPrefix)

this.incrementalCache = new IncrementalCache({
fs: this.getCacheFilesystem(),
dev,
serverDistDir: this.serverDistDir,
maxMemoryCacheSize: this.nextConfig.experimental.isrMemoryCacheSize,
flushToDisk: !minimalMode && this.nextConfig.experimental.isrFlushToDisk,
incrementalCacheHandlerPath:
this.nextConfig.experimental?.incrementalCacheHandlerPath,
getPrerenderManifest: () => {
if (dev) {
return {
version: -1 as any, // letting us know this doesn't conform to spec
routes: {},
dynamicRoutes: {},
notFoundRoutes: [],
preview: null as any, // `preview` is special case read in next-dev-server
}
} else {
return this.getPrerenderManifest()
}
},
})
this.responseCache = new ResponseCache(
this.incrementalCache,
this.minimalMode
)
this.responseCache = this.getResponseCache({ dev })
}

public logError(err: Error): void {
Expand Down Expand Up @@ -730,12 +715,6 @@ export default abstract class Server<ServerOptions extends Options = Options> {
return Object.assign(customRoutes, { rewrites })
}

protected getFallback(page: string): Promise<string> {
page = normalizePagePath(page)
const cacheFs = this.getCacheFilesystem()
return cacheFs.readFile(join(this.serverDistDir, 'pages', `${page}.html`))
}

protected getPreviewProps(): __ApiPreviewProps {
return this.getPrerenderManifest().preview
}
Expand Down
37 changes: 36 additions & 1 deletion packages/next/server/next-server.ts
Expand Up @@ -80,13 +80,14 @@ import { getRouteMatcher } from '../shared/lib/router/utils/route-matcher'
import { loadEnvConfig } from '@next/env'
import { getCustomRoute } from './server-route-utils'
import { urlQueryToSearchParams } from '../shared/lib/router/utils/querystring'
import ResponseCache from '../server/response-cache'
import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-slash'
import { getNextPathnameInfo } from '../shared/lib/router/utils/get-next-pathname-info'
import { bodyStreamToNodeStream, getClonableBody } from './body-streams'
import { checkIsManualRevalidate } from './api-utils'
import { isDynamicRoute } from '../shared/lib/router/utils'
import { shouldUseReactRoot } from './utils'
import ResponseCache from './response-cache'
import { IncrementalCache } from './lib/incremental-cache'

if (shouldUseReactRoot) {
;(process.env as any).__NEXT_REACT_ROOT = 'true'
Expand Down Expand Up @@ -171,6 +172,34 @@ export default class NextNodeServer extends BaseServer {
loadEnvConfig(this.dir, dev, Log, forceReload)
}

protected getResponseCache({ dev }: { dev: boolean }) {
const incrementalCache = new IncrementalCache({
fs: this.getCacheFilesystem(),
dev,
serverDistDir: this.serverDistDir,
maxMemoryCacheSize: this.nextConfig.experimental.isrMemoryCacheSize,
flushToDisk:
!this.minimalMode && this.nextConfig.experimental.isrFlushToDisk,
incrementalCacheHandlerPath:
this.nextConfig.experimental?.incrementalCacheHandlerPath,
getPrerenderManifest: () => {
if (dev) {
return {
version: -1 as any, // letting us know this doesn't conform to spec
routes: {},
dynamicRoutes: {},
notFoundRoutes: [],
preview: null as any, // `preview` is special case read in next-dev-server
}
} else {
return this.getPrerenderManifest()
}
},
})

return new ResponseCache(incrementalCache, this.minimalMode)
}

protected getPublicDir(): string {
return join(this.dir, CLIENT_PUBLIC_FILES_PATH)
}
Expand Down Expand Up @@ -798,6 +827,12 @@ export default class NextNodeServer extends BaseServer {
))
}

protected getFallback(page: string): Promise<string> {
page = normalizePagePath(page)
const cacheFs = this.getCacheFilesystem()
return cacheFs.readFile(join(this.serverDistDir, 'pages', `${page}.html`))
}

protected getCacheFilesystem(): CacheFs {
return {
readFile: (f) => fs.promises.readFile(f, 'utf8'),
Expand Down
@@ -1,82 +1,13 @@
import RenderResult from './render-result'
import type {
IncrementalCache,
ResponseCacheEntry,
ResponseGenerator,
IncrementalCacheItem,
} from './types'

export interface CachedRedirectValue {
kind: 'REDIRECT'
props: Object
}

interface CachedPageValue {
kind: 'PAGE'
// this needs to be a RenderResult so since renderResponse
// expects that type instead of a string
html: RenderResult
pageData: Object
}

export interface CachedImageValue {
kind: 'IMAGE'
etag: string
buffer: Buffer
extension: string
isMiss?: boolean
isStale?: boolean
}

interface IncrementalCachedPageValue {
kind: 'PAGE'
// this needs to be a string since the cache expects to store
// the string value
html: string
pageData: Object
}

export type IncrementalCacheEntry = {
curRevalidate?: number | false
// milliseconds to revalidate after
revalidateAfter: number | false
isStale?: boolean
value: IncrementalCacheValue | null
}

export type IncrementalCacheValue =
| CachedRedirectValue
| IncrementalCachedPageValue
| CachedImageValue

export type ResponseCacheValue =
| CachedRedirectValue
| CachedPageValue
| CachedImageValue

export type ResponseCacheEntry = {
revalidate?: number | false
value: ResponseCacheValue | null
isStale?: boolean
isMiss?: boolean
}

type ResponseGenerator = (
hasResolved: boolean,
hadCache: boolean
) => Promise<ResponseCacheEntry | null>
import RenderResult from '../render-result'

type IncrementalCacheItem = {
revalidateAfter?: number | false
curRevalidate?: number | false
revalidate?: number | false
value: IncrementalCacheValue | null
isStale?: boolean
isMiss?: boolean
} | null

interface IncrementalCache {
get: (key: string) => Promise<IncrementalCacheItem>
set: (
key: string,
data: IncrementalCacheValue | null,
revalidate?: number | false
) => Promise<void>
}
export * from './types'

export default class ResponseCache {
incrementalCache: IncrementalCache
Expand Down

0 comments on commit 0c95a93

Please sign in to comment.