Skip to content

Commit

Permalink
fix(@angular-devkit/build-angular): ensure Sass worker implementation…
Browse files Browse the repository at this point in the history
… supports Node.js 12.14

The Worker constructor option for a transfer list is unfortunately not supported until Node.js 12.17. For Node.js versions prior to 12.17, a manual message post is now used to transfer the necessary initialization data to the Sass workers.
  • Loading branch information
clydin committed May 21, 2021
1 parent 6dcb040 commit 4dc7cf9
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
17 changes: 15 additions & 2 deletions packages/angular_devkit/build_angular/src/sass/sass-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ interface RenderResponseMessage {
result?: Result;
}

/**
* Workaround required for lack of new Worker transfer list support in Node.js prior to 12.17
*/
let transferListWorkaround = false;
const version = process.versions.node.split('.').map((part) => Number(part));
if (version[0] === 12 && version[1] < 17) {
transferListWorkaround = true;
}

/**
* A Sass renderer implementation that provides an interface that can be used by Webpack's
* `sass-loader`. The implementation uses a Worker thread to perform the Sass rendering
Expand Down Expand Up @@ -126,10 +135,14 @@ export class SassWorkerImplementation {

const workerPath = require.resolve('./worker');
const worker = new Worker(workerPath, {
workerData: { workerImporterPort, importerSignal },
transferList: [workerImporterPort],
workerData: transferListWorkaround ? undefined : { workerImporterPort, importerSignal },
transferList: transferListWorkaround ? undefined : [workerImporterPort],
});

if (transferListWorkaround) {
worker.postMessage({ init: true, workerImporterPort, importerSignal }, [workerImporterPort]);
}

worker.on('message', (response: RenderResponseMessage) => {
const request = this.requests.get(response.id);
if (!request) {
Expand Down
31 changes: 25 additions & 6 deletions packages/angular_devkit/build_angular/src/sass/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,46 @@ interface RenderRequestMessage {
* importer on the main thread.
*/
id: number;

/**
* The Sass options to provide to the `dart-sass` render function.
*/
options: Options;

/**
* Indicates the request has a custom importer function on the main thread.
*/
hasImporter: boolean;

/**
* Indicates this is not an init message.
*/
init: undefined;
}

interface InitMessage {
init: true;
workerImporterPort: MessagePort;
importerSignal: Int32Array;
}

if (!parentPort || !workerData) {
if (!parentPort) {
throw new Error('Sass worker must be executed as a Worker.');
}

// The importer variables are used to proxy import requests to the main thread
const { workerImporterPort, importerSignal } = workerData as {
workerImporterPort: MessagePort;
importerSignal: Int32Array;
};
let { workerImporterPort, importerSignal } = (workerData || {}) as InitMessage;

parentPort.on('message', (message: RenderRequestMessage | InitMessage) => {
// The init message is only needed to support Node.js < 12.17 and can be removed once support is dropped
if (message.init) {
workerImporterPort = message.workerImporterPort;
importerSignal = message.importerSignal;

return;
}

parentPort.on('message', ({ id, hasImporter, options }: RenderRequestMessage) => {
const { id, hasImporter, options } = message;
try {
if (hasImporter) {
// When a custom importer function is present, the importer request must be proxied
Expand Down

0 comments on commit 4dc7cf9

Please sign in to comment.