diff --git a/packages/angular/build/src/utils/server-rendering/prerender.ts b/packages/angular/build/src/utils/server-rendering/prerender.ts index 5b42f8c739ef..f8796a7ac861 100644 --- a/packages/angular/build/src/utils/server-rendering/prerender.ts +++ b/packages/angular/build/src/utils/server-rendering/prerender.ts @@ -81,7 +81,11 @@ export async function prerenderPages( } // Get routes to prerender - const { routes: allRoutes, warnings: routesWarnings } = await getAllRoutes( + const { + routes: allRoutes, + warnings: routesWarnings, + errors: routesErrors, + } = await getAllRoutes( workspaceRoot, outputFilesForWorker, assetsReversed, @@ -92,11 +96,15 @@ export async function prerenderPages( verbose, ); + if (routesErrors?.length) { + errors.push(...routesErrors); + } + if (routesWarnings?.length) { warnings.push(...routesWarnings); } - if (allRoutes.size < 1) { + if (allRoutes.size < 1 || errors.length > 0) { return { errors, warnings, @@ -190,22 +198,27 @@ async function renderPages( const isAppShellRoute = appShellRoute === route; const serverContext: ServerContext = isAppShellRoute ? 'app-shell' : 'ssg'; const render: Promise = renderWorker.run({ route, serverContext }); - const renderResult: Promise = render.then(({ content, warnings, errors }) => { - if (content !== undefined) { - const outPath = isAppShellRoute - ? 'index.html' - : posix.join(removeLeadingSlash(route), 'index.html'); - output[outPath] = content; - } - - if (warnings) { - warnings.push(...warnings); - } - - if (errors) { - errors.push(...errors); - } - }); + const renderResult: Promise = render + .then(({ content, warnings, errors }) => { + if (content !== undefined) { + const outPath = isAppShellRoute + ? 'index.html' + : posix.join(removeLeadingSlash(route), 'index.html'); + output[outPath] = content; + } + + if (warnings) { + warnings.push(...warnings); + } + + if (errors) { + errors.push(...errors); + } + }) + .catch((err) => { + errors.push(`An error occurred while prerendering route '${route}'.\n\n${err.stack}`); + void renderWorker.destroy(); + }); renderingPromises.push(renderResult); } @@ -231,7 +244,7 @@ async function getAllRoutes( prerenderOptions: PrerenderOptions, sourcemap: boolean, verbose: boolean, -): Promise<{ routes: Set; warnings?: string[] }> { +): Promise<{ routes: Set; warnings?: string[]; errors?: string[] }> { const { routesFile, discoverRoutes } = prerenderOptions; const routes = new RoutesSet(); const { route: appShellRoute } = appShellOptions; @@ -275,8 +288,12 @@ async function getAllRoutes( recordTiming: false, }); + const errors: string[] = []; const { routes: extractedRoutes, warnings }: RoutersExtractorWorkerResult = await renderWorker .run({}) + .catch((err) => { + errors.push(`An error occurred while extracting routes.\n\n${err.stack}`); + }) .finally(() => { void renderWorker.destroy(); }); @@ -285,7 +302,7 @@ async function getAllRoutes( routes.add(route); } - return { routes, warnings }; + return { routes, warnings, errors }; } function addLeadingSlash(value: string): string { diff --git a/packages/angular_devkit/build_angular/src/builders/server/tests/behavior/build-errors_spec.ts b/packages/angular_devkit/build_angular/src/builders/server/tests/behavior/build-errors_spec.ts index 0fbb12794a62..11bd6b94b25e 100644 --- a/packages/angular_devkit/build_angular/src/builders/server/tests/behavior/build-errors_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/server/tests/behavior/build-errors_spec.ts @@ -15,13 +15,14 @@ describeBuilder(execute, SERVER_BUILDER_INFO, (harness) => { it('emits errors', async () => { harness.useTarget('server', { ...BASE_OPTIONS, - watch: true, }); // Generate an error await harness.appendToFile('src/main.server.ts', `const foo: = 'abc';`); - const { result, logs } = await harness.executeOnce(); + const { result, logs } = await harness.executeOnce({ + outputLogsOnFailure: false, + }); expect(result?.success).toBeFalse(); expect(logs).toContain(