Skip to content

Commit

Permalink
fix(@nguniversal/builders): import zone.js in worker during prerend…
Browse files Browse the repository at this point in the history
…ering

In some cases, zone.js might not be part of the bundle, which cause zone async task not be patched and awaited correctly prior of rendering.
  • Loading branch information
alan-agius4 committed Oct 14, 2022
1 parent 2edfc30 commit 654c23c
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 6 deletions.
6 changes: 4 additions & 2 deletions modules/builders/src/prerender/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,13 @@ async function _renderUniversal(
browserOptions.optimization,
);

const zonePackage = require.resolve('zone.js', { paths: [context.workspaceRoot] });

const { baseOutputPath = '' } = serverResult;
const worker = new Piscina({
filename: path.join(__dirname, 'worker.js'),
name: 'render',
maxThreads: numProcesses,
workerData: { zonePackage },
});

try {
Expand All @@ -131,7 +133,7 @@ async function _renderUniversal(
serverBundlePath,
};

return worker.run(options, { name: 'render' });
return worker.run(options);
}),
)) as RenderResult[];
let numErrors = 0;
Expand Down
37 changes: 33 additions & 4 deletions modules/builders/src/prerender/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@

import type { Type } from '@angular/core';
import type * as platformServer from '@angular/platform-server';
import assert from 'assert';
import * as fs from 'fs';
import * as path from 'path';
import assert from 'node:assert';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { workerData } from 'node:worker_threads';
import { loadEsmModule } from '../utils/utils';

export interface RenderOptions {
Expand All @@ -27,10 +28,18 @@ export interface RenderResult {
warnings?: string[];
}

/**
* The fully resolved path to the zone.js package that will be loaded during worker initialization.
* This is passed as workerData when setting up the worker via the `piscina` package.
*/
const { zonePackage } = workerData as {
zonePackage: string;
};

/**
* Renders each route in routes and writes them to <outputPath>/<route>/index.html.
*/
export async function render({
async function render({
indexFile,
deployUrl,
minifyCss,
Expand Down Expand Up @@ -108,3 +117,23 @@ export async function render({

return result;
}

/**
* Initializes the worker when it is first created by loading the Zone.js package
* into the worker instance.
*
* @returns A promise resolving to the render function of the worker.
*/
async function initialize() {
// Setup Zone.js
await import(zonePackage);

// Return the render function for use
return render;
}

/**
* The default export will be the promise returned by the initialize function.
* This is awaited by piscina prior to using the Worker.
*/
export default initialize();
2 changes: 2 additions & 0 deletions modules/builders/testing/hello-world-app/src/main.server.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'zone.js';

import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';

Expand Down

0 comments on commit 654c23c

Please sign in to comment.