@angular-devkit/build-angular 17.3.1 → 18.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +31 -31
- package/src/builders/app-shell/index.js +1 -1
- package/src/builders/application/build-action.d.ts +2 -3
- package/src/builders/dev-server/builder.d.ts +0 -2
- package/src/builders/dev-server/vite-server.js +14 -7
- package/src/builders/dev-server/webpack-server.js +1 -1
- package/src/builders/prerender/index.d.ts +2 -3
- package/src/builders/ssr-dev-server/utils.d.ts +1 -2
- package/src/tools/babel/plugins/adjust-static-class-members.js +3 -6
- package/src/tools/esbuild/angular/compilation/parallel-worker.d.ts +0 -2
- package/src/tools/esbuild/utils.d.ts +2 -2
- package/src/tools/esbuild/utils.js +1 -1
- package/src/tools/vite/angular-memory-plugin.js +8 -8
- package/src/tools/webpack/configs/dev-server.js +20 -11
- package/src/tools/webpack/configs/styles.js +22 -53
- package/src/tools/webpack/plugins/builder-watch-plugin.js +2 -2
- package/src/tools/webpack/plugins/styles-webpack-plugin.js +1 -1
- package/src/utils/environment-options.d.ts +0 -1
- package/src/utils/environment-options.js +1 -11
- package/src/utils/i18n-options.d.ts +3 -2
- package/src/utils/i18n-options.js +39 -33
- package/src/utils/index-file/inline-fonts.d.ts +0 -2
- package/src/utils/normalize-asset-patterns.d.ts +1 -2
- package/src/utils/normalize-asset-patterns.js +1 -2
- package/src/utils/normalize-cache.d.ts +1 -2
- package/src/utils/normalize-cache.js +10 -5
- package/src/utils/normalize-file-replacements.d.ts +1 -2
- package/src/utils/normalize-file-replacements.js +1 -2
- package/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.js +0 -2
- package/src/utils/server-rendering/prerender.js +11 -3
- package/src/utils/service-worker.d.ts +2 -2
- package/src/utils/supported-browsers.d.ts +3 -2
- package/src/utils/webpack-browser-config.d.ts +1 -2
- package/src/tools/sass/sass-service-legacy.d.ts +0 -51
- package/src/tools/sass/sass-service-legacy.js +0 -173
- package/src/tools/sass/worker-legacy.d.ts +0 -8
- package/src/tools/sass/worker-legacy.js +0 -43
- package/src/utils/server-rendering/esm-in-memory-loader/node-18-utils.d.ts +0 -10
- package/src/utils/server-rendering/esm-in-memory-loader/node-18-utils.js +0 -39
|
@@ -11,11 +11,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
11
11
|
};
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.loadTranslations = exports.configureI18nBuild = exports.createI18nOptions = void 0;
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
15
|
+
const node_module_1 = require("node:module");
|
|
16
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
17
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
19
18
|
const schema_1 = require("../builders/browser/schema");
|
|
20
19
|
const read_tsconfig_1 = require("../utils/read-tsconfig");
|
|
21
20
|
const load_translations_1 = require("./load-translations");
|
|
@@ -39,11 +38,19 @@ function normalizeTranslationFileOption(option, locale, expectObjectInError) {
|
|
|
39
38
|
}
|
|
40
39
|
throw new Error(errorMessage);
|
|
41
40
|
}
|
|
42
|
-
function
|
|
43
|
-
if (
|
|
44
|
-
throw new Error(
|
|
41
|
+
function ensureObject(value, name) {
|
|
42
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
43
|
+
throw new Error(`Project ${name} field is malformed. Expected an object.`);
|
|
45
44
|
}
|
|
46
|
-
|
|
45
|
+
}
|
|
46
|
+
function ensureString(value, name) {
|
|
47
|
+
if (typeof value !== 'string') {
|
|
48
|
+
throw new Error(`Project ${name} field is malformed. Expected a string.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function createI18nOptions(projectMetadata, inline) {
|
|
52
|
+
const { i18n: metadata = {} } = projectMetadata;
|
|
53
|
+
ensureObject(metadata, 'i18n');
|
|
47
54
|
const i18n = {
|
|
48
55
|
inlineLocales: new Set(),
|
|
49
56
|
// en-US is the default locale added to Angular applications (https://angular.io/guide/i18n#i18n-pipes)
|
|
@@ -55,21 +62,21 @@ function createI18nOptions(metadata, inline) {
|
|
|
55
62
|
};
|
|
56
63
|
let rawSourceLocale;
|
|
57
64
|
let rawSourceLocaleBaseHref;
|
|
58
|
-
if (
|
|
59
|
-
rawSourceLocale = metadata.sourceLocale.code;
|
|
60
|
-
if (metadata.sourceLocale.baseHref !== undefined &&
|
|
61
|
-
typeof metadata.sourceLocale.baseHref !== 'string') {
|
|
62
|
-
throw new Error('Project i18n sourceLocale baseHref field is malformed. Expected a string.');
|
|
63
|
-
}
|
|
64
|
-
rawSourceLocaleBaseHref = metadata.sourceLocale.baseHref;
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
65
|
+
if (typeof metadata.sourceLocale === 'string') {
|
|
67
66
|
rawSourceLocale = metadata.sourceLocale;
|
|
68
67
|
}
|
|
69
|
-
if (
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
else if (metadata.sourceLocale !== undefined) {
|
|
69
|
+
ensureObject(metadata.sourceLocale, 'i18n sourceLocale');
|
|
70
|
+
if (metadata.sourceLocale.code !== undefined) {
|
|
71
|
+
ensureString(metadata.sourceLocale.code, 'i18n sourceLocale code');
|
|
72
|
+
rawSourceLocale = metadata.sourceLocale.code;
|
|
73
|
+
}
|
|
74
|
+
if (metadata.sourceLocale.baseHref !== undefined) {
|
|
75
|
+
ensureString(metadata.sourceLocale.baseHref, 'i18n sourceLocale baseHref');
|
|
76
|
+
rawSourceLocaleBaseHref = metadata.sourceLocale.baseHref;
|
|
72
77
|
}
|
|
78
|
+
}
|
|
79
|
+
if (rawSourceLocale !== undefined) {
|
|
73
80
|
i18n.sourceLocale = rawSourceLocale;
|
|
74
81
|
i18n.hasDefinedSourceLocale = true;
|
|
75
82
|
}
|
|
@@ -77,16 +84,15 @@ function createI18nOptions(metadata, inline) {
|
|
|
77
84
|
files: [],
|
|
78
85
|
baseHref: rawSourceLocaleBaseHref,
|
|
79
86
|
};
|
|
80
|
-
if (metadata.locales !== undefined
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
else if (metadata.locales) {
|
|
87
|
+
if (metadata.locales !== undefined) {
|
|
88
|
+
ensureObject(metadata.locales, 'i18n locales');
|
|
84
89
|
for (const [locale, options] of Object.entries(metadata.locales)) {
|
|
85
90
|
let translationFiles;
|
|
86
91
|
let baseHref;
|
|
87
|
-
if (
|
|
92
|
+
if (options && typeof options === 'object' && 'translation' in options) {
|
|
88
93
|
translationFiles = normalizeTranslationFileOption(options.translation, locale, false);
|
|
89
|
-
if (
|
|
94
|
+
if ('baseHref' in options) {
|
|
95
|
+
ensureString(options.baseHref, `i18n locales ${locale} baseHref`);
|
|
90
96
|
baseHref = options.baseHref;
|
|
91
97
|
}
|
|
92
98
|
}
|
|
@@ -129,10 +135,10 @@ async function configureI18nBuild(context, options) {
|
|
|
129
135
|
if (!i18n.shouldInline && !i18n.hasDefinedSourceLocale) {
|
|
130
136
|
return { buildOptions, i18n };
|
|
131
137
|
}
|
|
132
|
-
const projectRoot =
|
|
138
|
+
const projectRoot = node_path_1.default.join(context.workspaceRoot, metadata.root || '');
|
|
133
139
|
// The trailing slash is required to signal that the path is a directory and not a file.
|
|
134
|
-
const projectRequire =
|
|
135
|
-
const localeResolver = (locale) => projectRequire.resolve(
|
|
140
|
+
const projectRequire = (0, node_module_1.createRequire)(projectRoot + '/');
|
|
141
|
+
const localeResolver = (locale) => projectRequire.resolve(node_path_1.default.join(LOCALE_DATA_BASE_MODULE, locale));
|
|
136
142
|
// Load locale data and translations (if present)
|
|
137
143
|
let loader;
|
|
138
144
|
const usedFormats = new Set();
|
|
@@ -177,11 +183,11 @@ async function configureI18nBuild(context, options) {
|
|
|
177
183
|
if (i18n.shouldInline) {
|
|
178
184
|
// TODO: we should likely save these in the .angular directory in the next major version.
|
|
179
185
|
// We'd need to do a migration to add the temp directory to gitignore.
|
|
180
|
-
const tempPath =
|
|
186
|
+
const tempPath = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_fs_1.default.realpathSync(node_os_1.default.tmpdir()), 'angular-cli-i18n-'));
|
|
181
187
|
buildOptions.outputPath = tempPath;
|
|
182
188
|
process.on('exit', () => {
|
|
183
189
|
try {
|
|
184
|
-
|
|
190
|
+
node_fs_1.default.rmSync(tempPath, { force: true, recursive: true, maxRetries: 3 });
|
|
185
191
|
}
|
|
186
192
|
catch { }
|
|
187
193
|
});
|
|
@@ -203,7 +209,7 @@ function findLocaleDataPath(locale, resolver) {
|
|
|
203
209
|
function loadTranslations(locale, desc, workspaceRoot, loader, logger, usedFormats, duplicateTranslation) {
|
|
204
210
|
let translations = undefined;
|
|
205
211
|
for (const file of desc.files) {
|
|
206
|
-
const loadResult = loader(
|
|
212
|
+
const loadResult = loader(node_path_1.default.join(workspaceRoot, file.path));
|
|
207
213
|
for (const diagnostics of loadResult.diagnostics.messages) {
|
|
208
214
|
if (diagnostics.type === 'error') {
|
|
209
215
|
logger.error(`Error parsing translation file '${file.path}': ${diagnostics.message}`);
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
8
|
/// <reference types="node" />
|
|
9
|
-
/// <reference types="@types/node/url" />
|
|
10
|
-
/// <reference types="@types/node/ts4.8/url" />
|
|
11
9
|
import { URL } from 'node:url';
|
|
12
10
|
import { NormalizedCachedOptions } from '../normalize-cache';
|
|
13
11
|
export interface InlineFontsOptions {
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
|
-
import { BaseException } from '@angular-devkit/core';
|
|
9
8
|
import { AssetPattern, AssetPatternClass } from '../builders/browser/schema';
|
|
10
|
-
export declare class MissingAssetSourceRootException extends
|
|
9
|
+
export declare class MissingAssetSourceRootException extends Error {
|
|
11
10
|
constructor(path: string);
|
|
12
11
|
}
|
|
13
12
|
export declare function normalizeAssetPatterns(assetPatterns: AssetPattern[], workspaceRoot: string, projectRoot: string, projectSourceRoot: string | undefined): AssetPatternClass[];
|
|
@@ -31,10 +31,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
31
31
|
};
|
|
32
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
33
|
exports.normalizeAssetPatterns = exports.MissingAssetSourceRootException = void 0;
|
|
34
|
-
const core_1 = require("@angular-devkit/core");
|
|
35
34
|
const fs_1 = require("fs");
|
|
36
35
|
const path = __importStar(require("path"));
|
|
37
|
-
class MissingAssetSourceRootException extends
|
|
36
|
+
class MissingAssetSourceRootException extends Error {
|
|
38
37
|
constructor(path) {
|
|
39
38
|
super(`The ${path} asset path must start with the project source root.`);
|
|
40
39
|
}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
|
-
import { json } from '@angular-devkit/core';
|
|
9
8
|
export interface NormalizedCachedOptions {
|
|
10
9
|
/** Whether disk cache is enabled. */
|
|
11
10
|
enabled: boolean;
|
|
@@ -14,4 +13,4 @@ export interface NormalizedCachedOptions {
|
|
|
14
13
|
/** Disk cache base path. Example: `/.angular/cache`. */
|
|
15
14
|
basePath: string;
|
|
16
15
|
}
|
|
17
|
-
export declare function normalizeCacheOptions(
|
|
16
|
+
export declare function normalizeCacheOptions(projectMetadata: unknown, worspaceRoot: string): NormalizedCachedOptions;
|
|
@@ -8,13 +8,18 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.normalizeCacheOptions = void 0;
|
|
11
|
-
const core_1 = require("@angular-devkit/core");
|
|
12
11
|
const path_1 = require("path");
|
|
13
12
|
const package_version_1 = require("./package-version");
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
function hasCacheMetadata(value) {
|
|
14
|
+
return (!!value &&
|
|
15
|
+
typeof value === 'object' &&
|
|
16
|
+
'cli' in value &&
|
|
17
|
+
!!value['cli'] &&
|
|
18
|
+
typeof value['cli'] === 'object' &&
|
|
19
|
+
'cache' in value['cli']);
|
|
20
|
+
}
|
|
21
|
+
function normalizeCacheOptions(projectMetadata, worspaceRoot) {
|
|
22
|
+
const cacheMetadata = hasCacheMetadata(projectMetadata) ? projectMetadata.cli.cache : {};
|
|
18
23
|
const { enabled = true, environment = 'local', path = '.angular/cache' } = cacheMetadata;
|
|
19
24
|
const isCI = process.env['CI'] === '1' || process.env['CI']?.toLowerCase() === 'true';
|
|
20
25
|
let cacheEnabled = enabled;
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
|
-
import { BaseException } from '@angular-devkit/core';
|
|
9
8
|
import { FileReplacement } from '../builders/browser/schema';
|
|
10
|
-
export declare class MissingFileReplacementException extends
|
|
9
|
+
export declare class MissingFileReplacementException extends Error {
|
|
11
10
|
constructor(path: string);
|
|
12
11
|
}
|
|
13
12
|
export interface NormalizedFileReplacement {
|
|
@@ -31,10 +31,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
31
31
|
};
|
|
32
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
33
|
exports.normalizeFileReplacements = exports.MissingFileReplacementException = void 0;
|
|
34
|
-
const core_1 = require("@angular-devkit/core");
|
|
35
34
|
const fs_1 = require("fs");
|
|
36
35
|
const path = __importStar(require("path"));
|
|
37
|
-
class MissingFileReplacementException extends
|
|
36
|
+
class MissingFileReplacementException extends Error {
|
|
38
37
|
constructor(path) {
|
|
39
38
|
super(`The ${path} path in file replacements does not exist.`);
|
|
40
39
|
}
|
|
@@ -17,7 +17,6 @@ const node_path_1 = require("node:path");
|
|
|
17
17
|
const node_url_1 = require("node:url");
|
|
18
18
|
const url_1 = require("url");
|
|
19
19
|
const javascript_transformer_1 = require("../../../tools/esbuild/javascript-transformer");
|
|
20
|
-
const node_18_utils_1 = require("./node-18-utils");
|
|
21
20
|
/**
|
|
22
21
|
* Node.js ESM loader to redirect imports to in memory files.
|
|
23
22
|
* @see: https://nodejs.org/api/esm.html#loaders for more information about loaders.
|
|
@@ -30,7 +29,6 @@ const javascriptTransformer = new javascript_transformer_1.JavaScriptTransformer
|
|
|
30
29
|
// In a development environment the additional scope information does not
|
|
31
30
|
// have a negative effect unlike production where final output size is relevant.
|
|
32
31
|
{ sourcemap: true, jit: true }, 1);
|
|
33
|
-
(0, node_18_utils_1.callInitializeIfNeeded)(initialize);
|
|
34
32
|
function initialize(data) {
|
|
35
33
|
// This path does not actually exist but is used to overlay the in memory files with the
|
|
36
34
|
// actual filesystem for resolution purposes.
|
|
@@ -13,9 +13,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
13
13
|
exports.prerenderPages = void 0;
|
|
14
14
|
const promises_1 = require("node:fs/promises");
|
|
15
15
|
const node_path_1 = require("node:path");
|
|
16
|
+
const node_url_1 = require("node:url");
|
|
16
17
|
const piscina_1 = __importDefault(require("piscina"));
|
|
17
18
|
const bundler_context_1 = require("../../tools/esbuild/bundler-context");
|
|
18
|
-
const node_18_utils_1 = require("./esm-in-memory-loader/node-18-utils");
|
|
19
19
|
async function prerenderPages(workspaceRoot, appShellOptions = {}, prerenderOptions = {}, outputFiles, assets, document, sourcemap = false, inlineCriticalCss = false, maxThreads = 1, verbose = false) {
|
|
20
20
|
const outputFilesForWorker = {};
|
|
21
21
|
const serverBundlesSourceMaps = new Map();
|
|
@@ -82,7 +82,11 @@ async function renderPages(sourcemap, allRoutes, maxThreads, workspaceRoot, outp
|
|
|
82
82
|
const output = {};
|
|
83
83
|
const warnings = [];
|
|
84
84
|
const errors = [];
|
|
85
|
-
const workerExecArgv =
|
|
85
|
+
const workerExecArgv = [
|
|
86
|
+
'--import',
|
|
87
|
+
// Loader cannot be an absolute path on Windows.
|
|
88
|
+
(0, node_url_1.pathToFileURL)((0, node_path_1.join)(__dirname, 'esm-in-memory-loader/register-hooks.js')).href,
|
|
89
|
+
];
|
|
86
90
|
if (sourcemap) {
|
|
87
91
|
workerExecArgv.push('--enable-source-maps');
|
|
88
92
|
}
|
|
@@ -149,7 +153,11 @@ async function getAllRoutes(workspaceRoot, outputFilesForWorker, assetFilesForWo
|
|
|
149
153
|
if (!discoverRoutes) {
|
|
150
154
|
return { routes };
|
|
151
155
|
}
|
|
152
|
-
const workerExecArgv =
|
|
156
|
+
const workerExecArgv = [
|
|
157
|
+
'--import',
|
|
158
|
+
// Loader cannot be an absolute path on Windows.
|
|
159
|
+
(0, node_url_1.pathToFileURL)((0, node_path_1.join)(__dirname, 'esm-in-memory-loader/register-hooks.js')).href,
|
|
160
|
+
];
|
|
153
161
|
if (sourcemap) {
|
|
154
162
|
workerExecArgv.push('--enable-source-maps');
|
|
155
163
|
}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
|
-
/// <reference types="
|
|
9
|
-
/// <reference types="
|
|
8
|
+
/// <reference types="node" />
|
|
9
|
+
/// <reference types="node" />
|
|
10
10
|
import type { Config, Filesystem } from '@angular/service-worker/config';
|
|
11
11
|
import { promises as fsPromises } from 'node:fs';
|
|
12
12
|
import { BuildOutputFile } from '../tools/esbuild/bundler-context';
|
|
@@ -5,5 +5,6 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
export declare function getSupportedBrowsers(projectRoot: string, logger: {
|
|
9
|
+
warn(message: string): void;
|
|
10
|
+
}): string[];
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
8
|
import { BuilderContext } from '@angular-devkit/architect';
|
|
9
|
-
import { logging } from '@angular-devkit/core';
|
|
10
9
|
import { Configuration } from 'webpack';
|
|
11
10
|
import { Schema as BrowserBuilderSchema } from '../builders/browser/schema';
|
|
12
11
|
import { NormalizedBrowserBuilderSchema } from '../utils';
|
|
@@ -14,7 +13,7 @@ import { WebpackConfigOptions } from '../utils/build-options';
|
|
|
14
13
|
import { I18nOptions } from './i18n-options';
|
|
15
14
|
export type BrowserWebpackConfigOptions = WebpackConfigOptions<NormalizedBrowserBuilderSchema>;
|
|
16
15
|
export type WebpackPartialGenerator = (configurationOptions: BrowserWebpackConfigOptions) => (Promise<Configuration> | Configuration)[];
|
|
17
|
-
export declare function generateWebpackConfig(workspaceRoot: string, projectRoot: string, sourceRoot: string | undefined, projectName: string, options: NormalizedBrowserBuilderSchema, webpackPartialGenerator: WebpackPartialGenerator, logger:
|
|
16
|
+
export declare function generateWebpackConfig(workspaceRoot: string, projectRoot: string, sourceRoot: string | undefined, projectName: string, options: NormalizedBrowserBuilderSchema, webpackPartialGenerator: WebpackPartialGenerator, logger: BuilderContext['logger'], extraBuildOptions: Partial<NormalizedBrowserBuilderSchema>): Promise<Configuration>;
|
|
18
17
|
export declare function generateI18nBrowserWebpackConfigFromContext(options: BrowserBuilderSchema, context: BuilderContext, webpackPartialGenerator: WebpackPartialGenerator, extraBuildOptions?: Partial<NormalizedBrowserBuilderSchema>): Promise<{
|
|
19
18
|
config: Configuration;
|
|
20
19
|
projectRoot: string;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright Google LLC All Rights Reserved.
|
|
4
|
-
*
|
|
5
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
-
* found in the LICENSE file at https://angular.io/license
|
|
7
|
-
*/
|
|
8
|
-
import { LegacyResult as CompileResult, LegacyException as Exception, LegacyOptions as Options } from 'sass';
|
|
9
|
-
/**
|
|
10
|
-
* The callback type for the `dart-sass` asynchronous render function.
|
|
11
|
-
*/
|
|
12
|
-
type RenderCallback = (error?: Exception, result?: CompileResult) => void;
|
|
13
|
-
/**
|
|
14
|
-
* A Sass renderer implementation that provides an interface that can be used by Webpack's
|
|
15
|
-
* `sass-loader`. The implementation uses a Worker thread to perform the Sass rendering
|
|
16
|
-
* with the `dart-sass` package. The `dart-sass` synchronous render function is used within
|
|
17
|
-
* the worker which can be up to two times faster than the asynchronous variant.
|
|
18
|
-
*/
|
|
19
|
-
export declare class SassLegacyWorkerImplementation {
|
|
20
|
-
private readonly workers;
|
|
21
|
-
private readonly availableWorkers;
|
|
22
|
-
private readonly requests;
|
|
23
|
-
private readonly workerPath;
|
|
24
|
-
private idCounter;
|
|
25
|
-
private nextWorkerIndex;
|
|
26
|
-
/**
|
|
27
|
-
* Provides information about the Sass implementation.
|
|
28
|
-
* This mimics enough of the `dart-sass` value to be used with the `sass-loader`.
|
|
29
|
-
*/
|
|
30
|
-
get info(): string;
|
|
31
|
-
/**
|
|
32
|
-
* The synchronous render function is not used by the `sass-loader`.
|
|
33
|
-
*/
|
|
34
|
-
renderSync(): never;
|
|
35
|
-
/**
|
|
36
|
-
* Asynchronously request a Sass stylesheet to be renderered.
|
|
37
|
-
*
|
|
38
|
-
* @param options The `dart-sass` options to use when rendering the stylesheet.
|
|
39
|
-
* @param callback The function to execute when the rendering is complete.
|
|
40
|
-
*/
|
|
41
|
-
render(options: Options<'async'>, callback: RenderCallback): void;
|
|
42
|
-
/**
|
|
43
|
-
* Shutdown the Sass render worker.
|
|
44
|
-
* Executing this method will stop any pending render requests.
|
|
45
|
-
*/
|
|
46
|
-
close(): void;
|
|
47
|
-
private createWorker;
|
|
48
|
-
private processImporters;
|
|
49
|
-
private createRequest;
|
|
50
|
-
}
|
|
51
|
-
export {};
|
|
@@ -1,173 +0,0 @@
|
|
|
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
|
-
*/
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.SassLegacyWorkerImplementation = void 0;
|
|
11
|
-
const path_1 = require("path");
|
|
12
|
-
const worker_threads_1 = require("worker_threads");
|
|
13
|
-
const environment_options_1 = require("../../utils/environment-options");
|
|
14
|
-
/**
|
|
15
|
-
* The maximum number of Workers that will be created to execute render requests.
|
|
16
|
-
*/
|
|
17
|
-
const MAX_RENDER_WORKERS = environment_options_1.maxWorkers;
|
|
18
|
-
/**
|
|
19
|
-
* A Sass renderer implementation that provides an interface that can be used by Webpack's
|
|
20
|
-
* `sass-loader`. The implementation uses a Worker thread to perform the Sass rendering
|
|
21
|
-
* with the `dart-sass` package. The `dart-sass` synchronous render function is used within
|
|
22
|
-
* the worker which can be up to two times faster than the asynchronous variant.
|
|
23
|
-
*/
|
|
24
|
-
class SassLegacyWorkerImplementation {
|
|
25
|
-
workers = [];
|
|
26
|
-
availableWorkers = [];
|
|
27
|
-
requests = new Map();
|
|
28
|
-
workerPath = (0, path_1.join)(__dirname, './worker-legacy.js');
|
|
29
|
-
idCounter = 1;
|
|
30
|
-
nextWorkerIndex = 0;
|
|
31
|
-
/**
|
|
32
|
-
* Provides information about the Sass implementation.
|
|
33
|
-
* This mimics enough of the `dart-sass` value to be used with the `sass-loader`.
|
|
34
|
-
*/
|
|
35
|
-
get info() {
|
|
36
|
-
return 'dart-sass\tworker';
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* The synchronous render function is not used by the `sass-loader`.
|
|
40
|
-
*/
|
|
41
|
-
renderSync() {
|
|
42
|
-
throw new Error('Sass renderSync is not supported.');
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Asynchronously request a Sass stylesheet to be renderered.
|
|
46
|
-
*
|
|
47
|
-
* @param options The `dart-sass` options to use when rendering the stylesheet.
|
|
48
|
-
* @param callback The function to execute when the rendering is complete.
|
|
49
|
-
*/
|
|
50
|
-
render(options, callback) {
|
|
51
|
-
// The `functions`, `logger` and `importer` options are JavaScript functions that cannot be transferred.
|
|
52
|
-
// If any additional function options are added in the future, they must be excluded as well.
|
|
53
|
-
const { functions, importer, logger, ...serializableOptions } = options;
|
|
54
|
-
// The CLI's configuration does not use or expose the ability to defined custom Sass functions
|
|
55
|
-
if (functions && Object.keys(functions).length > 0) {
|
|
56
|
-
throw new Error('Sass custom functions are not supported.');
|
|
57
|
-
}
|
|
58
|
-
let workerIndex = this.availableWorkers.pop();
|
|
59
|
-
if (workerIndex === undefined) {
|
|
60
|
-
if (this.workers.length < MAX_RENDER_WORKERS) {
|
|
61
|
-
workerIndex = this.workers.length;
|
|
62
|
-
this.workers.push(this.createWorker());
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
workerIndex = this.nextWorkerIndex++;
|
|
66
|
-
if (this.nextWorkerIndex >= this.workers.length) {
|
|
67
|
-
this.nextWorkerIndex = 0;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
const request = this.createRequest(workerIndex, callback, importer);
|
|
72
|
-
this.requests.set(request.id, request);
|
|
73
|
-
this.workers[workerIndex].postMessage({
|
|
74
|
-
id: request.id,
|
|
75
|
-
hasImporter: !!importer,
|
|
76
|
-
options: serializableOptions,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Shutdown the Sass render worker.
|
|
81
|
-
* Executing this method will stop any pending render requests.
|
|
82
|
-
*/
|
|
83
|
-
close() {
|
|
84
|
-
for (const worker of this.workers) {
|
|
85
|
-
try {
|
|
86
|
-
void worker.terminate();
|
|
87
|
-
}
|
|
88
|
-
catch { }
|
|
89
|
-
}
|
|
90
|
-
this.requests.clear();
|
|
91
|
-
}
|
|
92
|
-
createWorker() {
|
|
93
|
-
const { port1: mainImporterPort, port2: workerImporterPort } = new worker_threads_1.MessageChannel();
|
|
94
|
-
const importerSignal = new Int32Array(new SharedArrayBuffer(4));
|
|
95
|
-
const worker = new worker_threads_1.Worker(this.workerPath, {
|
|
96
|
-
workerData: { workerImporterPort, importerSignal },
|
|
97
|
-
transferList: [workerImporterPort],
|
|
98
|
-
});
|
|
99
|
-
worker.on('message', (response) => {
|
|
100
|
-
const request = this.requests.get(response.id);
|
|
101
|
-
if (!request) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
this.requests.delete(response.id);
|
|
105
|
-
this.availableWorkers.push(request.workerIndex);
|
|
106
|
-
if (response.result) {
|
|
107
|
-
// The results are expected to be Node.js `Buffer` objects but will each be transferred as
|
|
108
|
-
// a Uint8Array that does not have the expected `toString` behavior of a `Buffer`.
|
|
109
|
-
const { css, map, stats } = response.result;
|
|
110
|
-
const result = {
|
|
111
|
-
// This `Buffer.from` override will use the memory directly and avoid making a copy
|
|
112
|
-
css: Buffer.from(css.buffer, css.byteOffset, css.byteLength),
|
|
113
|
-
stats,
|
|
114
|
-
};
|
|
115
|
-
if (map) {
|
|
116
|
-
// This `Buffer.from` override will use the memory directly and avoid making a copy
|
|
117
|
-
result.map = Buffer.from(map.buffer, map.byteOffset, map.byteLength);
|
|
118
|
-
}
|
|
119
|
-
request.callback(undefined, result);
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
request.callback(response.error);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
mainImporterPort.on('message', ({ id, url, prev, fromImport, }) => {
|
|
126
|
-
const request = this.requests.get(id);
|
|
127
|
-
if (!request?.importers) {
|
|
128
|
-
mainImporterPort.postMessage(null);
|
|
129
|
-
Atomics.store(importerSignal, 0, 1);
|
|
130
|
-
Atomics.notify(importerSignal, 0);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
this.processImporters(request.importers, url, prev, fromImport)
|
|
134
|
-
.then((result) => {
|
|
135
|
-
mainImporterPort.postMessage(result);
|
|
136
|
-
})
|
|
137
|
-
.catch((error) => {
|
|
138
|
-
mainImporterPort.postMessage(error);
|
|
139
|
-
})
|
|
140
|
-
.finally(() => {
|
|
141
|
-
Atomics.store(importerSignal, 0, 1);
|
|
142
|
-
Atomics.notify(importerSignal, 0);
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
mainImporterPort.unref();
|
|
146
|
-
return worker;
|
|
147
|
-
}
|
|
148
|
-
async processImporters(importers, url, prev, fromImport) {
|
|
149
|
-
let result = null;
|
|
150
|
-
for (const importer of importers) {
|
|
151
|
-
result = await new Promise((resolve) => {
|
|
152
|
-
// Importers can be both sync and async
|
|
153
|
-
const innerResult = importer.call({ fromImport }, url, prev, resolve);
|
|
154
|
-
if (innerResult !== undefined) {
|
|
155
|
-
resolve(innerResult);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
if (result) {
|
|
159
|
-
break;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return result;
|
|
163
|
-
}
|
|
164
|
-
createRequest(workerIndex, callback, importer) {
|
|
165
|
-
return {
|
|
166
|
-
id: this.idCounter++,
|
|
167
|
-
workerIndex,
|
|
168
|
-
callback,
|
|
169
|
-
importers: !importer || Array.isArray(importer) ? importer : [importer],
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
exports.SassLegacyWorkerImplementation = SassLegacyWorkerImplementation;
|
|
@@ -1,43 +0,0 @@
|
|
|
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
|
-
*/
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
const sass_1 = require("sass");
|
|
11
|
-
const worker_threads_1 = require("worker_threads");
|
|
12
|
-
if (!worker_threads_1.parentPort || !worker_threads_1.workerData) {
|
|
13
|
-
throw new Error('Sass worker must be executed as a Worker.');
|
|
14
|
-
}
|
|
15
|
-
// The importer variables are used to proxy import requests to the main thread
|
|
16
|
-
const { workerImporterPort, importerSignal } = worker_threads_1.workerData;
|
|
17
|
-
worker_threads_1.parentPort.on('message', ({ id, hasImporter, options }) => {
|
|
18
|
-
try {
|
|
19
|
-
if (hasImporter) {
|
|
20
|
-
// When a custom importer function is present, the importer request must be proxied
|
|
21
|
-
// back to the main thread where it can be executed.
|
|
22
|
-
// This process must be synchronous from the perspective of dart-sass. The `Atomics`
|
|
23
|
-
// functions combined with the shared memory `importSignal` and the Node.js
|
|
24
|
-
// `receiveMessageOnPort` function are used to ensure synchronous behavior.
|
|
25
|
-
options.importer = function (url, prev) {
|
|
26
|
-
Atomics.store(importerSignal, 0, 0);
|
|
27
|
-
const { fromImport } = this;
|
|
28
|
-
workerImporterPort.postMessage({ id, url, prev, fromImport });
|
|
29
|
-
Atomics.wait(importerSignal, 0, 0);
|
|
30
|
-
return (0, worker_threads_1.receiveMessageOnPort)(workerImporterPort)?.message;
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
// The synchronous Sass render function can be up to two times faster than the async variant
|
|
34
|
-
const result = (0, sass_1.renderSync)(options);
|
|
35
|
-
worker_threads_1.parentPort?.postMessage({ id, result });
|
|
36
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
// Needed because V8 will only serialize the message and stack properties of an Error instance.
|
|
40
|
-
const { formatted, file, line, column, message, stack } = error;
|
|
41
|
-
worker_threads_1.parentPort?.postMessage({ id, error: { formatted, file, line, column, message, stack } });
|
|
42
|
-
}
|
|
43
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright Google LLC All Rights Reserved.
|
|
4
|
-
*
|
|
5
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
-
* found in the LICENSE file at https://angular.io/license
|
|
7
|
-
*/
|
|
8
|
-
/** Call the initialize hook when running on Node.js 18 */
|
|
9
|
-
export declare function callInitializeIfNeeded(initialize: (typeof import('./loader-hooks'))['initialize']): void;
|
|
10
|
-
export declare function getESMLoaderArgs(): string[];
|