Skip to content

Commit 60a7ec9

Browse files
committed
feat: add pages router rebuilding
1 parent 1872420 commit 60a7ec9

File tree

1 file changed

+122
-63
lines changed

1 file changed

+122
-63
lines changed

packages/next/src/builder.ts

Lines changed: 122 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -163,38 +163,55 @@ async function sendPagesResponse(res, webResponse) {
163163
}
164164

165165
// Build for Pages Router if present
166+
let pagesRouterConfig:
167+
| {
168+
pagesDir: string;
169+
workflowGeneratedDir: string;
170+
}
171+
| undefined;
172+
166173
if (routers.hasPagesRouter && routers.pagesRouterDir) {
174+
const workflowGeneratedDir = join(
175+
routers.pagesRouterDir,
176+
'api/.well-known/workflow/v1'
177+
);
167178
await this.buildForPagesRouter(
168179
routers.pagesRouterDir,
169180
inputFiles,
170181
tsConfig
171182
);
183+
pagesRouterConfig = {
184+
pagesDir: routers.pagesRouterDir,
185+
workflowGeneratedDir,
186+
};
172187
}
173188

174-
// Watch mode only supported for App Router currently
175-
// (Pages Router generates static files that don't need rebuild context)
176-
if (this.config.watch && appRouterBuildResult) {
177-
const { stepsBuildContext, workflowsBundle, workflowGeneratedDir } =
178-
appRouterBuildResult;
179-
if (!stepsBuildContext) {
180-
throw new Error(
181-
'Invariant: expected steps build context in watch mode'
182-
);
183-
}
184-
if (!workflowsBundle) {
185-
throw new Error('Invariant: expected workflows bundle in watch mode');
186-
}
187-
188-
let stepsCtx = stepsBuildContext;
189-
let workflowsCtx = workflowsBundle;
189+
// Watch mode for App Router and/or Pages Router
190+
if (this.config.watch && (appRouterBuildResult || pagesRouterConfig)) {
191+
// App Router watch state (may be undefined if only Pages Router)
192+
let stepsCtx = appRouterBuildResult?.stepsBuildContext;
193+
let workflowsCtx = appRouterBuildResult?.workflowsBundle;
190194

191195
// Options object for rebuild functions
192-
const options = {
193-
inputFiles,
194-
workflowGeneratedDir,
195-
tsBaseUrl: tsConfig.baseUrl,
196-
tsPaths: tsConfig.paths,
197-
};
196+
const appRouterOptions = appRouterBuildResult
197+
? {
198+
inputFiles,
199+
workflowGeneratedDir: appRouterBuildResult.workflowGeneratedDir,
200+
tsBaseUrl: tsConfig.baseUrl,
201+
tsPaths: tsConfig.paths,
202+
}
203+
: null;
204+
205+
// Pages Router rebuild options
206+
const pagesRouterOptions = pagesRouterConfig
207+
? {
208+
inputFiles,
209+
workflowGeneratedDir: pagesRouterConfig.workflowGeneratedDir,
210+
tsBaseUrl: tsConfig.baseUrl,
211+
tsPaths: tsConfig.paths,
212+
pagesDir: pagesRouterConfig.pagesDir,
213+
}
214+
: null;
198215

199216
const normalizePath = (pathname: string) =>
200217
pathname.replace(/\\/g, '/');
@@ -230,8 +247,19 @@ async function sendPagesResponse(res, webResponse) {
230247
'/.parcel-cache/',
231248
'/.well-known/workflow/',
232249
];
233-
const normalizedGeneratedDir = workflowGeneratedDir.replace(/\\/g, '/');
234-
ignoredPathFragments.push(normalizedGeneratedDir);
250+
// Collect all generated directories to ignore
251+
const normalizedGeneratedDirs: string[] = [];
252+
if (appRouterOptions) {
253+
normalizedGeneratedDirs.push(
254+
appRouterOptions.workflowGeneratedDir.replace(/\\/g, '/')
255+
);
256+
}
257+
if (pagesRouterOptions) {
258+
normalizedGeneratedDirs.push(
259+
pagesRouterOptions.workflowGeneratedDir.replace(/\\/g, '/')
260+
);
261+
}
262+
ignoredPathFragments.push(...normalizedGeneratedDirs);
235263

236264
// There is a node.js bug on MacOS which causes closing file watchers to be really slow.
237265
// This limits the number of watchers to mitigate the issue.
@@ -248,8 +276,11 @@ async function sendPagesResponse(res, webResponse) {
248276
if (extension && !watchableExtensions.has(extension)) {
249277
return true;
250278
}
251-
if (normalizedPath.startsWith(normalizedGeneratedDir)) {
252-
return true;
279+
// Check if path is in any of the generated directories
280+
for (const genDir of normalizedGeneratedDirs) {
281+
if (normalizedPath.startsWith(genDir)) {
282+
return true;
283+
}
253284
}
254285
for (const fragment of ignoredPathFragments) {
255286
if (normalizedPath.includes(fragment)) {
@@ -283,25 +314,38 @@ async function sendPagesResponse(res, webResponse) {
283314

284315
const fullRebuild = async () => {
285316
const newInputFiles = await this.getInputFiles();
286-
options.inputFiles = newInputFiles;
287317

288-
await stepsCtx.dispose();
289-
const newStepsCtx = await this.buildStepsFunction(options);
290-
if (!newStepsCtx) {
291-
throw new Error(
292-
'Invariant: expected steps build context after rebuild'
293-
);
318+
// Rebuild App Router if present
319+
if (appRouterOptions && stepsCtx && workflowsCtx) {
320+
appRouterOptions.inputFiles = newInputFiles;
321+
322+
await stepsCtx.dispose();
323+
const newStepsCtx = await this.buildStepsFunction(appRouterOptions);
324+
if (!newStepsCtx) {
325+
throw new Error(
326+
'Invariant: expected steps build context after rebuild'
327+
);
328+
}
329+
stepsCtx = newStepsCtx;
330+
331+
await workflowsCtx.interimBundleCtx.dispose();
332+
const newWorkflowsCtx =
333+
await this.buildWorkflowsFunction(appRouterOptions);
334+
if (!newWorkflowsCtx) {
335+
throw new Error(
336+
'Invariant: expected workflows bundle context after rebuild'
337+
);
338+
}
339+
workflowsCtx = newWorkflowsCtx;
294340
}
295-
stepsCtx = newStepsCtx;
296341

297-
await workflowsCtx.interimBundleCtx.dispose();
298-
const newWorkflowsCtx = await this.buildWorkflowsFunction(options);
299-
if (!newWorkflowsCtx) {
300-
throw new Error(
301-
'Invariant: expected workflows bundle context after rebuild'
302-
);
342+
// Rebuild Pages Router if present
343+
if (pagesRouterOptions) {
344+
pagesRouterOptions.inputFiles = newInputFiles;
345+
await this.buildStepsFunctionPages(pagesRouterOptions);
346+
await this.buildWorkflowsFunctionPages(pagesRouterOptions);
347+
console.log('Rebuilt Pages Router bundles');
303348
}
304-
workflowsCtx = newWorkflowsCtx;
305349
};
306350

307351
const logBuildMessages = (
@@ -330,32 +374,47 @@ async function sendPagesResponse(res, webResponse) {
330374
};
331375

332376
const rebuildExistingFiles = async () => {
333-
const rebuiltStepStart = Date.now();
334-
const stepsResult = await stepsCtx.rebuild();
335-
logBuildMessages(stepsResult, 'steps bundle');
336-
console.log(
337-
'Rebuilt steps bundle',
338-
`${Date.now() - rebuiltStepStart}ms`
339-
);
377+
// Rebuild App Router if present (uses incremental rebuild)
378+
if (stepsCtx && workflowsCtx) {
379+
const rebuiltStepStart = Date.now();
380+
const stepsResult = await stepsCtx.rebuild();
381+
logBuildMessages(stepsResult, 'steps bundle');
382+
console.log(
383+
'Rebuilt steps bundle',
384+
`${Date.now() - rebuiltStepStart}ms`
385+
);
340386

341-
const rebuiltWorkflowStart = Date.now();
342-
const workflowResult = await workflowsCtx.interimBundleCtx.rebuild();
343-
logBuildMessages(workflowResult, 'workflows bundle');
387+
const rebuiltWorkflowStart = Date.now();
388+
const workflowResult =
389+
await workflowsCtx.interimBundleCtx.rebuild();
390+
logBuildMessages(workflowResult, 'workflows bundle');
344391

345-
if (
346-
!workflowResult.outputFiles ||
347-
workflowResult.outputFiles.length === 0
348-
) {
349-
console.error(
350-
'No output generated while rebuilding workflows bundle'
392+
if (
393+
!workflowResult.outputFiles ||
394+
workflowResult.outputFiles.length === 0
395+
) {
396+
console.error(
397+
'No output generated while rebuilding workflows bundle'
398+
);
399+
return;
400+
}
401+
await workflowsCtx.bundleFinal(workflowResult.outputFiles[0].text);
402+
console.log(
403+
'Rebuilt workflow bundle',
404+
`${Date.now() - rebuiltWorkflowStart}ms`
405+
);
406+
}
407+
408+
// Rebuild Pages Router if present (full rebuild since no incremental support)
409+
if (pagesRouterOptions) {
410+
const rebuiltPagesStart = Date.now();
411+
await this.buildStepsFunctionPages(pagesRouterOptions);
412+
await this.buildWorkflowsFunctionPages(pagesRouterOptions);
413+
console.log(
414+
'Rebuilt Pages Router bundles',
415+
`${Date.now() - rebuiltPagesStart}ms`
351416
);
352-
return;
353417
}
354-
await workflowsCtx.bundleFinal(workflowResult.outputFiles[0].text);
355-
console.log(
356-
'Rebuilt workflow bundle',
357-
`${Date.now() - rebuiltWorkflowStart}ms`
358-
);
359418
};
360419

361420
const isWatchableFile = (path: string) =>

0 commit comments

Comments
 (0)