@angular-devkit/build-angular 15.0.0-rc.2 → 15.0.0-rc.4
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 +19 -19
- package/src/builders/browser-esbuild/compiler-plugin.js +25 -15
- package/src/builders/browser-esbuild/css-resource-plugin.js +8 -0
- package/src/builders/browser-esbuild/esbuild.d.ts +3 -1
- package/src/builders/browser-esbuild/esbuild.js +24 -3
- package/src/builders/browser-esbuild/index.js +63 -80
- package/src/builders/browser-esbuild/sass-plugin.js +44 -1
- package/src/builders/browser-esbuild/stylesheets.d.ts +4 -1
- package/src/builders/browser-esbuild/stylesheets.js +15 -13
- 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 +5 -2
- package/src/sass/worker.js +56 -24
- 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
|
@@ -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
|
}
|
|
@@ -94,6 +96,7 @@ class SassWorkerImplementation {
|
|
|
94
96
|
source,
|
|
95
97
|
hasImporter: !!(importers === null || importers === void 0 ? void 0 : importers.length),
|
|
96
98
|
hasLogger: !!logger,
|
|
99
|
+
rebase: this.rebase,
|
|
97
100
|
options: {
|
|
98
101
|
...serializableOptions,
|
|
99
102
|
// URL is not serializable so to convert to string here and back to URL in the worker.
|
package/src/sass/worker.js
CHANGED
|
@@ -6,46 +6,70 @@
|
|
|
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
|
}
|
|
22
|
-
const { id, hasImporter, hasLogger, source, options } = message;
|
|
29
|
+
const { id, hasImporter, hasLogger, source, options, rebase } = message;
|
|
30
|
+
const entryDirectory = (0, node_path_1.dirname)(options.url);
|
|
23
31
|
let warnings;
|
|
24
32
|
try {
|
|
33
|
+
const directoryCache = new Map();
|
|
34
|
+
const rebaseSourceMaps = options.sourceMap ? new Map() : undefined;
|
|
25
35
|
if (hasImporter) {
|
|
26
36
|
// When a custom importer function is present, the importer request must be proxied
|
|
27
37
|
// back to the main thread where it can be executed.
|
|
28
38
|
// This process must be synchronous from the perspective of dart-sass. The `Atomics`
|
|
29
39
|
// functions combined with the shared memory `importSignal` and the Node.js
|
|
30
40
|
// `receiveMessageOnPort` function are used to ensure synchronous behavior.
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return result ? (0, url_1.pathToFileURL)(result) : null;
|
|
40
|
-
},
|
|
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;
|
|
41
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,
|
|
42
55
|
];
|
|
43
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
|
+
}
|
|
44
66
|
// The synchronous Sass render function can be up to two times faster than the async variant
|
|
45
67
|
const result = (0, sass_1.compileString)(source, {
|
|
46
68
|
...options,
|
|
47
69
|
// URL is not serializable so to convert to string in the parent and back to URL here.
|
|
48
|
-
url:
|
|
70
|
+
url: (0, node_url_1.pathToFileURL)(options.url),
|
|
71
|
+
// The `importer` option (singular) handles relative imports
|
|
72
|
+
importer: relativeImporter,
|
|
49
73
|
logger: hasLogger
|
|
50
74
|
? {
|
|
51
75
|
warn(message, { deprecation, span, stack }) {
|
|
@@ -60,13 +84,21 @@ worker_threads_1.parentPort.on('message', (message) => {
|
|
|
60
84
|
}
|
|
61
85
|
: undefined,
|
|
62
86
|
});
|
|
63
|
-
|
|
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({
|
|
64
96
|
id,
|
|
65
97
|
warnings,
|
|
66
98
|
result: {
|
|
67
99
|
...result,
|
|
68
100
|
// URL is not serializable so to convert to string here and back to URL in the parent.
|
|
69
|
-
loadedUrls: result.loadedUrls.map((p) => (0,
|
|
101
|
+
loadedUrls: result.loadedUrls.map((p) => (0, node_url_1.fileURLToPath)(p)),
|
|
70
102
|
},
|
|
71
103
|
});
|
|
72
104
|
}
|
|
@@ -74,7 +106,7 @@ worker_threads_1.parentPort.on('message', (message) => {
|
|
|
74
106
|
// Needed because V8 will only serialize the message and stack properties of an Error instance.
|
|
75
107
|
if (error instanceof sass_1.Exception) {
|
|
76
108
|
const { span, message, stack, sassMessage, sassStack } = error;
|
|
77
|
-
|
|
109
|
+
node_worker_threads_1.parentPort.postMessage({
|
|
78
110
|
id,
|
|
79
111
|
warnings,
|
|
80
112
|
error: {
|
|
@@ -88,10 +120,10 @@ worker_threads_1.parentPort.on('message', (message) => {
|
|
|
88
120
|
}
|
|
89
121
|
else if (error instanceof Error) {
|
|
90
122
|
const { message, stack } = error;
|
|
91
|
-
|
|
123
|
+
node_worker_threads_1.parentPort.postMessage({ id, warnings, error: { message, stack } });
|
|
92
124
|
}
|
|
93
125
|
else {
|
|
94
|
-
|
|
126
|
+
node_worker_threads_1.parentPort.postMessage({
|
|
95
127
|
id,
|
|
96
128
|
warnings,
|
|
97
129
|
error: { message: 'An unknown error has occurred.' },
|
|
@@ -122,6 +154,6 @@ function convertSourceSpan(span) {
|
|
|
122
154
|
offset: span.start.offset,
|
|
123
155
|
line: span.start.line,
|
|
124
156
|
},
|
|
125
|
-
url: span.url ? (0,
|
|
157
|
+
url: span.url ? (0, node_url_1.fileURLToPath)(span.url) : undefined,
|
|
126
158
|
};
|
|
127
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');
|