Skip to content

Commit

Permalink
refactor: bring dev service into managed object
Browse files Browse the repository at this point in the history
  • Loading branch information
wyattjoh committed Oct 5, 2023
1 parent 3f73d9a commit f92957b
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 147 deletions.
43 changes: 12 additions & 31 deletions packages/next/src/server/dev/next-dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
NextParsedUrlQuery,
NextUrlWithParsedQuery,
} from '../request-meta'
import type { DevHandlers } from '../lib/dev-handlers'
import type { DevBundlerService } from '../lib/dev-bundler-service'

import fs from 'fs'
import { Worker } from 'next/dist/compiled/jest-worker'
Expand Down Expand Up @@ -81,6 +81,11 @@ export interface Options extends ServerOptions {
* Tells of Next.js is running from the `next dev` command
*/
isNextDevCommand?: boolean

/**
* Interface to the development bundler.
*/
bundlerService: DevBundlerService
}

export default class DevServer extends Server {
Expand All @@ -93,25 +98,12 @@ export default class DevServer extends Server {
private actualInstrumentationHookFile?: string
private middleware?: MiddlewareRoutingItem
private originalFetch: typeof fetch
private readonly bundlerService: DevBundlerService
private staticPathsCache: LRUCache<
string,
UnwrapPromise<ReturnType<DevServer['getStaticPaths']>>
>

private invokeDevMethod<M extends keyof DevHandlers>({
method,
args,
}: {
method: M
/**
* This filters out the first `dir` argument from the method signature, as
* it's added by this method when invoking.
*/
args: DevHandlers[M] extends (_: any, ...rest: infer P) => any ? P : never
}) {
return (global as any)._nextDevHandlers[method](this.dir, ...args)
}

protected staticPathsWorker?: { [key: string]: any } & {
loadStaticPaths: typeof import('./static-paths-worker').loadStaticPaths
}
Expand Down Expand Up @@ -151,6 +143,7 @@ export default class DevServer extends Server {
Error.stackTraceLimit = 50
} catch {}
super({ ...options, dev: true })
this.bundlerService = options.bundlerService
this.originalFetch = global.fetch
this.renderOpts.dev = true
this.renderOpts.appDirDevErrorLogger = (err: any) =>
Expand Down Expand Up @@ -498,10 +491,7 @@ export default class DevServer extends Server {
err?: unknown,
type?: 'unhandledRejection' | 'uncaughtException' | 'warning' | 'app-dir'
): Promise<void> {
await this.invokeDevMethod({
method: 'logErrorWithOriginalStack',
args: [err, type],
})
await this.bundlerService.logErrorWithOriginalStack(err, type)
}

protected getPagesManifest(): PagesManifest | undefined {
Expand Down Expand Up @@ -743,10 +733,7 @@ export default class DevServer extends Server {
appPaths?: ReadonlyArray<string> | null
definition: RouteDefinition | undefined
}): Promise<void> {
await this.invokeDevMethod({
method: 'ensurePage',
args: [opts],
})
await this.bundlerService.ensurePage(opts)
}

protected async findPageComponents({
Expand Down Expand Up @@ -804,17 +791,11 @@ export default class DevServer extends Server {
}

protected async getFallbackErrorComponents(): Promise<LoadComponentsReturnType | null> {
await this.invokeDevMethod({
method: 'getFallbackErrorComponents',
args: [],
})
await this.bundlerService.getFallbackErrorComponents()
return await loadDefaultErrorComponents(this.distDir)
}

async getCompilationError(page: string): Promise<any> {
return await this.invokeDevMethod({
method: 'getCompilationError',
args: [page],
})
return await this.bundlerService.getCompilationError(page)
}
}
74 changes: 74 additions & 0 deletions packages/next/src/server/lib/dev-bundler-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { IncomingMessage } from 'http'
import type { DevBundler } from './router-utils/setup-dev-bundler'
import type { WorkerRequestHandler } from './types'

import { createRequestResponseMocks } from './mock-request'

/**
* The DevBundlerService provides an interface to perform tasks with the
* bundler while in development.
*/
export class DevBundlerService {
constructor(
private readonly bundler: DevBundler,
private readonly handler: WorkerRequestHandler
) {}

public ensurePage: typeof this.bundler.hotReloader.ensurePage = async (
definition
) => {
// TODO: remove after ensure is pulled out of server
return await this.bundler.hotReloader.ensurePage(definition)
}

public logErrorWithOriginalStack: typeof this.bundler.logErrorWithOriginalStack =
async (...args) => {
return await this.bundler.logErrorWithOriginalStack(...args)
}

public async getFallbackErrorComponents() {
await this.bundler.hotReloader.buildFallbackError()
// Build the error page to ensure the fallback is built too.
// TODO: See if this can be moved into hotReloader or removed.
await this.bundler.hotReloader.ensurePage({
page: '/_error',
clientOnly: false,
definition: undefined,
})
}

public async getCompilationError(page: string) {
const errors = await this.bundler.hotReloader.getCompilationErrors(page)
if (!errors) return

// Return the very first error we found.
return errors[0]
}

public async revalidate({
urlPath,
revalidateHeaders,
opts: revalidateOpts,
}: {
urlPath: string
revalidateHeaders: IncomingMessage['headers']
opts: any
}) {
const mocked = createRequestResponseMocks({
url: urlPath,
headers: revalidateHeaders,
})

await this.handler(mocked.req, mocked.res)
await mocked.res.hasStreamed

if (
mocked.res.getHeader('x-nextjs-cache') !== 'REVALIDATED' &&
!(mocked.res.statusCode === 404 && revalidateOpts.unstable_onlyGenerated)
) {
throw new Error(`Invalid response ${mocked.res.statusCode}`)
}

return {}
}
}
27 changes: 0 additions & 27 deletions packages/next/src/server/lib/dev-handlers.ts

This file was deleted.

2 changes: 2 additions & 0 deletions packages/next/src/server/lib/render-server.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { NextServer, RequestHandler } from '../next'
import type { DevBundlerService } from './dev-bundler-service'

import next from '../next'
import { PropagateToWorkersField } from './router-utils/types'
Expand Down Expand Up @@ -79,6 +80,7 @@ async function initializeImpl(opts: {
experimentalHttpsServer: boolean
_ipcPort?: string
_ipcKey?: string
bundlerService: DevBundlerService | undefined
}) {
const type = process.env.__NEXT_PRIVATE_RENDER_WORKER
if (type) {
Expand Down
Loading

0 comments on commit f92957b

Please sign in to comment.