source: trip-planner-front/node_modules/@angular-devkit/build-angular/src/sass/sass-service.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 7.4 KB
Line 
1"use strict";
2/**
3 * @license
4 * Copyright Google LLC All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.io/license
8 */
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.SassWorkerImplementation = void 0;
11const worker_threads_1 = require("worker_threads");
12const environment_options_1 = require("../utils/environment-options");
13/**
14 * The maximum number of Workers that will be created to execute render requests.
15 */
16const MAX_RENDER_WORKERS = environment_options_1.maxWorkers;
17/**
18 * Workaround required for lack of new Worker transfer list support in Node.js prior to 12.17
19 */
20let transferListWorkaround = false;
21const version = process.versions.node.split('.').map((part) => Number(part));
22if (version[0] === 12 && version[1] < 17) {
23 transferListWorkaround = true;
24}
25/**
26 * A Sass renderer implementation that provides an interface that can be used by Webpack's
27 * `sass-loader`. The implementation uses a Worker thread to perform the Sass rendering
28 * with the `dart-sass` package. The `dart-sass` synchronous render function is used within
29 * the worker which can be up to two times faster than the asynchronous variant.
30 */
31class SassWorkerImplementation {
32 constructor() {
33 this.workers = [];
34 this.availableWorkers = [];
35 this.requests = new Map();
36 this.idCounter = 1;
37 this.nextWorkerIndex = 0;
38 }
39 /**
40 * Provides information about the Sass implementation.
41 * This mimics enough of the `dart-sass` value to be used with the `sass-loader`.
42 */
43 get info() {
44 return 'dart-sass\tworker';
45 }
46 /**
47 * The synchronous render function is not used by the `sass-loader`.
48 */
49 renderSync() {
50 throw new Error('Sass renderSync is not supported.');
51 }
52 /**
53 * Asynchronously request a Sass stylesheet to be renderered.
54 *
55 * @param options The `dart-sass` options to use when rendering the stylesheet.
56 * @param callback The function to execute when the rendering is complete.
57 */
58 render(options, callback) {
59 // The `functions` and `importer` options are JavaScript functions that cannot be transferred.
60 // If any additional function options are added in the future, they must be excluded as well.
61 const { functions, importer, ...serializableOptions } = options;
62 // The CLI's configuration does not use or expose the ability to defined custom Sass functions
63 if (functions && Object.keys(functions).length > 0) {
64 throw new Error('Sass custom functions are not supported.');
65 }
66 let workerIndex = this.availableWorkers.pop();
67 if (workerIndex === undefined) {
68 if (this.workers.length < MAX_RENDER_WORKERS) {
69 workerIndex = this.workers.length;
70 this.workers.push(this.createWorker());
71 }
72 else {
73 workerIndex = this.nextWorkerIndex++;
74 if (this.nextWorkerIndex >= this.workers.length) {
75 this.nextWorkerIndex = 0;
76 }
77 }
78 }
79 const request = this.createRequest(workerIndex, callback, importer);
80 this.requests.set(request.id, request);
81 this.workers[workerIndex].postMessage({
82 id: request.id,
83 hasImporter: !!importer,
84 options: serializableOptions,
85 });
86 }
87 /**
88 * Shutdown the Sass render worker.
89 * Executing this method will stop any pending render requests.
90 */
91 close() {
92 for (const worker of this.workers) {
93 try {
94 void worker.terminate();
95 }
96 catch { }
97 }
98 this.requests.clear();
99 }
100 createWorker() {
101 const { port1: mainImporterPort, port2: workerImporterPort } = new worker_threads_1.MessageChannel();
102 const importerSignal = new Int32Array(new SharedArrayBuffer(4));
103 const workerPath = require.resolve('./worker');
104 const worker = new worker_threads_1.Worker(workerPath, {
105 workerData: transferListWorkaround ? undefined : { workerImporterPort, importerSignal },
106 transferList: transferListWorkaround ? undefined : [workerImporterPort],
107 });
108 if (transferListWorkaround) {
109 worker.postMessage({ init: true, workerImporterPort, importerSignal }, [workerImporterPort]);
110 }
111 worker.on('message', (response) => {
112 const request = this.requests.get(response.id);
113 if (!request) {
114 return;
115 }
116 this.requests.delete(response.id);
117 this.availableWorkers.push(request.workerIndex);
118 if (response.result) {
119 // The results are expected to be Node.js `Buffer` objects but will each be transferred as
120 // a Uint8Array that does not have the expected `toString` behavior of a `Buffer`.
121 const { css, map, stats } = response.result;
122 const result = {
123 // This `Buffer.from` override will use the memory directly and avoid making a copy
124 css: Buffer.from(css.buffer, css.byteOffset, css.byteLength),
125 stats,
126 };
127 if (map) {
128 // This `Buffer.from` override will use the memory directly and avoid making a copy
129 result.map = Buffer.from(map.buffer, map.byteOffset, map.byteLength);
130 }
131 request.callback(undefined, result);
132 }
133 else {
134 request.callback(response.error);
135 }
136 });
137 mainImporterPort.on('message', ({ id, url, prev, fromImport, }) => {
138 const request = this.requests.get(id);
139 if (!(request === null || request === void 0 ? void 0 : request.importers)) {
140 mainImporterPort.postMessage(null);
141 Atomics.store(importerSignal, 0, 1);
142 Atomics.notify(importerSignal, 0);
143 return;
144 }
145 this.processImporters(request.importers, url, prev, fromImport)
146 .then((result) => {
147 mainImporterPort.postMessage(result);
148 })
149 .catch((error) => {
150 mainImporterPort.postMessage(error);
151 })
152 .finally(() => {
153 Atomics.store(importerSignal, 0, 1);
154 Atomics.notify(importerSignal, 0);
155 });
156 });
157 mainImporterPort.unref();
158 return worker;
159 }
160 async processImporters(importers, url, prev, fromImport) {
161 let result = null;
162 for (const importer of importers) {
163 result = await new Promise((resolve) => {
164 // Importers can be both sync and async
165 const innerResult = importer.call({ fromImport }, url, prev, resolve);
166 if (innerResult !== undefined) {
167 resolve(innerResult);
168 }
169 });
170 if (result) {
171 break;
172 }
173 }
174 return result;
175 }
176 createRequest(workerIndex, callback, importer) {
177 return {
178 id: this.idCounter++,
179 workerIndex,
180 callback,
181 importers: !importer || Array.isArray(importer) ? importer : [importer],
182 };
183 }
184}
185exports.SassWorkerImplementation = SassWorkerImplementation;
Note: See TracBrowser for help on using the repository browser.