@angular-devkit/build-angular 15.0.0-rc.1 → 15.0.0-rc.3
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 +18 -18
- package/src/builders/browser-esbuild/compiler-plugin.js +2 -2
- package/src/builders/browser-esbuild/css-resource-plugin.js +8 -0
- package/src/builders/browser-esbuild/index.js +8 -0
- package/src/builders/browser-esbuild/sass-plugin.d.ts +1 -0
- package/src/builders/browser-esbuild/sass-plugin.js +72 -33
- package/src/builders/browser-esbuild/stylesheets.js +4 -7
- package/src/builders/browser-esbuild/watcher.js +16 -5
- package/src/builders/server/index.js +16 -19
- package/src/sass/rebasing-importer.d.ts +98 -0
- package/src/sass/rebasing-importer.js +281 -0
- package/src/sass/sass-service.d.ts +2 -0
- package/src/sass/sass-service.js +21 -4
- package/src/sass/worker.js +102 -37
- package/src/webpack/configs/common.js +1 -1
- package/src/webpack/configs/styles.js +17 -10
- package/src/webpack/utils/helpers.d.ts +5 -0
- package/src/webpack/utils/helpers.js +15 -1
package/package.json
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-devkit/build-angular",
|
|
3
|
-
"version": "15.0.0-rc.
|
|
3
|
+
"version": "15.0.0-rc.3",
|
|
4
4
|
"description": "Angular Webpack Build Facade",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"typings": "src/index.d.ts",
|
|
7
7
|
"builders": "builders.json",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@ampproject/remapping": "2.2.0",
|
|
10
|
-
"@angular-devkit/architect": "0.1500.0-rc.
|
|
11
|
-
"@angular-devkit/build-webpack": "0.1500.0-rc.
|
|
12
|
-
"@angular-devkit/core": "15.0.0-rc.
|
|
13
|
-
"@babel/core": "7.
|
|
14
|
-
"@babel/generator": "7.
|
|
10
|
+
"@angular-devkit/architect": "0.1500.0-rc.3",
|
|
11
|
+
"@angular-devkit/build-webpack": "0.1500.0-rc.3",
|
|
12
|
+
"@angular-devkit/core": "15.0.0-rc.3",
|
|
13
|
+
"@babel/core": "7.20.2",
|
|
14
|
+
"@babel/generator": "7.20.3",
|
|
15
15
|
"@babel/helper-annotate-as-pure": "7.18.6",
|
|
16
|
-
"@babel/plugin-proposal-async-generator-functions": "7.
|
|
16
|
+
"@babel/plugin-proposal-async-generator-functions": "7.20.1",
|
|
17
17
|
"@babel/plugin-transform-async-to-generator": "7.18.6",
|
|
18
18
|
"@babel/plugin-transform-runtime": "7.19.6",
|
|
19
|
-
"@babel/preset-env": "7.
|
|
20
|
-
"@babel/runtime": "7.
|
|
19
|
+
"@babel/preset-env": "7.20.2",
|
|
20
|
+
"@babel/runtime": "7.20.1",
|
|
21
21
|
"@babel/template": "7.18.10",
|
|
22
22
|
"@discoveryjs/json-ext": "0.5.7",
|
|
23
|
-
"@ngtools/webpack": "15.0.0-rc.
|
|
23
|
+
"@ngtools/webpack": "15.0.0-rc.3",
|
|
24
24
|
"ansi-colors": "4.1.3",
|
|
25
|
-
"autoprefixer": "10.4.
|
|
26
|
-
"babel-loader": "
|
|
25
|
+
"autoprefixer": "10.4.13",
|
|
26
|
+
"babel-loader": "9.1.0",
|
|
27
27
|
"babel-plugin-istanbul": "6.1.1",
|
|
28
28
|
"browserslist": "^4.9.1",
|
|
29
|
-
"cacache": "17.0.
|
|
29
|
+
"cacache": "17.0.2",
|
|
30
30
|
"chokidar": "3.5.3",
|
|
31
31
|
"copy-webpack-plugin": "11.0.0",
|
|
32
32
|
"critters": "0.0.16",
|
|
33
33
|
"css-loader": "6.7.1",
|
|
34
|
-
"esbuild-wasm": "0.15.
|
|
34
|
+
"esbuild-wasm": "0.15.13",
|
|
35
35
|
"glob": "8.0.3",
|
|
36
36
|
"https-proxy-agent": "5.0.1",
|
|
37
37
|
"inquirer": "8.2.4",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"less-loader": "11.1.0",
|
|
42
42
|
"license-webpack-plugin": "4.0.2",
|
|
43
43
|
"loader-utils": "3.2.0",
|
|
44
|
+
"magic-string": "0.26.7",
|
|
44
45
|
"mini-css-extract-plugin": "2.6.1",
|
|
45
|
-
"minimatch": "5.1.0",
|
|
46
46
|
"open": "8.4.0",
|
|
47
47
|
"ora": "5.4.1",
|
|
48
48
|
"parse5-html-rewriting-stream": "6.0.1",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"regenerator-runtime": "0.13.10",
|
|
53
53
|
"resolve-url-loader": "5.0.0",
|
|
54
54
|
"rxjs": "6.6.7",
|
|
55
|
-
"sass": "1.
|
|
55
|
+
"sass": "1.56.0",
|
|
56
56
|
"sass-loader": "13.1.0",
|
|
57
57
|
"semver": "7.3.8",
|
|
58
58
|
"source-map-loader": "4.0.1",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"terser": "5.15.1",
|
|
61
61
|
"text-table": "0.2.0",
|
|
62
62
|
"tree-kill": "1.2.2",
|
|
63
|
-
"tslib": "2.4.
|
|
63
|
+
"tslib": "2.4.1",
|
|
64
64
|
"webpack": "5.74.0",
|
|
65
65
|
"webpack-dev-middleware": "5.3.3",
|
|
66
66
|
"webpack-dev-server": "4.11.1",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"webpack-subresource-integrity": "5.1.0"
|
|
69
69
|
},
|
|
70
70
|
"optionalDependencies": {
|
|
71
|
-
"esbuild": "0.15.
|
|
71
|
+
"esbuild": "0.15.13"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"@angular/compiler-cli": "^15.0.0-next",
|
|
@@ -188,8 +188,8 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
|
|
|
188
188
|
location: { file: pluginOptions.tsconfig },
|
|
189
189
|
notes: [
|
|
190
190
|
{
|
|
191
|
-
text:
|
|
192
|
-
|
|
191
|
+
text: 'To control ECMA version and features use the Browerslist configuration. ' +
|
|
192
|
+
'For more information, see https://angular.io/guide/build#configuring-browser-compatibility',
|
|
193
193
|
},
|
|
194
194
|
],
|
|
195
195
|
});
|
|
@@ -33,6 +33,14 @@ function createCssResourcePlugin() {
|
|
|
33
33
|
if (args.kind !== 'url-token' || ((_a = args.pluginData) === null || _a === void 0 ? void 0 : _a[CSS_RESOURCE_RESOLUTION])) {
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
|
+
// If root-relative, absolute or protocol relative url, mark as external to leave the
|
|
37
|
+
// path/URL in place.
|
|
38
|
+
if (/^((?:\w+:)?\/\/|data:|chrome:|#|\/)/.test(args.path)) {
|
|
39
|
+
return {
|
|
40
|
+
path: args.path,
|
|
41
|
+
external: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
36
44
|
const { importer, kind, resolveDir, namespace, pluginData = {} } = args;
|
|
37
45
|
pluginData[CSS_RESOURCE_RESOLUTION] = true;
|
|
38
46
|
const result = await build.resolve(args.path, {
|
|
@@ -46,6 +46,7 @@ const compiler_plugin_1 = require("./compiler-plugin");
|
|
|
46
46
|
const esbuild_1 = require("./esbuild");
|
|
47
47
|
const experimental_warnings_1 = require("./experimental-warnings");
|
|
48
48
|
const options_1 = require("./options");
|
|
49
|
+
const sass_plugin_1 = require("./sass-plugin");
|
|
49
50
|
const stylesheets_1 = require("./stylesheets");
|
|
50
51
|
const watcher_1 = require("./watcher");
|
|
51
52
|
/**
|
|
@@ -208,6 +209,11 @@ function createCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
208
209
|
// loader to perform the downlevel transformation.
|
|
209
210
|
// NOTE: If esbuild adds support in the future, the babel support for async generators can be disabled.
|
|
210
211
|
'async-await': false,
|
|
212
|
+
// V8 currently has a performance defect involving object spread operations that can cause signficant
|
|
213
|
+
// degradation in runtime performance. By not supporting the language feature here, a downlevel form
|
|
214
|
+
// will be used instead which provides a workaround for the performance issue.
|
|
215
|
+
// For more details: https://bugs.chromium.org/p/v8/issues/detail?id=11536
|
|
216
|
+
'object-rest-spread': false,
|
|
211
217
|
},
|
|
212
218
|
mainFields: ['es2020', 'browser', 'module', 'main'],
|
|
213
219
|
conditions: ['es2020', 'es2015', 'module'],
|
|
@@ -345,6 +351,7 @@ async function* buildEsbuildBrowser(initialOptions, context) {
|
|
|
345
351
|
yield result.output;
|
|
346
352
|
// Finish if watch mode is not enabled
|
|
347
353
|
if (!initialOptions.watch) {
|
|
354
|
+
(0, sass_plugin_1.shutdownSassWorkerPool)();
|
|
348
355
|
return;
|
|
349
356
|
}
|
|
350
357
|
context.logger.info('Watch mode enabled. Watching for file changes...');
|
|
@@ -378,6 +385,7 @@ async function* buildEsbuildBrowser(initialOptions, context) {
|
|
|
378
385
|
await watcher.close();
|
|
379
386
|
// Cleanup incremental rebuild state
|
|
380
387
|
result.dispose();
|
|
388
|
+
(0, sass_plugin_1.shutdownSassWorkerPool)();
|
|
381
389
|
}
|
|
382
390
|
}
|
|
383
391
|
exports.buildEsbuildBrowser = buildEsbuildBrowser;
|
|
@@ -6,54 +6,92 @@
|
|
|
6
6
|
* Use of this source code is governed by an MIT-style license that can be
|
|
7
7
|
* found in the LICENSE file at https://angular.io/license
|
|
8
8
|
*/
|
|
9
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
-
}
|
|
15
|
-
Object.defineProperty(o, k2, desc);
|
|
16
|
-
}) : (function(o, m, k, k2) {
|
|
17
|
-
if (k2 === undefined) k2 = k;
|
|
18
|
-
o[k2] = m[k];
|
|
19
|
-
}));
|
|
20
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
-
}) : function(o, v) {
|
|
23
|
-
o["default"] = v;
|
|
24
|
-
});
|
|
25
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
26
|
-
if (mod && mod.__esModule) return mod;
|
|
27
|
-
var result = {};
|
|
28
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
29
|
-
__setModuleDefault(result, mod);
|
|
30
|
-
return result;
|
|
31
|
-
};
|
|
32
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
-
exports.createSassPlugin = void 0;
|
|
10
|
+
exports.createSassPlugin = exports.shutdownSassWorkerPool = void 0;
|
|
11
|
+
const promises_1 = require("node:fs/promises");
|
|
34
12
|
const node_path_1 = require("node:path");
|
|
35
13
|
const node_url_1 = require("node:url");
|
|
14
|
+
const sass_service_1 = require("../../sass/sass-service");
|
|
15
|
+
let sassWorkerPool;
|
|
16
|
+
function isSassException(error) {
|
|
17
|
+
return !!error && typeof error === 'object' && 'sassMessage' in error;
|
|
18
|
+
}
|
|
19
|
+
function shutdownSassWorkerPool() {
|
|
20
|
+
sassWorkerPool === null || sassWorkerPool === void 0 ? void 0 : sassWorkerPool.close();
|
|
21
|
+
sassWorkerPool = undefined;
|
|
22
|
+
}
|
|
23
|
+
exports.shutdownSassWorkerPool = shutdownSassWorkerPool;
|
|
36
24
|
function createSassPlugin(options) {
|
|
37
25
|
return {
|
|
38
26
|
name: 'angular-sass',
|
|
39
27
|
setup(build) {
|
|
40
|
-
let sass;
|
|
41
28
|
build.onLoad({ filter: /\.s[ac]ss$/ }, async (args) => {
|
|
42
29
|
// Lazily load Sass when a Sass file is found
|
|
43
|
-
|
|
30
|
+
sassWorkerPool !== null && sassWorkerPool !== void 0 ? sassWorkerPool : (sassWorkerPool = new sass_service_1.SassWorkerImplementation(true));
|
|
31
|
+
const warnings = [];
|
|
44
32
|
try {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
const data = await (0, promises_1.readFile)(args.path, 'utf-8');
|
|
34
|
+
const { css, sourceMap, loadedUrls } = await sassWorkerPool.compileStringAsync(data, {
|
|
35
|
+
url: (0, node_url_1.pathToFileURL)(args.path),
|
|
48
36
|
style: 'expanded',
|
|
49
37
|
loadPaths: options.loadPaths,
|
|
50
38
|
sourceMap: options.sourcemap,
|
|
51
39
|
sourceMapIncludeSources: options.sourcemap,
|
|
52
40
|
quietDeps: true,
|
|
41
|
+
importers: [
|
|
42
|
+
{
|
|
43
|
+
findFileUrl: async (url, { previousResolvedModules }) => {
|
|
44
|
+
let result = await build.resolve(url, {
|
|
45
|
+
kind: 'import-rule',
|
|
46
|
+
// This should ideally be the directory of the importer file from Sass
|
|
47
|
+
// but that is not currently available from the Sass importer API.
|
|
48
|
+
resolveDir: build.initialOptions.absWorkingDir,
|
|
49
|
+
});
|
|
50
|
+
// Workaround to support Yarn PnP without access to the importer file from Sass
|
|
51
|
+
if (!result.path && (previousResolvedModules === null || previousResolvedModules === void 0 ? void 0 : previousResolvedModules.size)) {
|
|
52
|
+
for (const previous of previousResolvedModules) {
|
|
53
|
+
result = await build.resolve(url, {
|
|
54
|
+
kind: 'import-rule',
|
|
55
|
+
resolveDir: previous,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Check for package deep imports
|
|
60
|
+
if (!result.path) {
|
|
61
|
+
const parts = url.split('/');
|
|
62
|
+
const hasScope = parts.length > 2 && parts[0].startsWith('@');
|
|
63
|
+
if (hasScope || parts.length > 1) {
|
|
64
|
+
const [nameOrScope, nameOrFirstPath, ...pathPart] = parts;
|
|
65
|
+
const packageName = hasScope
|
|
66
|
+
? `${nameOrScope}/${nameOrFirstPath}`
|
|
67
|
+
: nameOrScope;
|
|
68
|
+
const packageResult = await build.resolve(packageName + '/package.json', {
|
|
69
|
+
kind: 'import-rule',
|
|
70
|
+
// This should ideally be the directory of the importer file from Sass
|
|
71
|
+
// but that is not currently available from the Sass importer API.
|
|
72
|
+
resolveDir: build.initialOptions.absWorkingDir,
|
|
73
|
+
});
|
|
74
|
+
if (packageResult.path) {
|
|
75
|
+
return (0, node_url_1.pathToFileURL)((0, node_path_1.join)((0, node_path_1.dirname)(packageResult.path), !hasScope ? nameOrFirstPath : '', ...pathPart));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result.path ? (0, node_url_1.pathToFileURL)(result.path) : null;
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
],
|
|
53
83
|
logger: {
|
|
54
|
-
warn: (text,
|
|
84
|
+
warn: (text, { deprecation, span }) => {
|
|
55
85
|
warnings.push({
|
|
56
|
-
text,
|
|
86
|
+
text: deprecation ? 'Deprecation' : text,
|
|
87
|
+
location: span && {
|
|
88
|
+
file: span.url && (0, node_url_1.fileURLToPath)(span.url),
|
|
89
|
+
lineText: span.context,
|
|
90
|
+
// Sass line numbers are 0-based while esbuild's are 1-based
|
|
91
|
+
line: span.start.line + 1,
|
|
92
|
+
column: span.start.column,
|
|
93
|
+
},
|
|
94
|
+
notes: deprecation ? [{ text }] : undefined,
|
|
57
95
|
});
|
|
58
96
|
},
|
|
59
97
|
},
|
|
@@ -68,15 +106,16 @@ function createSassPlugin(options) {
|
|
|
68
106
|
};
|
|
69
107
|
}
|
|
70
108
|
catch (error) {
|
|
71
|
-
if (error
|
|
109
|
+
if (isSassException(error)) {
|
|
72
110
|
const file = error.span.url ? (0, node_url_1.fileURLToPath)(error.span.url) : undefined;
|
|
73
111
|
return {
|
|
74
112
|
loader: 'css',
|
|
75
113
|
errors: [
|
|
76
114
|
{
|
|
77
|
-
text: error.
|
|
115
|
+
text: error.message,
|
|
78
116
|
},
|
|
79
117
|
],
|
|
118
|
+
warnings,
|
|
80
119
|
watchFiles: file ? [file] : undefined,
|
|
81
120
|
};
|
|
82
121
|
}
|
|
@@ -36,17 +36,14 @@ const css_resource_plugin_1 = require("./css-resource-plugin");
|
|
|
36
36
|
const esbuild_1 = require("./esbuild");
|
|
37
37
|
const sass_plugin_1 = require("./sass-plugin");
|
|
38
38
|
async function bundleStylesheet(entry, options) {
|
|
39
|
-
var _a, _b
|
|
40
|
-
const loadPaths = (_a = options.includePaths) !== null && _a !== void 0 ? _a : [];
|
|
41
|
-
// Needed to resolve node packages.
|
|
42
|
-
loadPaths.push(path.join(options.workspaceRoot, 'node_modules'));
|
|
39
|
+
var _a, _b;
|
|
43
40
|
// Execute esbuild
|
|
44
41
|
const result = await (0, esbuild_1.bundle)({
|
|
45
42
|
...entry,
|
|
46
43
|
absWorkingDir: options.workspaceRoot,
|
|
47
44
|
bundle: true,
|
|
48
|
-
entryNames: (
|
|
49
|
-
assetNames: (
|
|
45
|
+
entryNames: (_a = options.outputNames) === null || _a === void 0 ? void 0 : _a.bundles,
|
|
46
|
+
assetNames: (_b = options.outputNames) === null || _b === void 0 ? void 0 : _b.media,
|
|
50
47
|
logLevel: 'silent',
|
|
51
48
|
minify: options.optimization,
|
|
52
49
|
sourcemap: options.sourcemap,
|
|
@@ -59,7 +56,7 @@ async function bundleStylesheet(entry, options) {
|
|
|
59
56
|
conditions: ['style', 'sass'],
|
|
60
57
|
mainFields: ['style', 'sass'],
|
|
61
58
|
plugins: [
|
|
62
|
-
(0, sass_plugin_1.createSassPlugin)({ sourcemap: !!options.sourcemap, loadPaths }),
|
|
59
|
+
(0, sass_plugin_1.createSassPlugin)({ sourcemap: !!options.sourcemap, loadPaths: options.includePaths }),
|
|
63
60
|
(0, css_resource_plugin_1.createCssResourcePlugin)(),
|
|
64
61
|
],
|
|
65
62
|
});
|
|
@@ -33,6 +33,7 @@ function createWatcher(options) {
|
|
|
33
33
|
});
|
|
34
34
|
const nextQueue = [];
|
|
35
35
|
let currentChanges;
|
|
36
|
+
let nextWaitTimeout;
|
|
36
37
|
watcher.on('all', (event, path) => {
|
|
37
38
|
switch (event) {
|
|
38
39
|
case 'add':
|
|
@@ -50,11 +51,18 @@ function createWatcher(options) {
|
|
|
50
51
|
default:
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
// Wait 250ms from next change to better capture groups of file save operations.
|
|
55
|
+
if (!nextWaitTimeout) {
|
|
56
|
+
nextWaitTimeout = setTimeout(() => {
|
|
57
|
+
nextWaitTimeout = undefined;
|
|
58
|
+
const next = nextQueue.shift();
|
|
59
|
+
if (next) {
|
|
60
|
+
const value = currentChanges;
|
|
61
|
+
currentChanges = undefined;
|
|
62
|
+
next(value);
|
|
63
|
+
}
|
|
64
|
+
}, 250);
|
|
65
|
+
nextWaitTimeout === null || nextWaitTimeout === void 0 ? void 0 : nextWaitTimeout.unref();
|
|
58
66
|
}
|
|
59
67
|
});
|
|
60
68
|
return {
|
|
@@ -80,6 +88,9 @@ function createWatcher(options) {
|
|
|
80
88
|
async close() {
|
|
81
89
|
try {
|
|
82
90
|
await watcher.close();
|
|
91
|
+
if (nextWaitTimeout) {
|
|
92
|
+
clearTimeout(nextWaitTimeout);
|
|
93
|
+
}
|
|
83
94
|
}
|
|
84
95
|
finally {
|
|
85
96
|
let next;
|
|
@@ -43,6 +43,7 @@ const purge_cache_1 = require("../../utils/purge-cache");
|
|
|
43
43
|
const version_1 = require("../../utils/version");
|
|
44
44
|
const webpack_browser_config_1 = require("../../utils/webpack-browser-config");
|
|
45
45
|
const configs_1 = require("../../webpack/configs");
|
|
46
|
+
const helpers_1 = require("../../webpack/utils/helpers");
|
|
46
47
|
const stats_1 = require("../../webpack/utils/stats");
|
|
47
48
|
/**
|
|
48
49
|
* @experimental Direct usage of this function is considered experimental.
|
|
@@ -127,23 +128,19 @@ async function initialize(options, context, webpackConfigurationTransform) {
|
|
|
127
128
|
function getPlatformServerExportsConfig(wco) {
|
|
128
129
|
// Add `@angular/platform-server` exports.
|
|
129
130
|
// This is needed so that DI tokens can be referenced and set at runtime outside of the bundle.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
},
|
|
146
|
-
],
|
|
147
|
-
},
|
|
148
|
-
};
|
|
131
|
+
// Only add `@angular/platform-server` exports when it is installed.
|
|
132
|
+
// In some cases this builder is used when `@angular/platform-server` is not installed.
|
|
133
|
+
// Example: when using `@nguniversal/common/clover` which does not need `@angular/platform-server`.
|
|
134
|
+
return (0, helpers_1.isPlatformServerInstalled)(wco.root)
|
|
135
|
+
? {
|
|
136
|
+
module: {
|
|
137
|
+
rules: [
|
|
138
|
+
{
|
|
139
|
+
loader: require.resolve('./platform-server-exports-loader'),
|
|
140
|
+
include: [path.resolve(wco.root, wco.buildOptions.main)],
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
: {};
|
|
149
146
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
/// <reference types="node" />
|
|
9
|
+
/// <reference types="node" />
|
|
10
|
+
import { RawSourceMap } from '@ampproject/remapping';
|
|
11
|
+
import { Dirent } from 'node:fs';
|
|
12
|
+
import type { FileImporter, Importer, ImporterResult } from 'sass';
|
|
13
|
+
/**
|
|
14
|
+
* A Sass Importer base class that provides the load logic to rebase all `url()` functions
|
|
15
|
+
* within a stylesheet. The rebasing will ensure that the URLs in the output of the Sass compiler
|
|
16
|
+
* reflect the final filesystem location of the output CSS file.
|
|
17
|
+
*
|
|
18
|
+
* This class provides the core of the rebasing functionality. To ensure that each file is processed
|
|
19
|
+
* by this importer's load implementation, the Sass compiler requires the importer's canonicalize
|
|
20
|
+
* function to return a non-null value with the resolved location of the requested stylesheet.
|
|
21
|
+
* Concrete implementations of this class must provide this canonicalize functionality for rebasing
|
|
22
|
+
* to be effective.
|
|
23
|
+
*/
|
|
24
|
+
declare abstract class UrlRebasingImporter implements Importer<'sync'> {
|
|
25
|
+
private entryDirectory;
|
|
26
|
+
private rebaseSourceMaps?;
|
|
27
|
+
/**
|
|
28
|
+
* @param entryDirectory The directory of the entry stylesheet that was passed to the Sass compiler.
|
|
29
|
+
* @param rebaseSourceMaps When provided, rebased files will have an intermediate sourcemap added to the Map
|
|
30
|
+
* which can be used to generate a final sourcemap that contains original sources.
|
|
31
|
+
*/
|
|
32
|
+
constructor(entryDirectory: string, rebaseSourceMaps?: Map<string, RawSourceMap> | undefined);
|
|
33
|
+
abstract canonicalize(url: string, options: {
|
|
34
|
+
fromImport: boolean;
|
|
35
|
+
}): URL | null;
|
|
36
|
+
load(canonicalUrl: URL): ImporterResult | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Provides the Sass importer logic to resolve relative stylesheet imports via both import and use rules
|
|
40
|
+
* and also rebase any `url()` function usage within those stylesheets. The rebasing will ensure that
|
|
41
|
+
* the URLs in the output of the Sass compiler reflect the final filesystem location of the output CSS file.
|
|
42
|
+
*/
|
|
43
|
+
export declare class RelativeUrlRebasingImporter extends UrlRebasingImporter {
|
|
44
|
+
private directoryCache;
|
|
45
|
+
constructor(entryDirectory: string, directoryCache?: Map<string, Dirent[]>, rebaseSourceMaps?: Map<string, RawSourceMap>);
|
|
46
|
+
canonicalize(url: string, options: {
|
|
47
|
+
fromImport: boolean;
|
|
48
|
+
}): URL | null;
|
|
49
|
+
/**
|
|
50
|
+
* Attempts to resolve a provided URL to a stylesheet file using the Sass compiler's resolution algorithm.
|
|
51
|
+
* Based on https://github.com/sass/dart-sass/blob/44d6bb6ac72fe6b93f5bfec371a1fffb18e6b76d/lib/src/importer/utils.dart
|
|
52
|
+
* @param url The file protocol URL to resolve.
|
|
53
|
+
* @param fromImport If true, URL was from an import rule; otherwise from a use rule.
|
|
54
|
+
* @param checkDirectory If true, try checking for a directory with the base name containing an index file.
|
|
55
|
+
* @returns A full resolved URL of the stylesheet file or `null` if not found.
|
|
56
|
+
*/
|
|
57
|
+
private resolveImport;
|
|
58
|
+
/**
|
|
59
|
+
* Checks an array of potential stylesheet files to determine if there is a valid
|
|
60
|
+
* stylesheet file. More than one discovered file may indicate an error.
|
|
61
|
+
* @param found An array of discovered stylesheet files.
|
|
62
|
+
* @returns A fully resolved URL for a stylesheet file or `null` if not found.
|
|
63
|
+
* @throws If there are ambiguous files discovered.
|
|
64
|
+
*/
|
|
65
|
+
private checkFound;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Provides the Sass importer logic to resolve module (npm package) stylesheet imports via both import and
|
|
69
|
+
* use rules and also rebase any `url()` function usage within those stylesheets. The rebasing will ensure that
|
|
70
|
+
* the URLs in the output of the Sass compiler reflect the final filesystem location of the output CSS file.
|
|
71
|
+
*/
|
|
72
|
+
export declare class ModuleUrlRebasingImporter extends RelativeUrlRebasingImporter {
|
|
73
|
+
private finder;
|
|
74
|
+
constructor(entryDirectory: string, directoryCache: Map<string, Dirent[]>, rebaseSourceMaps: Map<string, RawSourceMap> | undefined, finder: FileImporter<'sync'>['findFileUrl']);
|
|
75
|
+
canonicalize(url: string, options: {
|
|
76
|
+
fromImport: boolean;
|
|
77
|
+
}): URL | null;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Provides the Sass importer logic to resolve load paths located stylesheet imports via both import and
|
|
81
|
+
* use rules and also rebase any `url()` function usage within those stylesheets. The rebasing will ensure that
|
|
82
|
+
* the URLs in the output of the Sass compiler reflect the final filesystem location of the output CSS file.
|
|
83
|
+
*/
|
|
84
|
+
export declare class LoadPathsUrlRebasingImporter extends RelativeUrlRebasingImporter {
|
|
85
|
+
private loadPaths;
|
|
86
|
+
constructor(entryDirectory: string, directoryCache: Map<string, Dirent[]>, rebaseSourceMaps: Map<string, RawSourceMap> | undefined, loadPaths: Iterable<string>);
|
|
87
|
+
canonicalize(url: string, options: {
|
|
88
|
+
fromImport: boolean;
|
|
89
|
+
}): URL | null;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Workaround for Sass not calling instance methods with `this`.
|
|
93
|
+
* The `canonicalize` and `load` methods will be bound to the class instance.
|
|
94
|
+
* @param importer A Sass importer to bind.
|
|
95
|
+
* @returns The bound Sass importer.
|
|
96
|
+
*/
|
|
97
|
+
export declare function sassBindWorkaround<T extends Importer>(importer: T): T;
|
|
98
|
+
export {};
|
|
@@ -0,0 +1,281 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.sassBindWorkaround = exports.LoadPathsUrlRebasingImporter = exports.ModuleUrlRebasingImporter = exports.RelativeUrlRebasingImporter = void 0;
|
|
14
|
+
const magic_string_1 = __importDefault(require("magic-string"));
|
|
15
|
+
const node_fs_1 = require("node:fs");
|
|
16
|
+
const node_path_1 = require("node:path");
|
|
17
|
+
const node_url_1 = require("node:url");
|
|
18
|
+
/**
|
|
19
|
+
* A Regular expression used to find all `url()` functions within a stylesheet.
|
|
20
|
+
* From packages/angular_devkit/build_angular/src/webpack/plugins/postcss-cli-resources.ts
|
|
21
|
+
*/
|
|
22
|
+
const URL_REGEXP = /url(?:\(\s*(['"]?))(.*?)(?:\1\s*\))/g;
|
|
23
|
+
/**
|
|
24
|
+
* A Sass Importer base class that provides the load logic to rebase all `url()` functions
|
|
25
|
+
* within a stylesheet. The rebasing will ensure that the URLs in the output of the Sass compiler
|
|
26
|
+
* reflect the final filesystem location of the output CSS file.
|
|
27
|
+
*
|
|
28
|
+
* This class provides the core of the rebasing functionality. To ensure that each file is processed
|
|
29
|
+
* by this importer's load implementation, the Sass compiler requires the importer's canonicalize
|
|
30
|
+
* function to return a non-null value with the resolved location of the requested stylesheet.
|
|
31
|
+
* Concrete implementations of this class must provide this canonicalize functionality for rebasing
|
|
32
|
+
* to be effective.
|
|
33
|
+
*/
|
|
34
|
+
class UrlRebasingImporter {
|
|
35
|
+
/**
|
|
36
|
+
* @param entryDirectory The directory of the entry stylesheet that was passed to the Sass compiler.
|
|
37
|
+
* @param rebaseSourceMaps When provided, rebased files will have an intermediate sourcemap added to the Map
|
|
38
|
+
* which can be used to generate a final sourcemap that contains original sources.
|
|
39
|
+
*/
|
|
40
|
+
constructor(entryDirectory, rebaseSourceMaps) {
|
|
41
|
+
this.entryDirectory = entryDirectory;
|
|
42
|
+
this.rebaseSourceMaps = rebaseSourceMaps;
|
|
43
|
+
}
|
|
44
|
+
load(canonicalUrl) {
|
|
45
|
+
const stylesheetPath = (0, node_url_1.fileURLToPath)(canonicalUrl);
|
|
46
|
+
let contents = (0, node_fs_1.readFileSync)(stylesheetPath, 'utf-8');
|
|
47
|
+
// Rebase any URLs that are found
|
|
48
|
+
if (contents.includes('url(')) {
|
|
49
|
+
const stylesheetDirectory = (0, node_path_1.dirname)(stylesheetPath);
|
|
50
|
+
let match;
|
|
51
|
+
URL_REGEXP.lastIndex = 0;
|
|
52
|
+
let updatedContents;
|
|
53
|
+
while ((match = URL_REGEXP.exec(contents))) {
|
|
54
|
+
const originalUrl = match[2];
|
|
55
|
+
// If root-relative, absolute or protocol relative url, leave as-is
|
|
56
|
+
if (/^((?:\w+:)?\/\/|data:|chrome:|#|\/)/.test(originalUrl)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const rebasedPath = (0, node_path_1.relative)(this.entryDirectory, (0, node_path_1.join)(stylesheetDirectory, originalUrl));
|
|
60
|
+
// Normalize path separators and escape characters
|
|
61
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/url#syntax
|
|
62
|
+
const rebasedUrl = './' + rebasedPath.replace(/\\/g, '/').replace(/[()\s'"]/g, '\\$&');
|
|
63
|
+
updatedContents !== null && updatedContents !== void 0 ? updatedContents : (updatedContents = new magic_string_1.default(contents));
|
|
64
|
+
updatedContents.update(match.index, match.index + match[0].length, `url(${rebasedUrl})`);
|
|
65
|
+
}
|
|
66
|
+
if (updatedContents) {
|
|
67
|
+
contents = updatedContents.toString();
|
|
68
|
+
if (this.rebaseSourceMaps) {
|
|
69
|
+
// Generate an intermediate source map for the rebasing changes
|
|
70
|
+
const map = updatedContents.generateMap({
|
|
71
|
+
hires: true,
|
|
72
|
+
includeContent: true,
|
|
73
|
+
source: canonicalUrl.href,
|
|
74
|
+
});
|
|
75
|
+
this.rebaseSourceMaps.set(canonicalUrl.href, map);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
let syntax;
|
|
80
|
+
switch ((0, node_path_1.extname)(stylesheetPath).toLowerCase()) {
|
|
81
|
+
case 'css':
|
|
82
|
+
syntax = 'css';
|
|
83
|
+
break;
|
|
84
|
+
case 'sass':
|
|
85
|
+
syntax = 'indented';
|
|
86
|
+
break;
|
|
87
|
+
default:
|
|
88
|
+
syntax = 'scss';
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
contents,
|
|
93
|
+
syntax,
|
|
94
|
+
sourceMapUrl: canonicalUrl,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Provides the Sass importer logic to resolve relative stylesheet imports via both import and use rules
|
|
100
|
+
* and also rebase any `url()` function usage within those stylesheets. The rebasing will ensure that
|
|
101
|
+
* the URLs in the output of the Sass compiler reflect the final filesystem location of the output CSS file.
|
|
102
|
+
*/
|
|
103
|
+
class RelativeUrlRebasingImporter extends UrlRebasingImporter {
|
|
104
|
+
constructor(entryDirectory, directoryCache = new Map(), rebaseSourceMaps) {
|
|
105
|
+
super(entryDirectory, rebaseSourceMaps);
|
|
106
|
+
this.directoryCache = directoryCache;
|
|
107
|
+
}
|
|
108
|
+
canonicalize(url, options) {
|
|
109
|
+
return this.resolveImport(url, options.fromImport, true);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Attempts to resolve a provided URL to a stylesheet file using the Sass compiler's resolution algorithm.
|
|
113
|
+
* Based on https://github.com/sass/dart-sass/blob/44d6bb6ac72fe6b93f5bfec371a1fffb18e6b76d/lib/src/importer/utils.dart
|
|
114
|
+
* @param url The file protocol URL to resolve.
|
|
115
|
+
* @param fromImport If true, URL was from an import rule; otherwise from a use rule.
|
|
116
|
+
* @param checkDirectory If true, try checking for a directory with the base name containing an index file.
|
|
117
|
+
* @returns A full resolved URL of the stylesheet file or `null` if not found.
|
|
118
|
+
*/
|
|
119
|
+
resolveImport(url, fromImport, checkDirectory) {
|
|
120
|
+
var _a;
|
|
121
|
+
let stylesheetPath;
|
|
122
|
+
try {
|
|
123
|
+
stylesheetPath = (0, node_url_1.fileURLToPath)(url);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Only file protocol URLs are supported by this importer
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
const directory = (0, node_path_1.dirname)(stylesheetPath);
|
|
130
|
+
const extension = (0, node_path_1.extname)(stylesheetPath);
|
|
131
|
+
const hasStyleExtension = extension === '.scss' || extension === '.sass' || extension === '.css';
|
|
132
|
+
// Remove the style extension if present to allow adding the `.import` suffix
|
|
133
|
+
const filename = (0, node_path_1.basename)(stylesheetPath, hasStyleExtension ? extension : undefined);
|
|
134
|
+
let entries;
|
|
135
|
+
try {
|
|
136
|
+
entries = this.directoryCache.get(directory);
|
|
137
|
+
if (!entries) {
|
|
138
|
+
entries = (0, node_fs_1.readdirSync)(directory, { withFileTypes: true });
|
|
139
|
+
this.directoryCache.set(directory, entries);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const importPotentials = new Set();
|
|
146
|
+
const defaultPotentials = new Set();
|
|
147
|
+
if (hasStyleExtension) {
|
|
148
|
+
if (fromImport) {
|
|
149
|
+
importPotentials.add(filename + '.import' + extension);
|
|
150
|
+
importPotentials.add('_' + filename + '.import' + extension);
|
|
151
|
+
}
|
|
152
|
+
defaultPotentials.add(filename + extension);
|
|
153
|
+
defaultPotentials.add('_' + filename + extension);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
if (fromImport) {
|
|
157
|
+
importPotentials.add(filename + '.import.scss');
|
|
158
|
+
importPotentials.add(filename + '.import.sass');
|
|
159
|
+
importPotentials.add(filename + '.import.css');
|
|
160
|
+
importPotentials.add('_' + filename + '.import.scss');
|
|
161
|
+
importPotentials.add('_' + filename + '.import.sass');
|
|
162
|
+
importPotentials.add('_' + filename + '.import.css');
|
|
163
|
+
}
|
|
164
|
+
defaultPotentials.add(filename + '.scss');
|
|
165
|
+
defaultPotentials.add(filename + '.sass');
|
|
166
|
+
defaultPotentials.add(filename + '.css');
|
|
167
|
+
defaultPotentials.add('_' + filename + '.scss');
|
|
168
|
+
defaultPotentials.add('_' + filename + '.sass');
|
|
169
|
+
defaultPotentials.add('_' + filename + '.css');
|
|
170
|
+
}
|
|
171
|
+
const foundDefaults = [];
|
|
172
|
+
const foundImports = [];
|
|
173
|
+
let hasPotentialIndex = false;
|
|
174
|
+
for (const entry of entries) {
|
|
175
|
+
// Record if the name should be checked as a directory with an index file
|
|
176
|
+
if (checkDirectory && !hasStyleExtension && entry.name === filename && entry.isDirectory()) {
|
|
177
|
+
hasPotentialIndex = true;
|
|
178
|
+
}
|
|
179
|
+
if (!entry.isFile()) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (importPotentials.has(entry.name)) {
|
|
183
|
+
foundImports.push((0, node_path_1.join)(directory, entry.name));
|
|
184
|
+
}
|
|
185
|
+
if (defaultPotentials.has(entry.name)) {
|
|
186
|
+
foundDefaults.push((0, node_path_1.join)(directory, entry.name));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// `foundImports` will only contain elements if `options.fromImport` is true
|
|
190
|
+
const result = (_a = this.checkFound(foundImports)) !== null && _a !== void 0 ? _a : this.checkFound(foundDefaults);
|
|
191
|
+
if (result === null && hasPotentialIndex) {
|
|
192
|
+
// Check for index files using filename as a directory
|
|
193
|
+
return this.resolveImport(url + '/index', fromImport, false);
|
|
194
|
+
}
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Checks an array of potential stylesheet files to determine if there is a valid
|
|
199
|
+
* stylesheet file. More than one discovered file may indicate an error.
|
|
200
|
+
* @param found An array of discovered stylesheet files.
|
|
201
|
+
* @returns A fully resolved URL for a stylesheet file or `null` if not found.
|
|
202
|
+
* @throws If there are ambiguous files discovered.
|
|
203
|
+
*/
|
|
204
|
+
checkFound(found) {
|
|
205
|
+
if (found.length === 0) {
|
|
206
|
+
// Not found
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
// More than one found file may be an error
|
|
210
|
+
if (found.length > 1) {
|
|
211
|
+
// Presence of CSS files alongside a Sass file does not cause an error
|
|
212
|
+
const foundWithoutCss = found.filter((element) => (0, node_path_1.extname)(element) !== '.css');
|
|
213
|
+
// If the length is zero then there are two or more css files
|
|
214
|
+
// If the length is more than one than there are two or more sass/scss files
|
|
215
|
+
if (foundWithoutCss.length !== 1) {
|
|
216
|
+
throw new Error('Ambiguous import detected.');
|
|
217
|
+
}
|
|
218
|
+
// Return the non-CSS file (sass/scss files have priority)
|
|
219
|
+
// https://github.com/sass/dart-sass/blob/44d6bb6ac72fe6b93f5bfec371a1fffb18e6b76d/lib/src/importer/utils.dart#L44-L47
|
|
220
|
+
return (0, node_url_1.pathToFileURL)(foundWithoutCss[0]);
|
|
221
|
+
}
|
|
222
|
+
return (0, node_url_1.pathToFileURL)(found[0]);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
exports.RelativeUrlRebasingImporter = RelativeUrlRebasingImporter;
|
|
226
|
+
/**
|
|
227
|
+
* Provides the Sass importer logic to resolve module (npm package) stylesheet imports via both import and
|
|
228
|
+
* use rules and also rebase any `url()` function usage within those stylesheets. The rebasing will ensure that
|
|
229
|
+
* the URLs in the output of the Sass compiler reflect the final filesystem location of the output CSS file.
|
|
230
|
+
*/
|
|
231
|
+
class ModuleUrlRebasingImporter extends RelativeUrlRebasingImporter {
|
|
232
|
+
constructor(entryDirectory, directoryCache, rebaseSourceMaps, finder) {
|
|
233
|
+
super(entryDirectory, directoryCache, rebaseSourceMaps);
|
|
234
|
+
this.finder = finder;
|
|
235
|
+
}
|
|
236
|
+
canonicalize(url, options) {
|
|
237
|
+
if (url.startsWith('file://')) {
|
|
238
|
+
return super.canonicalize(url, options);
|
|
239
|
+
}
|
|
240
|
+
const result = this.finder(url, options);
|
|
241
|
+
return result ? super.canonicalize(result.href, options) : null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
exports.ModuleUrlRebasingImporter = ModuleUrlRebasingImporter;
|
|
245
|
+
/**
|
|
246
|
+
* Provides the Sass importer logic to resolve load paths located stylesheet imports via both import and
|
|
247
|
+
* use rules and also rebase any `url()` function usage within those stylesheets. The rebasing will ensure that
|
|
248
|
+
* the URLs in the output of the Sass compiler reflect the final filesystem location of the output CSS file.
|
|
249
|
+
*/
|
|
250
|
+
class LoadPathsUrlRebasingImporter extends RelativeUrlRebasingImporter {
|
|
251
|
+
constructor(entryDirectory, directoryCache, rebaseSourceMaps, loadPaths) {
|
|
252
|
+
super(entryDirectory, directoryCache, rebaseSourceMaps);
|
|
253
|
+
this.loadPaths = loadPaths;
|
|
254
|
+
}
|
|
255
|
+
canonicalize(url, options) {
|
|
256
|
+
if (url.startsWith('file://')) {
|
|
257
|
+
return super.canonicalize(url, options);
|
|
258
|
+
}
|
|
259
|
+
let result = null;
|
|
260
|
+
for (const loadPath of this.loadPaths) {
|
|
261
|
+
result = super.canonicalize((0, node_url_1.pathToFileURL)((0, node_path_1.join)(loadPath, url)).href, options);
|
|
262
|
+
if (result !== null) {
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
exports.LoadPathsUrlRebasingImporter = LoadPathsUrlRebasingImporter;
|
|
270
|
+
/**
|
|
271
|
+
* Workaround for Sass not calling instance methods with `this`.
|
|
272
|
+
* The `canonicalize` and `load` methods will be bound to the class instance.
|
|
273
|
+
* @param importer A Sass importer to bind.
|
|
274
|
+
* @returns The bound Sass importer.
|
|
275
|
+
*/
|
|
276
|
+
function sassBindWorkaround(importer) {
|
|
277
|
+
importer.canonicalize = importer.canonicalize.bind(importer);
|
|
278
|
+
importer.load = importer.load.bind(importer);
|
|
279
|
+
return importer;
|
|
280
|
+
}
|
|
281
|
+
exports.sassBindWorkaround = sassBindWorkaround;
|
|
@@ -23,12 +23,14 @@ export interface FileImporterWithRequestContextOptions extends FileImporterOptio
|
|
|
23
23
|
* the worker which can be up to two times faster than the asynchronous variant.
|
|
24
24
|
*/
|
|
25
25
|
export declare class SassWorkerImplementation {
|
|
26
|
+
private rebase;
|
|
26
27
|
private readonly workers;
|
|
27
28
|
private readonly availableWorkers;
|
|
28
29
|
private readonly requests;
|
|
29
30
|
private readonly workerPath;
|
|
30
31
|
private idCounter;
|
|
31
32
|
private nextWorkerIndex;
|
|
33
|
+
constructor(rebase?: boolean);
|
|
32
34
|
/**
|
|
33
35
|
* Provides information about the Sass implementation.
|
|
34
36
|
* This mimics enough of the `dart-sass` value to be used with the `sass-loader`.
|
package/src/sass/sass-service.js
CHANGED
|
@@ -23,7 +23,8 @@ const MAX_RENDER_WORKERS = environment_options_1.maxWorkers;
|
|
|
23
23
|
* the worker which can be up to two times faster than the asynchronous variant.
|
|
24
24
|
*/
|
|
25
25
|
class SassWorkerImplementation {
|
|
26
|
-
constructor() {
|
|
26
|
+
constructor(rebase = false) {
|
|
27
|
+
this.rebase = rebase;
|
|
27
28
|
this.workers = [];
|
|
28
29
|
this.availableWorkers = [];
|
|
29
30
|
this.requests = new Map();
|
|
@@ -73,8 +74,9 @@ class SassWorkerImplementation {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
const callback = (error, result) => {
|
|
77
|
+
var _a;
|
|
76
78
|
if (error) {
|
|
77
|
-
const url = error === null ||
|
|
79
|
+
const url = (_a = error.span) === null || _a === void 0 ? void 0 : _a.url;
|
|
78
80
|
if (url) {
|
|
79
81
|
error.span.url = (0, node_url_1.pathToFileURL)(url);
|
|
80
82
|
}
|
|
@@ -87,12 +89,14 @@ class SassWorkerImplementation {
|
|
|
87
89
|
}
|
|
88
90
|
resolve(result);
|
|
89
91
|
};
|
|
90
|
-
const request = this.createRequest(workerIndex, callback, importers);
|
|
92
|
+
const request = this.createRequest(workerIndex, callback, logger, importers);
|
|
91
93
|
this.requests.set(request.id, request);
|
|
92
94
|
this.workers[workerIndex].postMessage({
|
|
93
95
|
id: request.id,
|
|
94
96
|
source,
|
|
95
97
|
hasImporter: !!(importers === null || importers === void 0 ? void 0 : importers.length),
|
|
98
|
+
hasLogger: !!logger,
|
|
99
|
+
rebase: this.rebase,
|
|
96
100
|
options: {
|
|
97
101
|
...serializableOptions,
|
|
98
102
|
// URL is not serializable so to convert to string here and back to URL in the worker.
|
|
@@ -122,12 +126,24 @@ class SassWorkerImplementation {
|
|
|
122
126
|
transferList: [workerImporterPort],
|
|
123
127
|
});
|
|
124
128
|
worker.on('message', (response) => {
|
|
129
|
+
var _a;
|
|
125
130
|
const request = this.requests.get(response.id);
|
|
126
131
|
if (!request) {
|
|
127
132
|
return;
|
|
128
133
|
}
|
|
129
134
|
this.requests.delete(response.id);
|
|
130
135
|
this.availableWorkers.push(request.workerIndex);
|
|
136
|
+
if (response.warnings && ((_a = request.logger) === null || _a === void 0 ? void 0 : _a.warn)) {
|
|
137
|
+
for (const { message, span, ...options } of response.warnings) {
|
|
138
|
+
request.logger.warn(message, {
|
|
139
|
+
...options,
|
|
140
|
+
span: span && {
|
|
141
|
+
...span,
|
|
142
|
+
url: span.url ? (0, node_url_1.pathToFileURL)(span.url) : undefined,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
131
147
|
if (response.result) {
|
|
132
148
|
request.callback(undefined, {
|
|
133
149
|
...response.result,
|
|
@@ -184,11 +200,12 @@ class SassWorkerImplementation {
|
|
|
184
200
|
}
|
|
185
201
|
return null;
|
|
186
202
|
}
|
|
187
|
-
createRequest(workerIndex, callback, importers) {
|
|
203
|
+
createRequest(workerIndex, callback, logger, importers) {
|
|
188
204
|
return {
|
|
189
205
|
id: this.idCounter++,
|
|
190
206
|
workerIndex,
|
|
191
207
|
callback,
|
|
208
|
+
logger,
|
|
192
209
|
importers,
|
|
193
210
|
};
|
|
194
211
|
}
|
package/src/sass/worker.js
CHANGED
|
@@ -6,51 +6,99 @@
|
|
|
6
6
|
* Use of this source code is governed by an MIT-style license that can be
|
|
7
7
|
* found in the LICENSE file at https://angular.io/license
|
|
8
8
|
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
9
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const remapping_1 = __importDefault(require("@ampproject/remapping"));
|
|
14
|
+
const node_path_1 = require("node:path");
|
|
15
|
+
const node_url_1 = require("node:url");
|
|
16
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
10
17
|
const sass_1 = require("sass");
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
if (!worker_threads_1.parentPort || !worker_threads_1.workerData) {
|
|
18
|
+
const rebasing_importer_1 = require("./rebasing-importer");
|
|
19
|
+
if (!node_worker_threads_1.parentPort || !node_worker_threads_1.workerData) {
|
|
14
20
|
throw new Error('Sass worker must be executed as a Worker.');
|
|
15
21
|
}
|
|
16
22
|
// The importer variables are used to proxy import requests to the main thread
|
|
17
|
-
const { workerImporterPort, importerSignal } =
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
const { workerImporterPort, importerSignal } = node_worker_threads_1.workerData;
|
|
24
|
+
node_worker_threads_1.parentPort.on('message', (message) => {
|
|
25
|
+
var _a, _b;
|
|
26
|
+
if (!node_worker_threads_1.parentPort) {
|
|
20
27
|
throw new Error('"parentPort" is not defined. Sass worker must be executed as a Worker.');
|
|
21
28
|
}
|
|
29
|
+
const { id, hasImporter, hasLogger, source, options, rebase } = message;
|
|
30
|
+
const entryDirectory = (0, node_path_1.dirname)(options.url);
|
|
31
|
+
let warnings;
|
|
22
32
|
try {
|
|
33
|
+
const directoryCache = new Map();
|
|
34
|
+
const rebaseSourceMaps = options.sourceMap ? new Map() : undefined;
|
|
23
35
|
if (hasImporter) {
|
|
24
36
|
// When a custom importer function is present, the importer request must be proxied
|
|
25
37
|
// back to the main thread where it can be executed.
|
|
26
38
|
// This process must be synchronous from the perspective of dart-sass. The `Atomics`
|
|
27
39
|
// functions combined with the shared memory `importSignal` and the Node.js
|
|
28
40
|
// `receiveMessageOnPort` function are used to ensure synchronous behavior.
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return result ? (0, url_1.pathToFileURL)(result) : null;
|
|
38
|
-
},
|
|
41
|
+
const proxyImporter = {
|
|
42
|
+
findFileUrl: (url, options) => {
|
|
43
|
+
var _a;
|
|
44
|
+
Atomics.store(importerSignal, 0, 0);
|
|
45
|
+
workerImporterPort.postMessage({ id, url, options });
|
|
46
|
+
Atomics.wait(importerSignal, 0, 0);
|
|
47
|
+
const result = (_a = (0, node_worker_threads_1.receiveMessageOnPort)(workerImporterPort)) === null || _a === void 0 ? void 0 : _a.message;
|
|
48
|
+
return result ? (0, node_url_1.pathToFileURL)(result) : null;
|
|
39
49
|
},
|
|
50
|
+
};
|
|
51
|
+
options.importers = [
|
|
52
|
+
rebase
|
|
53
|
+
? (0, rebasing_importer_1.sassBindWorkaround)(new rebasing_importer_1.ModuleUrlRebasingImporter(entryDirectory, directoryCache, rebaseSourceMaps, proxyImporter.findFileUrl))
|
|
54
|
+
: proxyImporter,
|
|
40
55
|
];
|
|
41
56
|
}
|
|
57
|
+
if (rebase && ((_a = options.loadPaths) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
58
|
+
(_b = options.importers) !== null && _b !== void 0 ? _b : (options.importers = []);
|
|
59
|
+
options.importers.push((0, rebasing_importer_1.sassBindWorkaround)(new rebasing_importer_1.LoadPathsUrlRebasingImporter(entryDirectory, directoryCache, rebaseSourceMaps, options.loadPaths)));
|
|
60
|
+
options.loadPaths = undefined;
|
|
61
|
+
}
|
|
62
|
+
let relativeImporter;
|
|
63
|
+
if (rebase) {
|
|
64
|
+
relativeImporter = (0, rebasing_importer_1.sassBindWorkaround)(new rebasing_importer_1.RelativeUrlRebasingImporter(entryDirectory, directoryCache, rebaseSourceMaps));
|
|
65
|
+
}
|
|
42
66
|
// The synchronous Sass render function can be up to two times faster than the async variant
|
|
43
67
|
const result = (0, sass_1.compileString)(source, {
|
|
44
68
|
...options,
|
|
45
69
|
// URL is not serializable so to convert to string in the parent and back to URL here.
|
|
46
|
-
url:
|
|
70
|
+
url: (0, node_url_1.pathToFileURL)(options.url),
|
|
71
|
+
// The `importer` option (singular) handles relative imports
|
|
72
|
+
importer: relativeImporter,
|
|
73
|
+
logger: hasLogger
|
|
74
|
+
? {
|
|
75
|
+
warn(message, { deprecation, span, stack }) {
|
|
76
|
+
warnings !== null && warnings !== void 0 ? warnings : (warnings = []);
|
|
77
|
+
warnings.push({
|
|
78
|
+
message,
|
|
79
|
+
deprecation,
|
|
80
|
+
stack,
|
|
81
|
+
span: span && convertSourceSpan(span),
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
: undefined,
|
|
47
86
|
});
|
|
48
|
-
|
|
87
|
+
if (result.sourceMap && (rebaseSourceMaps === null || rebaseSourceMaps === void 0 ? void 0 : rebaseSourceMaps.size)) {
|
|
88
|
+
// Merge the intermediate rebasing source maps into the final Sass generated source map.
|
|
89
|
+
// Casting is required due to small but compatible differences in typings between the packages.
|
|
90
|
+
result.sourceMap = (0, remapping_1.default)(result.sourceMap,
|
|
91
|
+
// To prevent an infinite lookup loop, skip getting the source when the rebasing source map
|
|
92
|
+
// is referencing its original self.
|
|
93
|
+
(file, context) => (file !== context.importer ? rebaseSourceMaps.get(file) : null));
|
|
94
|
+
}
|
|
95
|
+
node_worker_threads_1.parentPort.postMessage({
|
|
49
96
|
id,
|
|
97
|
+
warnings,
|
|
50
98
|
result: {
|
|
51
99
|
...result,
|
|
52
100
|
// URL is not serializable so to convert to string here and back to URL in the parent.
|
|
53
|
-
loadedUrls: result.loadedUrls.map((p) => (0,
|
|
101
|
+
loadedUrls: result.loadedUrls.map((p) => (0, node_url_1.fileURLToPath)(p)),
|
|
54
102
|
},
|
|
55
103
|
});
|
|
56
104
|
}
|
|
@@ -58,24 +106,11 @@ worker_threads_1.parentPort.on('message', ({ id, hasImporter, source, options })
|
|
|
58
106
|
// Needed because V8 will only serialize the message and stack properties of an Error instance.
|
|
59
107
|
if (error instanceof sass_1.Exception) {
|
|
60
108
|
const { span, message, stack, sassMessage, sassStack } = error;
|
|
61
|
-
|
|
109
|
+
node_worker_threads_1.parentPort.postMessage({
|
|
62
110
|
id,
|
|
111
|
+
warnings,
|
|
63
112
|
error: {
|
|
64
|
-
span:
|
|
65
|
-
text: span.text,
|
|
66
|
-
context: span.context,
|
|
67
|
-
end: {
|
|
68
|
-
column: span.end.column,
|
|
69
|
-
offset: span.end.offset,
|
|
70
|
-
line: span.end.line,
|
|
71
|
-
},
|
|
72
|
-
start: {
|
|
73
|
-
column: span.start.column,
|
|
74
|
-
offset: span.start.offset,
|
|
75
|
-
line: span.start.line,
|
|
76
|
-
},
|
|
77
|
-
url: span.url ? (0, url_1.fileURLToPath)(span.url) : undefined,
|
|
78
|
-
},
|
|
113
|
+
span: convertSourceSpan(span),
|
|
79
114
|
message,
|
|
80
115
|
stack,
|
|
81
116
|
sassMessage,
|
|
@@ -85,10 +120,40 @@ worker_threads_1.parentPort.on('message', ({ id, hasImporter, source, options })
|
|
|
85
120
|
}
|
|
86
121
|
else if (error instanceof Error) {
|
|
87
122
|
const { message, stack } = error;
|
|
88
|
-
|
|
123
|
+
node_worker_threads_1.parentPort.postMessage({ id, warnings, error: { message, stack } });
|
|
89
124
|
}
|
|
90
125
|
else {
|
|
91
|
-
|
|
126
|
+
node_worker_threads_1.parentPort.postMessage({
|
|
127
|
+
id,
|
|
128
|
+
warnings,
|
|
129
|
+
error: { message: 'An unknown error has occurred.' },
|
|
130
|
+
});
|
|
92
131
|
}
|
|
93
132
|
}
|
|
94
133
|
});
|
|
134
|
+
/**
|
|
135
|
+
* Converts a Sass SourceSpan object into a serializable form.
|
|
136
|
+
* The SourceSpan object contains a URL property which must be converted into a string.
|
|
137
|
+
* Also, most of the interface's properties are get accessors and are not automatically
|
|
138
|
+
* serialized when sent back from the worker.
|
|
139
|
+
*
|
|
140
|
+
* @param span The Sass SourceSpan object to convert.
|
|
141
|
+
* @returns A serializable form of the SourceSpan object.
|
|
142
|
+
*/
|
|
143
|
+
function convertSourceSpan(span) {
|
|
144
|
+
return {
|
|
145
|
+
text: span.text,
|
|
146
|
+
context: span.context,
|
|
147
|
+
end: {
|
|
148
|
+
column: span.end.column,
|
|
149
|
+
offset: span.end.offset,
|
|
150
|
+
line: span.end.line,
|
|
151
|
+
},
|
|
152
|
+
start: {
|
|
153
|
+
column: span.start.column,
|
|
154
|
+
offset: span.start.offset,
|
|
155
|
+
line: span.start.line,
|
|
156
|
+
},
|
|
157
|
+
url: span.url ? (0, node_url_1.fileURLToPath)(span.url) : undefined,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -86,7 +86,7 @@ async function getCommonConfig(wco) {
|
|
|
86
86
|
if (isPlatformServer) {
|
|
87
87
|
// Fixes Critical dependency: the request of a dependency is an expression
|
|
88
88
|
extraPlugins.push(new webpack_2.ContextReplacementPlugin(/@?hapi|express[\\/]/));
|
|
89
|
-
if (Array.isArray(entryPoints['main'])) {
|
|
89
|
+
if ((0, helpers_1.isPlatformServerInstalled)(wco.root) && Array.isArray(entryPoints['main'])) {
|
|
90
90
|
// This import must come before any imports (direct or transitive) that rely on DOM built-ins being
|
|
91
91
|
// available, such as `@angular/elements`.
|
|
92
92
|
entryPoints['main'].unshift('@angular/platform-server/init');
|
|
@@ -48,7 +48,7 @@ const helpers_1 = require("../utils/helpers");
|
|
|
48
48
|
// eslint-disable-next-line max-lines-per-function
|
|
49
49
|
function getStylesConfig(wco) {
|
|
50
50
|
var _a, _b, _c;
|
|
51
|
-
const { root, buildOptions } = wco;
|
|
51
|
+
const { root, buildOptions, logger } = wco;
|
|
52
52
|
const extraPlugins = [];
|
|
53
53
|
extraPlugins.push(new plugins_1.AnyComponentStyleBudgetChecker(buildOptions.budgets));
|
|
54
54
|
const cssSourceMap = buildOptions.sourceMap.styles;
|
|
@@ -93,7 +93,7 @@ function getStylesConfig(wco) {
|
|
|
93
93
|
}
|
|
94
94
|
catch {
|
|
95
95
|
const relativeTailwindConfigPath = path.relative(wco.root, tailwindConfigPath);
|
|
96
|
-
|
|
96
|
+
logger.warn(`Tailwind CSS configuration file found (${relativeTailwindConfigPath})` +
|
|
97
97
|
` but the 'tailwindcss' package is not installed.` +
|
|
98
98
|
` To enable Tailwind CSS, please install the 'tailwindcss' package.`);
|
|
99
99
|
}
|
|
@@ -131,14 +131,21 @@ function getStylesConfig(wco) {
|
|
|
131
131
|
optionGenerator.config = false;
|
|
132
132
|
return optionGenerator;
|
|
133
133
|
};
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
134
|
+
let componentsSourceMap = !!cssSourceMap;
|
|
135
|
+
if (cssSourceMap) {
|
|
136
|
+
if (buildOptions.optimization.styles.minify) {
|
|
137
|
+
// Never use component css sourcemap when style optimizations are on.
|
|
138
|
+
// It will just increase bundle size without offering good debug experience.
|
|
139
|
+
logger.warn('Components styles sourcemaps are not generated when styles optimization is enabled.');
|
|
140
|
+
componentsSourceMap = false;
|
|
141
|
+
}
|
|
142
|
+
else if (buildOptions.sourceMap.hidden) {
|
|
143
|
+
// Inline all sourcemap types except hidden ones, which are the same as no sourcemaps
|
|
144
|
+
// for component css.
|
|
145
|
+
logger.warn('Components styles sourcemaps are not generated when sourcemaps are hidden.');
|
|
146
|
+
componentsSourceMap = false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
142
149
|
// extract global css from js files into own css file.
|
|
143
150
|
extraPlugins.push(new mini_css_extract_plugin_1.default({ filename: `[name]${hashFormat.extract}.css` }));
|
|
144
151
|
if (!buildOptions.hmr) {
|
|
@@ -33,3 +33,8 @@ export declare function globalScriptsByBundleName(scripts: ScriptElement[]): {
|
|
|
33
33
|
}[];
|
|
34
34
|
export declare function assetPatterns(root: string, assets: AssetPatternClass[]): ObjectPattern[];
|
|
35
35
|
export declare function getStatsOptions(verbose?: boolean): WebpackStatsOptions;
|
|
36
|
+
/**
|
|
37
|
+
* @param root the workspace root
|
|
38
|
+
* @returns `true` when `@angular/platform-server` is installed.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isPlatformServerInstalled(root: string): boolean;
|
|
@@ -33,7 +33,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
33
33
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
34
34
|
};
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.getStatsOptions = exports.assetPatterns = exports.globalScriptsByBundleName = exports.getCacheSettings = exports.normalizeGlobalStyles = exports.getInstrumentationExcludedPaths = exports.assetNameTemplateFactory = exports.normalizeExtraEntryPoints = exports.getOutputHashFormat = void 0;
|
|
36
|
+
exports.isPlatformServerInstalled = exports.getStatsOptions = exports.assetPatterns = exports.globalScriptsByBundleName = exports.getCacheSettings = exports.normalizeGlobalStyles = exports.getInstrumentationExcludedPaths = exports.assetNameTemplateFactory = exports.normalizeExtraEntryPoints = exports.getOutputHashFormat = void 0;
|
|
37
37
|
const crypto_1 = require("crypto");
|
|
38
38
|
const glob_1 = __importDefault(require("glob"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
@@ -278,3 +278,17 @@ function getStatsOptions(verbose = false) {
|
|
|
278
278
|
: webpackOutputOptions;
|
|
279
279
|
}
|
|
280
280
|
exports.getStatsOptions = getStatsOptions;
|
|
281
|
+
/**
|
|
282
|
+
* @param root the workspace root
|
|
283
|
+
* @returns `true` when `@angular/platform-server` is installed.
|
|
284
|
+
*/
|
|
285
|
+
function isPlatformServerInstalled(root) {
|
|
286
|
+
try {
|
|
287
|
+
require.resolve('@angular/platform-server', { paths: [root] });
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
exports.isPlatformServerInstalled = isPlatformServerInstalled;
|