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

refactor: move fs based inc cache to next-server #36246

Closed
wants to merge 3 commits into from
Closed
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
8 changes: 6 additions & 2 deletions packages/next/build/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ 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 { MIDDLEWARE_ROUTE } from '../lib/constants'
import {
API_ROUTE,
DOT_NEXT_ALIAS,
PAGES_DIR_ALIAS,
MIDDLEWARE_ROUTE,
} from '../lib/constants'
import { __ApiPreviewProps } from '../server/api-utils'
import { isTargetLikeServerless } from '../server/utils'
import { normalizePagePath } from '../server/normalize-page-path'
Expand Down
53 changes: 7 additions & 46 deletions packages/next/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import type { Rewrite } from '../lib/load-custom-routes'
import type { RenderOpts, RenderOptsPartial } from './render'
import type { ResponseCacheEntry, ResponseCacheValue } from './response-cache'
import type { UrlWithParsedQuery } from 'url'
import type { CacheFs } from '../shared/lib/utils'
import type { PreviewData } from 'next/types'
import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin'
import type { BaseNextRequest, BaseNextResponse } from './base-http'
Expand All @@ -23,8 +22,6 @@ import { parse as parseQs } from 'querystring'
import { format as formatUrl, parse as parseUrl } from 'url'
import { getRedirectStatus } from '../lib/load-custom-routes'
import {
SERVERLESS_DIRECTORY,
SERVER_DIRECTORY,
STATIC_STATUS_PAGES,
TEMPORARY_REDIRECT_STATUS,
} from '../shared/lib/constants'
Expand All @@ -44,7 +41,6 @@ import { DecodeError, normalizeRepeatedSlashes } from '../shared/lib/utils'
import { isTargetLikeServerless } from './utils'
import Router, { route } from './router'
import { setRevalidateHeaders } from './send-payload/revalidate-headers'
import { IncrementalCache } from './incremental-cache'
import { execOnce } from '../shared/lib/utils'
import { isBlockedPage, isBot } from './utils'
import RenderResult from './render-result'
Expand Down Expand Up @@ -171,8 +167,9 @@ export default abstract class Server {
serverComponentProps?: any
reactRoot: boolean
}
private incrementalCache: IncrementalCache
private responseCache: ResponseCache

protected responseCache: ResponseCache
protected incrementalCache: any
protected router: Router
protected dynamicRoutes?: DynamicRoutes
protected customRoutes: CustomRoutes
Expand Down Expand Up @@ -224,6 +221,8 @@ export default abstract class Server {
protected abstract getRoutesManifest(): CustomRoutes
protected abstract getPrerenderManifest(): PrerenderManifest
protected abstract getServerComponentManifest(): any
protected abstract getIncrementalCache(dev: boolean): any
protected abstract getResponseCache(): any

protected abstract sendRenderResult(
req: BaseNextRequest,
Expand Down Expand Up @@ -350,36 +349,8 @@ export default abstract class Server {
this.router = new Router(this.generateRoutes())
this.setAssetPrefix(assetPrefix)

this.incrementalCache = new IncrementalCache({
fs: this.getCacheFilesystem(),
dev,
distDir: this.distDir,
pagesDir: join(
this.distDir,
this._isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY,
'pages'
),
locales: this.nextConfig.i18n?.locales,
max: this.nextConfig.experimental.isrMemoryCacheSize,
flushToDisk: !minimalMode && this.nextConfig.experimental.isrFlushToDisk,
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.incrementalCache = this.getIncrementalCache(dev)
this.responseCache = this.getResponseCache()
}

public logError(err: Error): void {
Expand Down Expand Up @@ -1893,16 +1864,6 @@ export default abstract class Server {
})
}

protected getCacheFilesystem(): CacheFs {
return {
readFile: () => Promise.resolve(''),
readFileSync: () => '',
writeFile: () => Promise.resolve(),
mkdir: () => Promise.resolve(),
stat: () => Promise.resolve({ mtime: new Date() }),
}
}

protected async getFallbackErrorComponents(): Promise<LoadComponentsReturnType | null> {
// The development server will provide an implementation for this
return null
Expand Down
20 changes: 15 additions & 5 deletions packages/next/server/incremental-cache.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { CacheFs } from '../shared/lib/utils'

import LRUCache from 'next/dist/compiled/lru-cache'
import path from 'path'
import { PrerenderManifest } from '../build'
Expand All @@ -10,6 +8,14 @@ function toRoute(pathname: string): string {
return pathname.replace(/\/$/, '').replace(/\/index$/, '') || '/'
}

interface CacheFs {
readFile(f: string): Promise<string>
readFileSync(f: string): string
writeFile(f: string, d: any): Promise<void>
mkdir(dir: string): Promise<void | string>
stat(f: string): Promise<{ mtime: Date }>
}

export class IncrementalCache {
incrementalOptions: {
flushToDisk?: boolean
Expand All @@ -19,7 +25,7 @@ export class IncrementalCache {
}

prerenderManifest: PrerenderManifest
cache?: LRUCache<string, IncrementalCacheEntry>
cache?: any
locales?: string[]
fs: CacheFs

Expand Down Expand Up @@ -61,7 +67,7 @@ export class IncrementalCache {
if (max) {
this.cache = new LRUCache({
max,
length({ value }) {
length({ value }: any) {
if (!value) {
return 25
} else if (value.kind === 'REDIRECT') {
Expand Down Expand Up @@ -103,7 +109,7 @@ export class IncrementalCache {
return revalidateAfter
}

getFallback(page: string): Promise<string> {
public getFallback(page: string): Promise<string> {
page = normalizePagePath(page)
return this.fs.readFile(this.getSeedPath(page, 'html'))
}
Expand Down Expand Up @@ -216,3 +222,7 @@ export class IncrementalCache {
}
}
}

type IncrementalCacheType = typeof IncrementalCache

export { IncrementalCacheType }
53 changes: 46 additions & 7 deletions packages/next/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import './node-polyfill-fetch'
import './node-polyfill-web-streams'

import type { Params, Route } from './router'
import type { CacheFs } from '../shared/lib/utils'
import type { MiddlewareManifest } from '../build/webpack/plugins/middleware-plugin'
import type RenderResult from './render-result'
import type { FetchEventResult } from './web/types'
Expand Down Expand Up @@ -74,6 +73,7 @@ import { urlQueryToSearchParams } from '../shared/lib/router/utils/querystring'
import ResponseCache from '../server/response-cache'
import { removePathTrailingSlash } from '../client/normalize-trailing-slash'
import { clonableBodyForRequest } from './body-streams'
import { IncrementalCache } from './incremental-cache'

export * from './base-server'

Expand Down Expand Up @@ -113,6 +113,11 @@ export default class NextNodeServer extends BaseServer {
process.env.__NEXT_SCRIPT_WORKERS = JSON.stringify(true)
}

this.responseCache = new ResponseCache(
this.incrementalCache,
this.minimalMode
)

if (!this.minimalMode) {
const { ImageOptimizerCache } =
require('./image-optimizer') as typeof import('./image-optimizer')
Expand Down Expand Up @@ -704,13 +709,13 @@ export default class NextNodeServer extends BaseServer {
))
}

protected getCacheFilesystem(): CacheFs {
protected getCacheFilesystem() {
return {
readFile: (f) => fs.promises.readFile(f, 'utf8'),
readFileSync: (f) => fs.readFileSync(f, 'utf8'),
writeFile: (f, d) => fs.promises.writeFile(f, d, 'utf8'),
mkdir: (dir) => fs.promises.mkdir(dir, { recursive: true }),
stat: (f) => fs.promises.stat(f),
readFile: (f: string) => fs.promises.readFile(f, 'utf8'),
readFileSync: (f: string) => fs.readFileSync(f, 'utf8'),
writeFile: (f: string, d: number) => fs.promises.writeFile(f, d, 'utf8'),
mkdir: (dir: string) => fs.promises.mkdir(dir, { recursive: true }),
stat: (f: string) => fs.promises.stat(f),
}
}

Expand Down Expand Up @@ -1357,4 +1362,38 @@ export default class NextNodeServer extends BaseServer {
this.warnIfQueryParametersWereDeleted = () => {}
}
}

protected getIncrementalCache(dev: boolean) {
return new IncrementalCache({
fs: this.getCacheFilesystem(),
dev,
distDir: this.distDir,
pagesDir: join(
this.distDir,
this._isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY,
'pages'
),
locales: this.nextConfig.i18n?.locales,
max: this.nextConfig.experimental.isrMemoryCacheSize,
flushToDisk:
!this.minimalMode && this.nextConfig.experimental.isrFlushToDisk,
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()
}
},
})
}

protected getResponseCache() {
return new ResponseCache(this.incrementalCache, this.minimalMode)
}
}
30 changes: 30 additions & 0 deletions packages/next/server/web-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,34 @@ export default class NextWebServer extends BaseServer {
components: result,
}
}

protected getIncrementalCache() {
return {
async set() {},
async get() {
return null
},
async getFallback() {
return ''
},
}
}

protected getCacheFilesystem() {
return {
readFile: () => Promise.resolve(''),
readFileSync: () => '',
writeFile: () => Promise.resolve(),
mkdir: () => Promise.resolve(),
stat: () => Promise.resolve({ mtime: new Date() }),
}
}

protected getResponseCache() {
return {
get() {
return null
},
}
}
}
8 changes: 0 additions & 8 deletions packages/next/shared/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,11 +397,3 @@ export const ST =
typeof performance.measure === 'function'

export class DecodeError extends Error {}

export interface CacheFs {
readFile(f: string): Promise<string>
readFileSync(f: string): string
writeFile(f: string, d: any): Promise<void>
mkdir(dir: string): Promise<void | string>
stat(f: string): Promise<{ mtime: Date }>
}
5 changes: 1 addition & 4 deletions packages/next/types/misc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,7 @@ declare module 'next/dist/compiled/lodash.curry' {
import m from 'lodash.curry'
export = m
}
declare module 'next/dist/compiled/lru-cache' {
import m from 'lru-cache'
export = m
}
declare module 'next/dist/compiled/lru-cache'
declare module 'next/dist/compiled/micromatch' {
import m from 'micromatch'
export = m
Expand Down
4 changes: 4 additions & 0 deletions test/integration/react-18/app/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ export default function Index() {
</div>
)
}

export const config = {
// runtime: 'edge'
}
3 changes: 3 additions & 0 deletions test/integration/react-18/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import webdriver from 'next-webdriver'
const appDir = join(__dirname, '../app')
const nextConfig = new File(join(appDir, 'next.config.js'))
const invalidPage = new File(join(appDir, 'pages/invalid.js'))
const indexPage = new File(join(appDir, 'pages/index.js'))

describe('Basics', () => {
runTests('default setting with react 18', basics)
Expand Down Expand Up @@ -67,11 +68,13 @@ function runTestsAgainstRuntime(runtime) {
invalidPage.write(`export const value = 1`)
}
nextConfig.replace("// runtime: 'edge'", `runtime: '${runtime}'`)
indexPage.replace("// runtime: 'edge'", `runtime: '${runtime}'`)
Copy link
Member Author

Choose a reason for hiding this comment

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

Setting page runtime to edge, this wasn't coverred before cause it will be statically optimized.
Adding this to avoid the basic build failed when removing the nodejs polyfills

},
afterAll: (env) => {
if (env === 'dev') {
invalidPage.delete()
}
indexPage.restore()
nextConfig.restore()
},
}
Expand Down