@nx/angular-rspack 23.1.0 → 23.1.1
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/dist/lib/config/config-utils/browser-config.d.ts +4 -1
- package/dist/lib/config/config-utils/browser-config.d.ts.map +1 -1
- package/dist/lib/config/config-utils/browser-config.js +5 -18
- package/dist/lib/config/config-utils/server-config.d.ts +4 -1
- package/dist/lib/config/config-utils/server-config.d.ts.map +1 -1
- package/dist/lib/config/config-utils/server-config.js +10 -18
- package/dist/lib/config/config-utils/swc-transpilation.d.ts +16 -0
- package/dist/lib/config/config-utils/swc-transpilation.d.ts.map +1 -0
- package/dist/lib/config/config-utils/swc-transpilation.js +50 -0
- package/dist/lib/config/create-config.d.ts.map +1 -1
- package/dist/lib/config/create-config.js +20 -2
- package/dist/lib/models/augmented-compilation.d.ts +6 -0
- package/dist/lib/models/augmented-compilation.d.ts.map +1 -1
- package/dist/lib/plugins/angular-rspack-plugin.d.ts +9 -0
- package/dist/lib/plugins/angular-rspack-plugin.d.ts.map +1 -1
- package/dist/lib/plugins/angular-rspack-plugin.js +245 -83
- package/dist/lib/plugins/extract-licenses-plugin.d.ts +78 -0
- package/dist/lib/plugins/extract-licenses-plugin.d.ts.map +1 -0
- package/dist/lib/plugins/extract-licenses-plugin.js +217 -0
- package/dist/lib/plugins/loaders/angular-partial-transform.loader.d.ts +2 -2
- package/dist/lib/plugins/loaders/angular-partial-transform.loader.d.ts.map +1 -1
- package/dist/lib/plugins/loaders/angular-partial-transform.loader.js +78 -16
- package/dist/lib/plugins/loaders/angular-transform.loader.d.ts.map +1 -1
- package/dist/lib/plugins/loaders/angular-transform.loader.js +49 -20
- package/dist/lib/plugins/loaders/inline-source-map.d.ts +34 -0
- package/dist/lib/plugins/loaders/inline-source-map.d.ts.map +1 -0
- package/dist/lib/plugins/loaders/inline-source-map.js +76 -0
- package/dist/lib/plugins/ng-rspack.d.ts +18 -0
- package/dist/lib/plugins/ng-rspack.d.ts.map +1 -1
- package/dist/lib/plugins/ng-rspack.js +43 -9
- package/dist/lib/plugins/prerender-plugin.d.ts.map +1 -1
- package/dist/lib/plugins/prerender-plugin.js +26 -3
- package/dist/lib/utils/postcss-cli-resources.d.ts.map +1 -1
- package/dist/lib/utils/postcss-cli-resources.js +8 -4
- package/package.json +5 -11
- package/LICENSE +0 -22
|
@@ -0,0 +1,217 @@
|
|
|
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.dev/license
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ExtractLicensesPlugin = void 0;
|
|
11
|
+
exports.extractLicenses = extractLicenses;
|
|
12
|
+
const tslib_1 = require("tslib");
|
|
13
|
+
const promises_1 = require("node:fs/promises");
|
|
14
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
15
|
+
const models_1 = require("../models");
|
|
16
|
+
/**
|
|
17
|
+
* The path segment used to signify that a file is part of a package.
|
|
18
|
+
*/
|
|
19
|
+
const NODE_MODULE_SEGMENT = 'node_modules';
|
|
20
|
+
/**
|
|
21
|
+
* String constant for the NPM recommended custom license wording.
|
|
22
|
+
*
|
|
23
|
+
* See: https://docs.npmjs.com/cli/v9/configuring-npm/package-json#license
|
|
24
|
+
*
|
|
25
|
+
* Example:
|
|
26
|
+
* ```
|
|
27
|
+
* {
|
|
28
|
+
* "license" : "SEE LICENSE IN <filename>"
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
const CUSTOM_LICENSE_TEXT = 'SEE LICENSE IN ';
|
|
33
|
+
/**
|
|
34
|
+
* A list of commonly named license files found within packages.
|
|
35
|
+
*/
|
|
36
|
+
const LICENSE_FILES = ['LICENSE', 'LICENSE.txt', 'LICENSE.md'];
|
|
37
|
+
/**
|
|
38
|
+
* Header text that will be added to the top of the output license extraction file.
|
|
39
|
+
*/
|
|
40
|
+
const EXTRACTION_FILE_HEADER = '';
|
|
41
|
+
/**
|
|
42
|
+
* The package entry separator to use within the output license extraction file.
|
|
43
|
+
*/
|
|
44
|
+
const EXTRACTION_FILE_SEPARATOR = '-'.repeat(80) + '\n';
|
|
45
|
+
/**
|
|
46
|
+
* Extracts license information for each node module package included in the output
|
|
47
|
+
* files of the built code. This includes JavaScript and CSS output files. The esbuild
|
|
48
|
+
* metafile generated during the bundling steps is used as the source of information
|
|
49
|
+
* regarding what input files where included and where they are located. A path segment
|
|
50
|
+
* of `node_modules` is used to indicate that a file belongs to a package and its license
|
|
51
|
+
* should be include in the output licenses file.
|
|
52
|
+
*
|
|
53
|
+
* The package name and license field are extracted from the `package.json` file for the
|
|
54
|
+
* package. If a license file (e.g., `LICENSE`) is present in the root of the package, it
|
|
55
|
+
* will also be included in the output licenses file.
|
|
56
|
+
*
|
|
57
|
+
* Vendored from `@angular/build` (`src/tools/esbuild/license-extractor.ts`, identical
|
|
58
|
+
* across the supported Angular majors) since it is not exposed in the package's public
|
|
59
|
+
* or private API. Only the esbuild `Metafile` type import is replaced with the local
|
|
60
|
+
* `LicenseMetafile` interface.
|
|
61
|
+
*
|
|
62
|
+
* @param metafile An esbuild metafile object.
|
|
63
|
+
* @param rootDirectory The root directory of the workspace.
|
|
64
|
+
* @returns A string containing the content of the output licenses file.
|
|
65
|
+
*/
|
|
66
|
+
async function extractLicenses(metafile, rootDirectory) {
|
|
67
|
+
let extractedLicenseContent = `${EXTRACTION_FILE_HEADER}\n${EXTRACTION_FILE_SEPARATOR}`;
|
|
68
|
+
const seenPaths = new Set();
|
|
69
|
+
const seenPackages = new Set();
|
|
70
|
+
for (const entry of Object.values(metafile.outputs)) {
|
|
71
|
+
for (const [inputPath, { bytesInOutput }] of Object.entries(entry.inputs)) {
|
|
72
|
+
// Skip if not included in output
|
|
73
|
+
if (bytesInOutput <= 0) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Skip already processed paths
|
|
77
|
+
if (seenPaths.has(inputPath)) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
seenPaths.add(inputPath);
|
|
81
|
+
// Skip non-package paths
|
|
82
|
+
if (!inputPath.includes(NODE_MODULE_SEGMENT)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// Extract the package name from the path
|
|
86
|
+
let baseDirectory = node_path_1.default.join(rootDirectory, inputPath);
|
|
87
|
+
let nameOrScope, nameOrFile;
|
|
88
|
+
let found = false;
|
|
89
|
+
while (baseDirectory !== node_path_1.default.dirname(baseDirectory)) {
|
|
90
|
+
const segment = node_path_1.default.basename(baseDirectory);
|
|
91
|
+
if (segment === NODE_MODULE_SEGMENT) {
|
|
92
|
+
found = true;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
nameOrFile = nameOrScope;
|
|
96
|
+
nameOrScope = segment;
|
|
97
|
+
baseDirectory = node_path_1.default.dirname(baseDirectory);
|
|
98
|
+
}
|
|
99
|
+
// Skip non-package path edge cases that are not caught in the includes check above
|
|
100
|
+
if (!found || !nameOrScope) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const packageName = nameOrScope.startsWith('@')
|
|
104
|
+
? `${nameOrScope}/${nameOrFile}`
|
|
105
|
+
: nameOrScope;
|
|
106
|
+
const packageDirectory = node_path_1.default.join(baseDirectory, packageName);
|
|
107
|
+
// Load the package's metadata to find the package's name, version, and license type
|
|
108
|
+
const packageJsonPath = node_path_1.default.join(packageDirectory, 'package.json');
|
|
109
|
+
let packageJson;
|
|
110
|
+
try {
|
|
111
|
+
packageJson = JSON.parse(await (0, promises_1.readFile)(packageJsonPath, 'utf-8'));
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Invalid package
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Skip already processed packages
|
|
118
|
+
const packageId = `${packageName}@${packageJson.version}`;
|
|
119
|
+
if (seenPackages.has(packageId)) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
seenPackages.add(packageId);
|
|
123
|
+
// Attempt to find license text inside package
|
|
124
|
+
let licenseText = '';
|
|
125
|
+
if (typeof packageJson.license === 'string' &&
|
|
126
|
+
packageJson.license.toLowerCase().startsWith(CUSTOM_LICENSE_TEXT)) {
|
|
127
|
+
// Attempt to load the package's custom license
|
|
128
|
+
let customLicensePath;
|
|
129
|
+
const customLicenseFile = node_path_1.default.normalize(packageJson.license.slice(CUSTOM_LICENSE_TEXT.length + 1).trim());
|
|
130
|
+
if (customLicenseFile.startsWith('..') ||
|
|
131
|
+
node_path_1.default.isAbsolute(customLicenseFile)) {
|
|
132
|
+
// Path is attempting to access files outside of the package
|
|
133
|
+
// TODO: Issue warning?
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
customLicensePath = node_path_1.default.join(packageDirectory, customLicenseFile);
|
|
137
|
+
try {
|
|
138
|
+
licenseText = await (0, promises_1.readFile)(customLicensePath, 'utf-8');
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
catch { }
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// Search for a license file within the root of the package
|
|
146
|
+
for (const potentialLicense of LICENSE_FILES) {
|
|
147
|
+
const packageLicensePath = node_path_1.default.join(packageDirectory, potentialLicense);
|
|
148
|
+
try {
|
|
149
|
+
licenseText = await (0, promises_1.readFile)(packageLicensePath, 'utf-8');
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
catch { }
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Generate the package's license entry in the output content
|
|
156
|
+
extractedLicenseContent += `Package: ${packageJson.name}\n`;
|
|
157
|
+
extractedLicenseContent += `License: ${JSON.stringify(packageJson.license, null, 2)}\n`;
|
|
158
|
+
extractedLicenseContent += `\n${licenseText}\n`;
|
|
159
|
+
extractedLicenseContent += EXTRACTION_FILE_SEPARATOR;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return extractedLicenseContent;
|
|
163
|
+
}
|
|
164
|
+
const PLUGIN_NAME = 'angular-extract-licenses-plugin';
|
|
165
|
+
/**
|
|
166
|
+
* Emits a licenses file for the node module packages included in the output,
|
|
167
|
+
* mirroring the `@angular/build` application builder's `extractLicenses`
|
|
168
|
+
* behavior and output. Feeds the chunk graph's module paths to the vendored
|
|
169
|
+
* extractor in place of an esbuild metafile.
|
|
170
|
+
*/
|
|
171
|
+
class ExtractLicensesPlugin {
|
|
172
|
+
constructor(options) {
|
|
173
|
+
this.options = options;
|
|
174
|
+
this.sharedInputs = options.sharedInputs ?? new Map();
|
|
175
|
+
}
|
|
176
|
+
apply(compiler) {
|
|
177
|
+
compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
|
|
178
|
+
compilation.hooks.processAssets.tapPromise({
|
|
179
|
+
name: PLUGIN_NAME,
|
|
180
|
+
stage: compiler.rspack.Compilation.PROCESS_ASSETS_STAGE_REPORT,
|
|
181
|
+
}, async () => {
|
|
182
|
+
const { outputFilename, rootDirectory } = this.options;
|
|
183
|
+
const inputs = {};
|
|
184
|
+
for (const chunk of compilation.chunks) {
|
|
185
|
+
for (const module of compilation.chunkGraph.getChunkModulesIterable(chunk)) {
|
|
186
|
+
// Concatenated modules (production) wrap the actual source
|
|
187
|
+
// modules, whose paths carry the package information.
|
|
188
|
+
const innerModules = module
|
|
189
|
+
.modules;
|
|
190
|
+
for (const m of innerModules ?? [module]) {
|
|
191
|
+
const resourcePath = m.nameForCondition?.();
|
|
192
|
+
if (!resourcePath) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
inputs[node_path_1.default.relative(rootDirectory, resourcePath)] = {
|
|
196
|
+
bytesInOutput: 1,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Packages bundled into component stylesheets never appear in the
|
|
202
|
+
// chunk graph; their inputs are tracked by the Angular plugin.
|
|
203
|
+
const stylesheetInputs = compilation[models_1.NG_RSPACK_SYMBOL_NAME]?.().stylesheetMetafileInputs;
|
|
204
|
+
Object.assign(inputs, stylesheetInputs);
|
|
205
|
+
this.sharedInputs.set(this, inputs);
|
|
206
|
+
const outputs = {};
|
|
207
|
+
let outputIndex = 0;
|
|
208
|
+
for (const compilerInputs of this.sharedInputs.values()) {
|
|
209
|
+
outputs[outputIndex++] = { inputs: compilerInputs };
|
|
210
|
+
}
|
|
211
|
+
const licenses = await extractLicenses({ outputs }, rootDirectory);
|
|
212
|
+
compilation.emitAsset(outputFilename, new compiler.rspack.sources.RawSource(licenses));
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
exports.ExtractLicensesPlugin = ExtractLicensesPlugin;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { LoaderContext } from '@rspack/core';
|
|
2
|
-
export default function loader(this: LoaderContext<unknown>, content: string): void;
|
|
1
|
+
import { LoaderContext, RawSourceMap } from '@rspack/core';
|
|
2
|
+
export default function loader(this: LoaderContext<unknown>, content: string, inputMap?: string | RawSourceMap): void;
|
|
3
3
|
//# sourceMappingURL=angular-partial-transform.loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-partial-transform.loader.d.ts","sourceRoot":"","sources":["../../../../src/lib/plugins/loaders/angular-partial-transform.loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"angular-partial-transform.loader.d.ts","sourceRoot":"","sources":["../../../../src/lib/plugins/loaders/angular-partial-transform.loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAQ3D,MAAM,CAAC,OAAO,UAAU,MAAM,CAC5B,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,EAC5B,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,QAuIjC"}
|
|
@@ -1,43 +1,105 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = loader;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const angular_rspack_compiler_1 = require("@nx/angular-rspack-compiler");
|
|
4
6
|
const models_1 = require("../../models");
|
|
5
|
-
|
|
7
|
+
const inline_source_map_1 = require("./inline-source-map");
|
|
8
|
+
function loader(content, inputMap) {
|
|
6
9
|
const callback = this.async();
|
|
7
10
|
if (this._compilation[models_1.NG_RSPACK_SYMBOL_NAME] ===
|
|
8
11
|
undefined) {
|
|
9
|
-
callback(null, content);
|
|
12
|
+
callback(null, content, inputMap);
|
|
10
13
|
}
|
|
11
14
|
else {
|
|
12
|
-
const { javascriptTransformer, typescriptFileCache, angularCompilationFailed, } = this._compilation[models_1.NG_RSPACK_SYMBOL_NAME]();
|
|
15
|
+
const { javascriptTransformer, typescriptFileCache, babelFileCache, angularCompilationFailed, } = this._compilation[models_1.NG_RSPACK_SYMBOL_NAME]();
|
|
16
|
+
// The sourcemap chained by earlier loaders: source-map-loader runs first
|
|
17
|
+
// and consumes the file's own sourceMappingURL comment (inline or an
|
|
18
|
+
// external .map file) subject to the vendor sourcemap policy. Rspack
|
|
19
|
+
// fails the module build on maps it cannot deserialize, so drop anything
|
|
20
|
+
// unusable instead of forwarding it.
|
|
21
|
+
const chainMap = (0, inline_source_map_1.isForwardableSourceMap)(inputMap) ? inputMap : undefined;
|
|
13
22
|
if (angularCompilationFailed) {
|
|
14
23
|
// The build is already failing with the Angular compilation error,
|
|
15
24
|
// so skip transforming and pass the original content through.
|
|
16
|
-
callback(null, content);
|
|
25
|
+
callback(null, content, chainMap);
|
|
17
26
|
return;
|
|
18
27
|
}
|
|
19
28
|
const request = this.resourcePath;
|
|
20
29
|
if (request.startsWith('data:text/javascript') &&
|
|
21
30
|
request.includes('__module_federation_bundler_runtime__')) {
|
|
22
|
-
callback(null, content);
|
|
31
|
+
callback(null, content, chainMap);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const normalizedRequest = (0, angular_rspack_compiler_1.toTypeScriptFileCacheKey)(request);
|
|
35
|
+
const cached = typescriptFileCache.get(normalizedRequest);
|
|
36
|
+
if (cached !== undefined) {
|
|
37
|
+
if (typeof cached !== 'string') {
|
|
38
|
+
callback(null, cached.code, cached.map);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// A string entry is raw JavaScript emitted by the Angular compilation
|
|
42
|
+
// (allowJs); it always needs the JavaScript transformations applied.
|
|
43
|
+
javascriptTransformer
|
|
44
|
+
.transformData(normalizedRequest, cached, true, false)
|
|
45
|
+
.then((transformed) => {
|
|
46
|
+
const text = Buffer.from(transformed).toString('utf8');
|
|
47
|
+
const { code, map } = (0, inline_source_map_1.extractInlineSourceMap)(text);
|
|
48
|
+
// A newer emit may have replaced the entry while transforming;
|
|
49
|
+
// only store the result for the emit it was produced from.
|
|
50
|
+
if (typescriptFileCache.get(normalizedRequest) === cached) {
|
|
51
|
+
typescriptFileCache.set(normalizedRequest, { code, map });
|
|
52
|
+
}
|
|
53
|
+
callback(null, code, map);
|
|
54
|
+
}, (error) => {
|
|
55
|
+
// Fail the module instead of leaving the loader callback pending,
|
|
56
|
+
// which would hang the build.
|
|
57
|
+
callback(error instanceof Error ? error : new Error(String(error)));
|
|
58
|
+
});
|
|
23
59
|
return;
|
|
24
60
|
}
|
|
25
61
|
if (!content.includes('@angular')) {
|
|
26
|
-
callback(null, content);
|
|
62
|
+
callback(null, content, chainMap);
|
|
27
63
|
return;
|
|
28
64
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
65
|
+
// The chained map takes part in cache validity: the transformer reads
|
|
66
|
+
// the file's external map file itself and merges it into its output, so
|
|
67
|
+
// a cached transform is stale once that map changes, even though the
|
|
68
|
+
// file itself did not.
|
|
69
|
+
const serializedChainMap = chainMap ? JSON.stringify(chainMap) : undefined;
|
|
70
|
+
const cachedTransform = babelFileCache.get(normalizedRequest);
|
|
71
|
+
if (cachedTransform !== undefined &&
|
|
72
|
+
cachedTransform.chainedMap === serializedChainMap) {
|
|
73
|
+
callback(null, cachedTransform.code, cachedTransform.map);
|
|
35
74
|
return;
|
|
36
75
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
76
|
+
// A mismatched entry means the chained map changed since the entry was
|
|
77
|
+
// produced. The transformer's persistent cache is keyed on the file
|
|
78
|
+
// bytes only, so `transformFile` would return the same stale output;
|
|
79
|
+
// hand it the current file data instead, which always runs the worker
|
|
80
|
+
// and re-reads the changed map file. A cold process has no entry to
|
|
81
|
+
// compare against, so a stale persistent entry can still be served
|
|
82
|
+
// there, matching the esbuild application builder's behavior.
|
|
83
|
+
const transformed = cachedTransform !== undefined
|
|
84
|
+
? (0, promises_1.readFile)(request, 'utf8').then((data) => javascriptTransformer.transformData(request, data, false, false))
|
|
85
|
+
: javascriptTransformer.transformFile(request, false, false);
|
|
86
|
+
transformed.then((contents) => {
|
|
87
|
+
const text = Buffer.from(contents).toString('utf8');
|
|
88
|
+
const { code, map: extractedMap, strippedComment, } = (0, inline_source_map_1.extractInlineSourceMap)(text);
|
|
89
|
+
// The transformer's output carries a trailing sourcemap comment only
|
|
90
|
+
// when sourcemaps apply to this file: its own inline map for
|
|
91
|
+
// transformed output, the file's original comment when passed
|
|
92
|
+
// through untouched. A stripped comment without a usable inline map
|
|
93
|
+
// references an external map file, which source-map-loader has
|
|
94
|
+
// already read, so chain its map. No comment at all means sourcemaps
|
|
95
|
+
// are off for this file and nothing must be forwarded.
|
|
96
|
+
const map = extractedMap ?? (strippedComment ? serializedChainMap : undefined);
|
|
97
|
+
babelFileCache.set(normalizedRequest, {
|
|
98
|
+
code,
|
|
99
|
+
map,
|
|
100
|
+
chainedMap: serializedChainMap,
|
|
101
|
+
});
|
|
102
|
+
callback(null, code, map);
|
|
41
103
|
}, (error) => {
|
|
42
104
|
// Fail the module instead of leaving the loader callback pending,
|
|
43
105
|
// which would hang the build.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-transform.loader.d.ts","sourceRoot":"","sources":["../../../../src/lib/plugins/loaders/angular-transform.loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"angular-transform.loader.d.ts","sourceRoot":"","sources":["../../../../src/lib/plugins/loaders/angular-transform.loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EAErB,MAAM,6BAA6B,CAAC;AAMrC,MAAM,CAAC,OAAO,UAAU,MAAM,CAC5B,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,EAC5B,OAAO,EAAE,MAAM,EACf,GAAG,CAAC,EAAE;IACJ,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,oBAAoB,EAAE,oBAAoB,CAAC;CAC5C,QAuFF"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = loader;
|
|
4
|
-
const path_1 = require("path");
|
|
5
4
|
const models_1 = require("../../models");
|
|
6
5
|
const angular_rspack_compiler_1 = require("@nx/angular-rspack-compiler");
|
|
6
|
+
const inline_source_map_1 = require("./inline-source-map");
|
|
7
7
|
const _styleUrlsResolver = new angular_rspack_compiler_1.StyleUrlsResolver();
|
|
8
8
|
const _templateUrlsResolver = new angular_rspack_compiler_1.TemplateUrlsResolver();
|
|
9
9
|
function loader(content, opt) {
|
|
@@ -14,7 +14,7 @@ function loader(content, opt) {
|
|
|
14
14
|
callback(null, content);
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
17
|
-
const { typescriptFileCache, angularCompilationFailed } = this._compilation[models_1.NG_RSPACK_SYMBOL_NAME]();
|
|
17
|
+
const { typescriptFileCache, javascriptTransformer, useTypeScriptTranspilation, angularCompilationFailed, resourceDependencies, } = this._compilation[models_1.NG_RSPACK_SYMBOL_NAME]();
|
|
18
18
|
if (angularCompilationFailed) {
|
|
19
19
|
// The Angular compilation failure is already reported as a compilation
|
|
20
20
|
// error. Emit empty modules instead of raw TS sources that would only
|
|
@@ -22,26 +22,55 @@ function loader(content, opt) {
|
|
|
22
22
|
callback(null, '');
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.addDependency(absoluteFileUrl);
|
|
35
|
-
}
|
|
36
|
-
const contents = typescriptFileCache.get(normalizedRequest);
|
|
37
|
-
if (contents === undefined) {
|
|
38
|
-
callback(null, content);
|
|
39
|
-
}
|
|
40
|
-
else if (typeof contents === 'string') {
|
|
41
|
-
callback(null, contents);
|
|
25
|
+
const normalizedRequest = (0, angular_rspack_compiler_1.toTypeScriptFileCacheKey)(this.resourcePath);
|
|
26
|
+
const resourceDeps = resourceDependencies?.get(normalizedRequest);
|
|
27
|
+
if (resourceDeps !== undefined) {
|
|
28
|
+
// The compiler tracked this file's template and stylesheet
|
|
29
|
+
// dependencies; registering them keeps the module rebuilding when a
|
|
30
|
+
// resource changes, at no parsing cost.
|
|
31
|
+
for (const dependency of resourceDeps) {
|
|
32
|
+
this.addDependency(dependency);
|
|
33
|
+
}
|
|
42
34
|
}
|
|
43
35
|
else {
|
|
44
|
-
|
|
36
|
+
const templateUrls = templateUrlsResolver.resolve(content, normalizedRequest);
|
|
37
|
+
const styleUrls = styleUrlsResolver.resolve(content, normalizedRequest);
|
|
38
|
+
for (const urlSet of [...templateUrls, ...styleUrls]) {
|
|
39
|
+
// `urlSet` is a string where a relative path is joined with an
|
|
40
|
+
// absolute path using the `|` symbol.
|
|
41
|
+
// For example: `./app.component.html|/home/projects/analog/src/app/app.component.html`.
|
|
42
|
+
const [, absoluteFileUrl] = urlSet.split('|');
|
|
43
|
+
this.addDependency(absoluteFileUrl);
|
|
44
|
+
}
|
|
45
45
|
}
|
|
46
|
+
const cached = typescriptFileCache.get(normalizedRequest);
|
|
47
|
+
if (cached !== undefined) {
|
|
48
|
+
if (typeof cached !== 'string') {
|
|
49
|
+
callback(null, cached.code, cached.map);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// A string entry is a raw emit from the Angular compilation. Without
|
|
53
|
+
// TypeScript transpilation it is Angular-transformed TypeScript that
|
|
54
|
+
// the bundler transpiles as-is, matching `@angular/build`.
|
|
55
|
+
if (!useTypeScriptTranspilation) {
|
|
56
|
+
callback(null, cached);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
javascriptTransformer
|
|
60
|
+
.transformData(normalizedRequest, cached, true, false)
|
|
61
|
+
.then((transformed) => {
|
|
62
|
+
const text = Buffer.from(transformed).toString();
|
|
63
|
+
const { code, map } = (0, inline_source_map_1.extractInlineSourceMap)(text);
|
|
64
|
+
// A newer emit may have replaced the entry while transforming;
|
|
65
|
+
// only store the result for the emit it was produced from.
|
|
66
|
+
if (typescriptFileCache.get(normalizedRequest) === cached) {
|
|
67
|
+
typescriptFileCache.set(normalizedRequest, { code, map });
|
|
68
|
+
}
|
|
69
|
+
callback(null, code, map);
|
|
70
|
+
})
|
|
71
|
+
.catch((err) => callback(err));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
callback(null, content);
|
|
46
75
|
}
|
|
47
76
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { RawSourceMap } from '@rspack/core';
|
|
2
|
+
export interface ExtractedSourceMap {
|
|
3
|
+
code: string;
|
|
4
|
+
/** The decoded sourcemap as a JSON string, when inline and usable. */
|
|
5
|
+
map: string | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Whether a trailing sourceMappingURL comment was stripped from the code,
|
|
8
|
+
* even when it yielded no usable map (an external file reference or a
|
|
9
|
+
* payload rspack would reject).
|
|
10
|
+
*/
|
|
11
|
+
strippedComment: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Splits a trailing sourcemap comment off the given code so the map can be
|
|
15
|
+
* passed to the loader callback and chained into the final sourcemaps,
|
|
16
|
+
* mirroring how the esbuild pipeline consumes the inline sourcemaps of the
|
|
17
|
+
* Angular compilation and the JavaScript transformer. Comments that carry no
|
|
18
|
+
* usable inline map are still stripped: esbuild never emits input
|
|
19
|
+
* sourceMappingURL comments into the bundle.
|
|
20
|
+
*/
|
|
21
|
+
export declare function extractInlineSourceMap(code: string): ExtractedSourceMap;
|
|
22
|
+
/**
|
|
23
|
+
* Whether rspack's sourcemap deserializer accepts this value as a
|
|
24
|
+
* loader-provided map. Rspack fails the module build on any map it cannot
|
|
25
|
+
* deserialize, even when sourcemaps are disabled, so externally authored maps
|
|
26
|
+
* (a package's own sourcemap) must pass this check before being handed to
|
|
27
|
+
* the loader callback. Mirrors rspack's deserialization rules: `mappings`
|
|
28
|
+
* must be a string; every other field is optional and may be null, but a
|
|
29
|
+
* present value must have the expected type, including array elements
|
|
30
|
+
* (`sources`, `names` and `sourcesContent` entries may be null; `ignoreList`
|
|
31
|
+
* entries are deserialized as unsigned 32-bit integers).
|
|
32
|
+
*/
|
|
33
|
+
export declare function isForwardableSourceMap(value: unknown): value is RawSourceMap;
|
|
34
|
+
//# sourceMappingURL=inline-source-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline-source-map.d.ts","sourceRoot":"","sources":["../../../../src/lib/plugins/loaders/inline-source-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAiBjD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAqBvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CA8B5E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractInlineSourceMap = extractInlineSourceMap;
|
|
4
|
+
exports.isForwardableSourceMap = isForwardableSourceMap;
|
|
5
|
+
// A `sourceMappingURL` value: an inline base64 data URI (captured) or any
|
|
6
|
+
// other reference, e.g. an external `.js.map` file.
|
|
7
|
+
const SOURCE_MAP_URL_SOURCE = 'sourceMappingURL=(?:data:application\\/json[^,]*;base64,([A-Za-z0-9+/=]+)|[^\\r\\n]*?)';
|
|
8
|
+
// Matches a trailing sourcemap comment in the forms source-map-loader
|
|
9
|
+
// consumes: `//#`, the legacy `//@`, and their single-line block variants
|
|
10
|
+
// `/*# ... */` and `/*@ ... */`. The leading `\r?\n` consumes the newline
|
|
11
|
+
// preceding the comment so no stray `\r` is left on the stripped code. The
|
|
12
|
+
// inline base64 payload lands in group 1 (line comment) or group 2 (block
|
|
13
|
+
// comment).
|
|
14
|
+
const TRAILING_SOURCE_MAP_COMMENT_REGEX = new RegExp(`(?:\\r?\\n)?(?:\\/\\/[#@][ \\t]+${SOURCE_MAP_URL_SOURCE}|\\/\\*[#@][ \\t]+${SOURCE_MAP_URL_SOURCE}[ \\t]*\\*\\/)\\s*$`);
|
|
15
|
+
/**
|
|
16
|
+
* Splits a trailing sourcemap comment off the given code so the map can be
|
|
17
|
+
* passed to the loader callback and chained into the final sourcemaps,
|
|
18
|
+
* mirroring how the esbuild pipeline consumes the inline sourcemaps of the
|
|
19
|
+
* Angular compilation and the JavaScript transformer. Comments that carry no
|
|
20
|
+
* usable inline map are still stripped: esbuild never emits input
|
|
21
|
+
* sourceMappingURL comments into the bundle.
|
|
22
|
+
*/
|
|
23
|
+
function extractInlineSourceMap(code) {
|
|
24
|
+
const match = code.match(TRAILING_SOURCE_MAP_COMMENT_REGEX);
|
|
25
|
+
if (match?.index === undefined) {
|
|
26
|
+
return { code, map: undefined, strippedComment: false };
|
|
27
|
+
}
|
|
28
|
+
const stripped = code.slice(0, match.index);
|
|
29
|
+
const inlinePayload = match[1] ?? match[2];
|
|
30
|
+
if (inlinePayload === undefined) {
|
|
31
|
+
// A reference to an external map file; there is nothing to decode.
|
|
32
|
+
return { code: stripped, map: undefined, strippedComment: true };
|
|
33
|
+
}
|
|
34
|
+
const map = Buffer.from(inlinePayload, 'base64').toString('utf8');
|
|
35
|
+
try {
|
|
36
|
+
if (!isForwardableSourceMap(JSON.parse(map))) {
|
|
37
|
+
return { code: stripped, map: undefined, strippedComment: true };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// A malformed map is unusable; still strip its comment from the code.
|
|
42
|
+
return { code: stripped, map: undefined, strippedComment: true };
|
|
43
|
+
}
|
|
44
|
+
return { code: stripped, map, strippedComment: true };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Whether rspack's sourcemap deserializer accepts this value as a
|
|
48
|
+
* loader-provided map. Rspack fails the module build on any map it cannot
|
|
49
|
+
* deserialize, even when sourcemaps are disabled, so externally authored maps
|
|
50
|
+
* (a package's own sourcemap) must pass this check before being handed to
|
|
51
|
+
* the loader callback. Mirrors rspack's deserialization rules: `mappings`
|
|
52
|
+
* must be a string; every other field is optional and may be null, but a
|
|
53
|
+
* present value must have the expected type, including array elements
|
|
54
|
+
* (`sources`, `names` and `sourcesContent` entries may be null; `ignoreList`
|
|
55
|
+
* entries are deserialized as unsigned 32-bit integers).
|
|
56
|
+
*/
|
|
57
|
+
function isForwardableSourceMap(value) {
|
|
58
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const map = value;
|
|
62
|
+
const isNullableString = (v) => v === null || typeof v === 'string';
|
|
63
|
+
const isOptional = (v, check) => v === undefined || v === null || check(v);
|
|
64
|
+
const isArrayOf = (v, check) => Array.isArray(v) && v.every(check);
|
|
65
|
+
return (typeof map.mappings === 'string' &&
|
|
66
|
+
isOptional(map.sources, (v) => isArrayOf(v, isNullableString)) &&
|
|
67
|
+
isOptional(map.names, (v) => isArrayOf(v, isNullableString)) &&
|
|
68
|
+
isOptional(map.sourcesContent, (v) => isArrayOf(v, isNullableString)) &&
|
|
69
|
+
isOptional(map.file, (v) => typeof v === 'string') &&
|
|
70
|
+
isOptional(map.sourceRoot, (v) => typeof v === 'string') &&
|
|
71
|
+
isOptional(map.debugId, (v) => typeof v === 'string') &&
|
|
72
|
+
isOptional(map.ignoreList, (v) => isArrayOf(v, (el) => typeof el === 'number' &&
|
|
73
|
+
Number.isInteger(el) &&
|
|
74
|
+
el >= 0 &&
|
|
75
|
+
el <= 0xffffffff)));
|
|
76
|
+
}
|
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
import { Compiler, RspackPluginInstance } from '@rspack/core';
|
|
2
2
|
import type { I18nOptions, NormalizedAngularRspackPluginOptions } from '../models';
|
|
3
|
+
import { AngularRspackPlugin } from './angular-rspack-plugin';
|
|
4
|
+
import { type SharedLicenseInputs } from './extract-licenses-plugin';
|
|
3
5
|
export declare class NgRspackPlugin implements RspackPluginInstance {
|
|
4
6
|
readonly pluginOptions: NormalizedAngularRspackPluginOptions;
|
|
5
7
|
readonly isPlatformServer: boolean;
|
|
6
8
|
readonly i18n: I18nOptions;
|
|
9
|
+
private readonly sharedLicenseInputs;
|
|
10
|
+
private readonly sharedAngularPlugin;
|
|
7
11
|
constructor(pluginOptions: NormalizedAngularRspackPluginOptions, extraOptions: {
|
|
8
12
|
platform: 'browser' | 'server';
|
|
9
13
|
i18nOptions: I18nOptions;
|
|
14
|
+
/**
|
|
15
|
+
* License extraction inputs shared across the compilers of an SSR
|
|
16
|
+
* build, so the browser and server compilers emit the union instead of
|
|
17
|
+
* overwriting each other's licenses file.
|
|
18
|
+
*/
|
|
19
|
+
sharedLicenseInputs?: SharedLicenseInputs;
|
|
20
|
+
/**
|
|
21
|
+
* Angular compilation shared across the compilers of an SSR build: the
|
|
22
|
+
* browser compiler owns it (its program includes the server entry
|
|
23
|
+
* points) and the server compiler consumes its output instead of
|
|
24
|
+
* running a second compilation. When absent, each compiler runs its
|
|
25
|
+
* own compilation.
|
|
26
|
+
*/
|
|
27
|
+
sharedAngularPlugin?: AngularRspackPlugin;
|
|
10
28
|
});
|
|
11
29
|
apply(compiler: Compiler): void;
|
|
12
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-rspack.d.ts","sourceRoot":"","sources":["../../../src/lib/plugins/ng-rspack.ts"],"names":[],"mappings":"AACA,OAAO,EACL,QAAQ,EAGR,oBAAoB,EACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EACV,WAAW,EACX,oCAAoC,EACrC,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ng-rspack.d.ts","sourceRoot":"","sources":["../../../src/lib/plugins/ng-rspack.ts"],"names":[],"mappings":"AACA,OAAO,EACL,QAAQ,EAGR,oBAAoB,EACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EACV,WAAW,EACX,oCAAoC,EACrC,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AAMnC,qBAAa,cAAe,YAAW,oBAAoB;IACzD,QAAQ,CAAC,aAAa,EAAE,oCAAoC,CAAC;IAC7D,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAkC;IACtE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAkC;IAEtE,YACE,aAAa,EAAE,oCAAoC,EACnD,YAAY,EAAE;QACZ,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAC;QAC/B,WAAW,EAAE,WAAW,CAAC;QACzB;;;;WAIG;QACH,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;QAC1C;;;;;;WAMG;QACH,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;KAC3C,EAOF;IAED,KAAK,CAAC,QAAQ,EAAE,QAAQ,QA2MvB;CACF"}
|