@angular/build 19.0.0-next.10 → 19.0.0-next.11
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 +13 -13
- package/src/builders/application/options.d.ts +3 -1
- package/src/builders/application/options.js +2 -1
- package/src/builders/application/results.d.ts +5 -3
- package/src/builders/application/schema.d.ts +57 -0
- package/src/builders/application/schema.js +19 -1
- package/src/builders/application/schema.json +33 -0
- package/src/builders/dev-server/vite-server.d.ts +1 -1
- package/src/builders/dev-server/vite-server.js +26 -7
- package/src/tools/angular/angular-host.d.ts +1 -1
- package/src/tools/angular/angular-host.js +1 -4
- package/src/tools/angular/compilation/parallel-compilation.js +2 -2
- package/src/tools/angular/compilation/parallel-worker.js +3 -1
- package/src/tools/esbuild/angular/compiler-plugin.js +27 -8
- package/src/tools/esbuild/angular/component-stylesheets.d.ts +3 -2
- package/src/tools/esbuild/angular/component-stylesheets.js +4 -2
- package/src/tools/esbuild/angular/jit-plugin-callbacks.d.ts +1 -1
- package/src/tools/esbuild/angular/jit-plugin-callbacks.js +2 -2
- package/src/tools/esbuild/application-code-bundle.js +46 -25
- package/src/tools/esbuild/bundler-context.js +7 -10
- package/src/tools/esbuild/compiler-plugin-options.js +3 -0
- package/src/tools/esbuild/global-scripts.js +1 -1
- package/src/tools/esbuild/global-styles.js +3 -0
- package/src/tools/esbuild/server-bundle-metadata-plugin.d.ts +22 -0
- package/src/tools/esbuild/server-bundle-metadata-plugin.js +36 -0
- package/src/tools/esbuild/stylesheets/bundle-options.d.ts +2 -0
- package/src/tools/esbuild/stylesheets/bundle-options.js +2 -1
- package/src/tools/esbuild/stylesheets/sass-language.js +4 -0
- package/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.d.ts +9 -0
- package/src/tools/esbuild/utils.js +12 -1
- package/src/tools/sass/worker.js +19 -0
- package/src/tools/vite/middlewares/assets-middleware.d.ts +1 -1
- package/src/tools/vite/middlewares/assets-middleware.js +2 -2
- package/src/tools/vite/middlewares/component-middleware.d.ts +9 -0
- package/src/tools/vite/middlewares/component-middleware.js +33 -0
- package/src/tools/vite/middlewares/index.d.ts +1 -0
- package/src/tools/vite/middlewares/index.js +3 -1
- package/src/tools/vite/middlewares/ssr-middleware.js +6 -6
- package/src/tools/vite/plugins/setup-middlewares-plugin.d.ts +2 -1
- package/src/tools/vite/plugins/setup-middlewares-plugin.js +2 -1
- package/src/utils/environment-options.js +1 -1
- package/src/utils/normalize-cache.js +1 -1
- package/src/utils/server-rendering/launch-server.js +5 -5
- package/src/utils/server-rendering/load-esm-from-memory.d.ts +1 -1
- package/src/utils/supported-browsers.js +1 -0
|
@@ -18,6 +18,7 @@ exports.createSsrEntryCodeBundleOptions = createSsrEntryCodeBundleOptions;
|
|
|
18
18
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
19
19
|
const node_crypto_1 = require("node:crypto");
|
|
20
20
|
const node_path_1 = require("node:path");
|
|
21
|
+
const schema_1 = require("../../builders/application/schema");
|
|
21
22
|
const environment_options_1 = require("../../utils/environment-options");
|
|
22
23
|
const manifest_1 = require("../../utils/server-rendering/manifest");
|
|
23
24
|
const compiler_plugin_1 = require("./angular/compiler-plugin");
|
|
@@ -26,6 +27,7 @@ const external_packages_plugin_1 = require("./external-packages-plugin");
|
|
|
26
27
|
const i18n_locale_plugin_1 = require("./i18n-locale-plugin");
|
|
27
28
|
const loader_import_attribute_plugin_1 = require("./loader-import-attribute-plugin");
|
|
28
29
|
const rxjs_esm_resolution_plugin_1 = require("./rxjs-esm-resolution-plugin");
|
|
30
|
+
const server_bundle_metadata_plugin_1 = require("./server-bundle-metadata-plugin");
|
|
29
31
|
const sourcemap_ignorelist_plugin_1 = require("./sourcemap-ignorelist-plugin");
|
|
30
32
|
const utils_1 = require("./utils");
|
|
31
33
|
const virtual_module_plugin_1 = require("./virtual-module-plugin");
|
|
@@ -115,8 +117,9 @@ function createBrowserPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
115
117
|
function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
116
118
|
const serverPolyfills = [];
|
|
117
119
|
const polyfillsFromConfig = new Set(options.polyfills);
|
|
120
|
+
const isNodePlatform = options.ssrOptions?.platform !== schema_1.ExperimentalPlatform.Neutral;
|
|
118
121
|
if (!(0, utils_1.isZonelessApp)(options.polyfills)) {
|
|
119
|
-
serverPolyfills.push('zone.js/node');
|
|
122
|
+
serverPolyfills.push(isNodePlatform ? 'zone.js/node' : 'zone.js');
|
|
120
123
|
}
|
|
121
124
|
if (polyfillsFromConfig.has('@angular/localize') ||
|
|
122
125
|
polyfillsFromConfig.has('@angular/localize/init')) {
|
|
@@ -133,7 +136,7 @@ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
133
136
|
}
|
|
134
137
|
const buildOptions = {
|
|
135
138
|
...polyfillBundleOptions,
|
|
136
|
-
platform: 'node',
|
|
139
|
+
platform: isNodePlatform ? 'node' : 'neutral',
|
|
137
140
|
outExtension: { '.js': '.mjs' },
|
|
138
141
|
// Note: `es2015` is needed for RxJS v6. If not specified, `module` would
|
|
139
142
|
// match and the ES5 distribution would be bundled and ends up breaking at
|
|
@@ -141,19 +144,23 @@ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
|
|
|
141
144
|
// More details: https://github.com/angular/angular-cli/issues/25405.
|
|
142
145
|
mainFields: ['es2020', 'es2015', 'module', 'main'],
|
|
143
146
|
entryNames: '[name]',
|
|
144
|
-
banner:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
147
|
+
banner: isNodePlatform
|
|
148
|
+
? {
|
|
149
|
+
js: [
|
|
150
|
+
// Note: Needed as esbuild does not provide require shims / proxy from ESModules.
|
|
151
|
+
// See: https://github.com/evanw/esbuild/issues/1921.
|
|
152
|
+
`import { createRequire } from 'node:module';`,
|
|
153
|
+
`globalThis['require'] ??= createRequire(import.meta.url);`,
|
|
154
|
+
].join('\n'),
|
|
155
|
+
}
|
|
156
|
+
: undefined,
|
|
152
157
|
target,
|
|
153
158
|
entryPoints: {
|
|
154
159
|
'polyfills.server': namespace,
|
|
155
160
|
},
|
|
156
161
|
};
|
|
162
|
+
buildOptions.plugins ??= [];
|
|
163
|
+
buildOptions.plugins.push((0, server_bundle_metadata_plugin_1.createServerBundleMetadata)());
|
|
157
164
|
return () => buildOptions;
|
|
158
165
|
}
|
|
159
166
|
function createServerMainCodeBundleOptions(options, target, sourceFileCache) {
|
|
@@ -199,7 +206,14 @@ function createServerMainCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
199
206
|
}
|
|
200
207
|
// Mark manifest and polyfills file as external as these are generated by a different bundle step.
|
|
201
208
|
(buildOptions.external ??= []).push(...utils_1.SERVER_GENERATED_EXTERNALS);
|
|
202
|
-
|
|
209
|
+
const isNodePlatform = options.ssrOptions?.platform !== schema_1.ExperimentalPlatform.Neutral;
|
|
210
|
+
if (!isNodePlatform) {
|
|
211
|
+
// `@angular/platform-server` lazily depends on `xhr2` for XHR usage with the HTTP client.
|
|
212
|
+
// Since `xhr2` has Node.js dependencies, it cannot be used when targeting non-Node.js platforms.
|
|
213
|
+
// Note: The framework already issues a warning when using XHR with SSR.
|
|
214
|
+
buildOptions.external.push('xhr2');
|
|
215
|
+
}
|
|
216
|
+
buildOptions.plugins.push((0, server_bundle_metadata_plugin_1.createServerBundleMetadata)(), (0, virtual_module_plugin_1.createVirtualModulePlugin)({
|
|
203
217
|
namespace: mainServerInjectPolyfillsNamespace,
|
|
204
218
|
cache: sourceFileCache?.loadResultCache,
|
|
205
219
|
loadContent: () => ({
|
|
@@ -259,6 +273,11 @@ function createSsrEntryCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
259
273
|
const ssrEntryNamespace = 'angular:ssr-entry';
|
|
260
274
|
const ssrInjectManifestNamespace = 'angular:ssr-entry-inject-manifest';
|
|
261
275
|
const ssrInjectRequireNamespace = 'angular:ssr-entry-inject-require';
|
|
276
|
+
const isNodePlatform = options.ssrOptions?.platform !== schema_1.ExperimentalPlatform.Neutral;
|
|
277
|
+
const inject = [ssrInjectManifestNamespace];
|
|
278
|
+
if (isNodePlatform) {
|
|
279
|
+
inject.unshift(ssrInjectRequireNamespace);
|
|
280
|
+
}
|
|
262
281
|
const buildOptions = {
|
|
263
282
|
...getEsBuildServerCommonOptions(options),
|
|
264
283
|
target,
|
|
@@ -275,7 +294,7 @@ function createSsrEntryCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
275
294
|
// Component stylesheet options
|
|
276
295
|
styleOptions),
|
|
277
296
|
],
|
|
278
|
-
inject
|
|
297
|
+
inject,
|
|
279
298
|
};
|
|
280
299
|
buildOptions.plugins ??= [];
|
|
281
300
|
if (externalPackages) {
|
|
@@ -286,17 +305,13 @@ function createSsrEntryCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
286
305
|
}
|
|
287
306
|
// Mark manifest file as external. As this will be generated later on.
|
|
288
307
|
(buildOptions.external ??= []).push('*/main.server.mjs', ...utils_1.SERVER_GENERATED_EXTERNALS);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
},
|
|
299
|
-
}, (0, virtual_module_plugin_1.createVirtualModulePlugin)({
|
|
308
|
+
if (!isNodePlatform) {
|
|
309
|
+
// `@angular/platform-server` lazily depends on `xhr2` for XHR usage with the HTTP client.
|
|
310
|
+
// Since `xhr2` has Node.js dependencies, it cannot be used when targeting non-Node.js platforms.
|
|
311
|
+
// Note: The framework already issues a warning when using XHR with SSR.
|
|
312
|
+
buildOptions.external.push('xhr2');
|
|
313
|
+
}
|
|
314
|
+
buildOptions.plugins.push((0, server_bundle_metadata_plugin_1.createServerBundleMetadata)({ ssrEntryBundle: true }), (0, virtual_module_plugin_1.createVirtualModulePlugin)({
|
|
300
315
|
namespace: ssrInjectRequireNamespace,
|
|
301
316
|
cache: sourceFileCache?.loadResultCache,
|
|
302
317
|
loadContent: () => {
|
|
@@ -357,9 +372,10 @@ function createSsrEntryCodeBundleOptions(options, target, sourceFileCache) {
|
|
|
357
372
|
return buildOptions;
|
|
358
373
|
}
|
|
359
374
|
function getEsBuildServerCommonOptions(options) {
|
|
375
|
+
const isNodePlatform = options.ssrOptions?.platform !== schema_1.ExperimentalPlatform.Neutral;
|
|
360
376
|
return {
|
|
361
377
|
...getEsBuildCommonOptions(options),
|
|
362
|
-
platform: 'node',
|
|
378
|
+
platform: isNodePlatform ? 'node' : 'neutral',
|
|
363
379
|
outExtension: { '.js': '.mjs' },
|
|
364
380
|
// Note: `es2015` is needed for RxJS v6. If not specified, `module` would
|
|
365
381
|
// match and the ES5 distribution would be bundled and ends up breaking at
|
|
@@ -387,7 +403,12 @@ function getEsBuildCommonOptions(options) {
|
|
|
387
403
|
bundle: true,
|
|
388
404
|
packages: 'bundle',
|
|
389
405
|
assetNames: outputNames.media,
|
|
390
|
-
conditions: [
|
|
406
|
+
conditions: [
|
|
407
|
+
'es2020',
|
|
408
|
+
'es2015',
|
|
409
|
+
'module',
|
|
410
|
+
optimizationOptions.scripts ? 'production' : 'development',
|
|
411
|
+
],
|
|
391
412
|
resolveExtensions: ['.ts', '.tsx', '.mjs', '.js', '.cjs'],
|
|
392
413
|
metafile: true,
|
|
393
414
|
legalComments: options.extractLicenses ? 'none' : 'eof',
|
|
@@ -211,6 +211,7 @@ class BundlerContext {
|
|
|
211
211
|
warnings: result.warnings,
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
|
+
const { 'ng-platform-server': isPlatformServer = false, 'ng-ssr-entry-bundle': isSsrEntryBundle = false, } = result.metafile;
|
|
214
215
|
// Find all initial files
|
|
215
216
|
const initialFiles = new Map();
|
|
216
217
|
for (const outputFile of result.outputFiles) {
|
|
@@ -231,7 +232,7 @@ class BundlerContext {
|
|
|
231
232
|
name,
|
|
232
233
|
type,
|
|
233
234
|
entrypoint: true,
|
|
234
|
-
serverFile:
|
|
235
|
+
serverFile: isPlatformServer,
|
|
235
236
|
depth: 0,
|
|
236
237
|
};
|
|
237
238
|
if (!this.initialFilter || this.initialFilter(record)) {
|
|
@@ -259,7 +260,7 @@ class BundlerContext {
|
|
|
259
260
|
type: initialImport.kind === 'import-rule' ? 'style' : 'script',
|
|
260
261
|
entrypoint: false,
|
|
261
262
|
external: initialImport.external,
|
|
262
|
-
serverFile:
|
|
263
|
+
serverFile: isPlatformServer,
|
|
263
264
|
depth: entryRecord.depth + 1,
|
|
264
265
|
};
|
|
265
266
|
if (!this.initialFilter || this.initialFilter(record)) {
|
|
@@ -292,9 +293,8 @@ class BundlerContext {
|
|
|
292
293
|
if (!/\.([cm]?js|css|wasm)(\.map)?$/i.test(file.path)) {
|
|
293
294
|
fileType = BuildOutputFileType.Media;
|
|
294
295
|
}
|
|
295
|
-
else if (
|
|
296
|
-
|
|
297
|
-
fileType = result.metafile['ng-ssr-entry-bundle']
|
|
296
|
+
else if (isPlatformServer) {
|
|
297
|
+
fileType = isSsrEntryBundle
|
|
298
298
|
? BuildOutputFileType.ServerRoot
|
|
299
299
|
: BuildOutputFileType.ServerApplication;
|
|
300
300
|
}
|
|
@@ -304,7 +304,7 @@ class BundlerContext {
|
|
|
304
304
|
return (0, utils_1.convertOutputFile)(file, fileType);
|
|
305
305
|
});
|
|
306
306
|
let externalConfiguration = this.#esbuildOptions.external;
|
|
307
|
-
if (
|
|
307
|
+
if (isPlatformServer && externalConfiguration) {
|
|
308
308
|
externalConfiguration = externalConfiguration.filter((dep) => !utils_1.SERVER_GENERATED_EXTERNALS.has(dep));
|
|
309
309
|
if (!externalConfiguration.length) {
|
|
310
310
|
externalConfiguration = undefined;
|
|
@@ -316,7 +316,7 @@ class BundlerContext {
|
|
|
316
316
|
outputFiles,
|
|
317
317
|
initialFiles,
|
|
318
318
|
externalImports: {
|
|
319
|
-
[
|
|
319
|
+
[isPlatformServer ? 'server' : 'browser']: externalImports,
|
|
320
320
|
},
|
|
321
321
|
externalConfiguration,
|
|
322
322
|
errors: undefined,
|
|
@@ -336,9 +336,6 @@ class BundlerContext {
|
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
|
-
get #platformIsServer() {
|
|
340
|
-
return this.#esbuildOptions?.platform === 'node';
|
|
341
|
-
}
|
|
342
339
|
/**
|
|
343
340
|
* Invalidate a stored bundler result based on the previous watch files
|
|
344
341
|
* and a list of changed files.
|
|
@@ -37,6 +37,9 @@ function createCompilerPluginOptions(options, target, sourceFileCache) {
|
|
|
37
37
|
sourcemapOptions.styles && !sourcemapOptions.hidden ? 'linked' : false,
|
|
38
38
|
outputNames,
|
|
39
39
|
includePaths: stylePreprocessorOptions?.includePaths,
|
|
40
|
+
// string[] | undefined' is not assignable to type '(Version | DeprecationOrId)[] | undefined'.
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
sass: stylePreprocessorOptions?.sass,
|
|
40
43
|
externalDependencies,
|
|
41
44
|
target,
|
|
42
45
|
inlineStyleLanguage,
|
|
@@ -72,7 +72,7 @@ function createGlobalScriptsBundleOptions(options, target, initial) {
|
|
|
72
72
|
entryNames: initial ? outputNames.bundles : '[name]',
|
|
73
73
|
assetNames: outputNames.media,
|
|
74
74
|
mainFields: ['script', 'browser', 'main'],
|
|
75
|
-
conditions: ['script'],
|
|
75
|
+
conditions: ['script', optimizationOptions.scripts ? 'production' : 'development'],
|
|
76
76
|
resolveExtensions: ['.mjs', '.js', '.cjs'],
|
|
77
77
|
logLevel: options.verbose && !jsonLogs ? 'debug' : 'silent',
|
|
78
78
|
metafile: true,
|
|
@@ -45,6 +45,9 @@ function createGlobalStylesBundleOptions(options, target, initial) {
|
|
|
45
45
|
bundles: '[name]',
|
|
46
46
|
},
|
|
47
47
|
includePaths: stylePreprocessorOptions?.includePaths,
|
|
48
|
+
// string[] | undefined' is not assignable to type '(Version | DeprecationOrId)[] | undefined'.
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
sass: stylePreprocessorOptions?.sass,
|
|
48
51
|
tailwindConfiguration,
|
|
49
52
|
postcssConfiguration,
|
|
50
53
|
cacheOptions,
|
|
@@ -0,0 +1,22 @@
|
|
|
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.dev/license
|
|
7
|
+
*/
|
|
8
|
+
import type { Plugin } from 'esbuild';
|
|
9
|
+
/**
|
|
10
|
+
* Generates an esbuild plugin that appends metadata to the output bundle,
|
|
11
|
+
* marking it with server-side rendering (SSR) details for Angular SSR scenarios.
|
|
12
|
+
*
|
|
13
|
+
* @param options Optional configuration object.
|
|
14
|
+
* - `ssrEntryBundle`: If `true`, marks the bundle as an SSR entry point.
|
|
15
|
+
*
|
|
16
|
+
* @note We can't rely on `platform: node` or `platform: neutral`, as the latter
|
|
17
|
+
* is used for non-SSR-related code too (e.g., global scripts).
|
|
18
|
+
* @returns An esbuild plugin that injects SSR metadata into the build result's metafile.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createServerBundleMetadata(options?: {
|
|
21
|
+
ssrEntryBundle?: boolean;
|
|
22
|
+
}): Plugin;
|
|
@@ -0,0 +1,36 @@
|
|
|
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.createServerBundleMetadata = createServerBundleMetadata;
|
|
11
|
+
/**
|
|
12
|
+
* Generates an esbuild plugin that appends metadata to the output bundle,
|
|
13
|
+
* marking it with server-side rendering (SSR) details for Angular SSR scenarios.
|
|
14
|
+
*
|
|
15
|
+
* @param options Optional configuration object.
|
|
16
|
+
* - `ssrEntryBundle`: If `true`, marks the bundle as an SSR entry point.
|
|
17
|
+
*
|
|
18
|
+
* @note We can't rely on `platform: node` or `platform: neutral`, as the latter
|
|
19
|
+
* is used for non-SSR-related code too (e.g., global scripts).
|
|
20
|
+
* @returns An esbuild plugin that injects SSR metadata into the build result's metafile.
|
|
21
|
+
*/
|
|
22
|
+
function createServerBundleMetadata(options) {
|
|
23
|
+
return {
|
|
24
|
+
name: 'angular-server-bundle-metadata',
|
|
25
|
+
setup(build) {
|
|
26
|
+
build.onEnd((result) => {
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
+
const metafile = result.metafile;
|
|
29
|
+
if (metafile) {
|
|
30
|
+
metafile['ng-ssr-entry-bundle'] = !!options?.ssrEntryBundle;
|
|
31
|
+
metafile['ng-platform-server'] = true;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -9,6 +9,7 @@ import type { BuildOptions } from 'esbuild';
|
|
|
9
9
|
import { NormalizedCachedOptions } from '../../../utils/normalize-cache';
|
|
10
10
|
import { PostcssConfiguration } from '../../../utils/postcss-configuration';
|
|
11
11
|
import { LoadResultCache } from '../load-result-cache';
|
|
12
|
+
import { StylesheetPluginsass } from './stylesheet-plugin-factory';
|
|
12
13
|
export interface BundleStylesheetOptions {
|
|
13
14
|
workspaceRoot: string;
|
|
14
15
|
optimization: boolean;
|
|
@@ -20,6 +21,7 @@ export interface BundleStylesheetOptions {
|
|
|
20
21
|
media: string;
|
|
21
22
|
};
|
|
22
23
|
includePaths?: string[];
|
|
24
|
+
sass?: StylesheetPluginsass;
|
|
23
25
|
externalDependencies?: string[];
|
|
24
26
|
target: string[];
|
|
25
27
|
tailwindConfiguration?: {
|
|
@@ -27,6 +27,7 @@ function createStylesheetBundleOptions(options, cache, inlineComponentData) {
|
|
|
27
27
|
inlineComponentData,
|
|
28
28
|
tailwindConfiguration: options.tailwindConfiguration,
|
|
29
29
|
postcssConfiguration: options.postcssConfiguration,
|
|
30
|
+
sass: options.sass,
|
|
30
31
|
}, cache);
|
|
31
32
|
const plugins = [
|
|
32
33
|
pluginFactory.create(sass_language_1.SassStylesheetLanguage),
|
|
@@ -53,7 +54,7 @@ function createStylesheetBundleOptions(options, cache, inlineComponentData) {
|
|
|
53
54
|
preserveSymlinks: options.preserveSymlinks,
|
|
54
55
|
external: options.externalDependencies,
|
|
55
56
|
publicPath: options.publicPath,
|
|
56
|
-
conditions: ['style', 'sass', 'less'],
|
|
57
|
+
conditions: ['style', 'sass', 'less', options.optimization ? 'production' : 'development'],
|
|
57
58
|
mainFields: ['style', 'sass'],
|
|
58
59
|
// Unlike JS, CSS does not have implicit file extensions in the general case.
|
|
59
60
|
// Preprocessor specific behavior is handled in each stylesheet language plugin.
|
|
@@ -99,6 +99,7 @@ async function compileString(data, filePath, syntax, options, resolveUrl) {
|
|
|
99
99
|
const resolutionCache = new cache_1.MemoryCache();
|
|
100
100
|
const packageRootCache = new cache_1.MemoryCache();
|
|
101
101
|
const warnings = [];
|
|
102
|
+
const { silenceDeprecations, futureDeprecations, fatalDeprecations } = options.sass ?? {};
|
|
102
103
|
try {
|
|
103
104
|
const { css, sourceMap, loadedUrls } = await sassWorkerPool.compileStringAsync(data, {
|
|
104
105
|
url: (0, node_url_1.pathToFileURL)(filePath),
|
|
@@ -107,6 +108,9 @@ async function compileString(data, filePath, syntax, options, resolveUrl) {
|
|
|
107
108
|
loadPaths: options.includePaths,
|
|
108
109
|
sourceMap: options.sourcemap,
|
|
109
110
|
sourceMapIncludeSources: options.sourcemap,
|
|
111
|
+
silenceDeprecations,
|
|
112
|
+
fatalDeprecations,
|
|
113
|
+
futureDeprecations,
|
|
110
114
|
quietDeps: true,
|
|
111
115
|
importers: [
|
|
112
116
|
{
|
|
@@ -6,8 +6,13 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
8
|
import type { OnLoadResult, Plugin, PluginBuild } from 'esbuild';
|
|
9
|
+
import type { Options } from 'sass';
|
|
9
10
|
import type { PostcssConfiguration } from '../../../utils/postcss-configuration';
|
|
10
11
|
import { LoadResultCache } from '../load-result-cache';
|
|
12
|
+
/**
|
|
13
|
+
* Configuration options for handling Sass-specific deprecations in a stylesheet plugin.
|
|
14
|
+
*/
|
|
15
|
+
export type StylesheetPluginsass = Pick<Options<'async'>, 'futureDeprecations' | 'fatalDeprecations' | 'silenceDeprecations'>;
|
|
11
16
|
/**
|
|
12
17
|
* An object containing the plugin options to use when processing stylesheets.
|
|
13
18
|
*/
|
|
@@ -42,6 +47,10 @@ export interface StylesheetPluginOptions {
|
|
|
42
47
|
* and any tailwind usage must be manually configured in the custom postcss usage.
|
|
43
48
|
*/
|
|
44
49
|
postcssConfiguration?: PostcssConfiguration;
|
|
50
|
+
/**
|
|
51
|
+
* Optional Options for configuring Sass behavior.
|
|
52
|
+
*/
|
|
53
|
+
sass?: StylesheetPluginsass;
|
|
45
54
|
}
|
|
46
55
|
export interface StylesheetLanguage {
|
|
47
56
|
name: string;
|
|
@@ -38,6 +38,7 @@ function logBuildStats(metafile, outputFiles, initial, budgetFailures, colors, c
|
|
|
38
38
|
const browserStats = [];
|
|
39
39
|
const serverStats = [];
|
|
40
40
|
let unchangedCount = 0;
|
|
41
|
+
let componentStyleChange = false;
|
|
41
42
|
for (const { path: file, size, type } of outputFiles) {
|
|
42
43
|
// Only display JavaScript and CSS files
|
|
43
44
|
if (!/\.(?:css|m?js)$/.test(file)) {
|
|
@@ -53,6 +54,11 @@ function logBuildStats(metafile, outputFiles, initial, budgetFailures, colors, c
|
|
|
53
54
|
// Only log server build stats when SSR is enabled.
|
|
54
55
|
continue;
|
|
55
56
|
}
|
|
57
|
+
// Skip logging external component stylesheets used for HMR
|
|
58
|
+
if (metafile.outputs[file] && 'ng-component' in metafile.outputs[file]) {
|
|
59
|
+
componentStyleChange = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
56
62
|
const name = initial.get(file)?.name ?? getChunkNameFromMetafile(metafile, file);
|
|
57
63
|
const stat = {
|
|
58
64
|
initial: initial.has(file),
|
|
@@ -70,7 +76,12 @@ function logBuildStats(metafile, outputFiles, initial, budgetFailures, colors, c
|
|
|
70
76
|
return tableText + '\n';
|
|
71
77
|
}
|
|
72
78
|
else if (changedFiles !== undefined) {
|
|
73
|
-
|
|
79
|
+
if (componentStyleChange) {
|
|
80
|
+
return '\nComponent stylesheet(s) changed.\n';
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
return '\nNo output file changes.\n';
|
|
84
|
+
}
|
|
74
85
|
}
|
|
75
86
|
if (unchangedCount > 0) {
|
|
76
87
|
return `Unchanged output files: ${unchangedCount}`;
|
package/src/tools/sass/worker.js
CHANGED
|
@@ -40,6 +40,25 @@ async function renderSassStylesheet(request) {
|
|
|
40
40
|
containingUrl: containingUrl ? (0, node_url_1.fileURLToPath)(containingUrl) : null,
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
|
+
// Wait for the main thread to set the signal to 1 and notify, which tells
|
|
44
|
+
// us that a message can be received on the port.
|
|
45
|
+
// If the main thread is fast, the signal will already be set to 1, and no
|
|
46
|
+
// sleep/notify is necessary.
|
|
47
|
+
// However, there can be a race condition here:
|
|
48
|
+
// - the main thread sets the signal to 1, but does not get to the notify instruction yet
|
|
49
|
+
// - the worker does not pause because the signal is set to 1
|
|
50
|
+
// - the worker very soon enters this method again
|
|
51
|
+
// - this method sets the signal to 0 and sends the message
|
|
52
|
+
// - the signal is 0 and so the `Atomics.wait` call blocks
|
|
53
|
+
// - only now the main thread runs the `notify` from the first invocation, so the
|
|
54
|
+
// worker continues.
|
|
55
|
+
// - but there is no message yet in the port, because the thread should not have been
|
|
56
|
+
// waken up yet.
|
|
57
|
+
// To combat this, wait for a non-0 value _twice_.
|
|
58
|
+
// Almost every time, this immediately continues with "not-equal", because
|
|
59
|
+
// the signal is still set to 1, except during the race condition, when the second
|
|
60
|
+
// wait will wait for the correct notify.
|
|
61
|
+
Atomics.wait(importerChannel.signal, 0, 0);
|
|
43
62
|
Atomics.wait(importerChannel.signal, 0, 0);
|
|
44
63
|
const result = (0, node_worker_threads_1.receiveMessageOnPort)(importerChannel.port)?.message;
|
|
45
64
|
return result ? (0, node_url_1.pathToFileURL)(result) : null;
|
|
@@ -7,4 +7,4 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Connect, ViteDevServer } from 'vite';
|
|
9
9
|
import { AngularMemoryOutputFiles } from '../utils';
|
|
10
|
-
export declare function createAngularAssetsMiddleware(server: ViteDevServer, assets: Map<string, string>, outputFiles: AngularMemoryOutputFiles, usedComponentStyles: Map<string, string
|
|
10
|
+
export declare function createAngularAssetsMiddleware(server: ViteDevServer, assets: Map<string, string>, outputFiles: AngularMemoryOutputFiles, usedComponentStyles: Map<string, Set<string>>): Connect.NextHandleFunction;
|
|
@@ -67,10 +67,10 @@ function createAngularAssetsMiddleware(server, assets, outputFiles, usedComponen
|
|
|
67
67
|
// Record the component style usage for HMR updates
|
|
68
68
|
const usedIds = usedComponentStyles.get(pathname);
|
|
69
69
|
if (usedIds === undefined) {
|
|
70
|
-
usedComponentStyles.set(pathname, [componentId]);
|
|
70
|
+
usedComponentStyles.set(pathname, new Set([componentId]));
|
|
71
71
|
}
|
|
72
72
|
else {
|
|
73
|
-
usedIds.
|
|
73
|
+
usedIds.add(componentId);
|
|
74
74
|
}
|
|
75
75
|
// Shim the stylesheet if a component ID is provided
|
|
76
76
|
if (componentId.length > 0) {
|
|
@@ -0,0 +1,9 @@
|
|
|
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.dev/license
|
|
7
|
+
*/
|
|
8
|
+
import type { Connect } from 'vite';
|
|
9
|
+
export declare function createAngularComponentMiddleware(templateUpdates: ReadonlyMap<string, string>): Connect.NextHandleFunction;
|
|
@@ -0,0 +1,33 @@
|
|
|
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.createAngularComponentMiddleware = createAngularComponentMiddleware;
|
|
11
|
+
const ANGULAR_COMPONENT_PREFIX = '/@ng/component';
|
|
12
|
+
function createAngularComponentMiddleware(templateUpdates) {
|
|
13
|
+
return function angularComponentMiddleware(req, res, next) {
|
|
14
|
+
if (req.url === undefined || res.writableEnded) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (!req.url.startsWith(ANGULAR_COMPONENT_PREFIX)) {
|
|
18
|
+
next();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const requestUrl = new URL(req.url, 'http://localhost');
|
|
22
|
+
const componentId = requestUrl.searchParams.get('c');
|
|
23
|
+
if (!componentId) {
|
|
24
|
+
res.statusCode = 400;
|
|
25
|
+
res.end();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const updateCode = templateUpdates.get(componentId) ?? '';
|
|
29
|
+
res.setHeader('Content-Type', 'text/javascript');
|
|
30
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
31
|
+
res.end(updateCode);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -10,3 +10,4 @@ export { angularHtmlFallbackMiddleware } from './html-fallback-middleware';
|
|
|
10
10
|
export { createAngularIndexHtmlMiddleware } from './index-html-middleware';
|
|
11
11
|
export { createAngularSsrExternalMiddleware, createAngularSsrInternalMiddleware, } from './ssr-middleware';
|
|
12
12
|
export { createAngularHeadersMiddleware } from './headers-middleware';
|
|
13
|
+
export { createAngularComponentMiddleware } from './component-middleware';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* found in the LICENSE file at https://angular.dev/license
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.createAngularHeadersMiddleware = exports.createAngularSsrInternalMiddleware = exports.createAngularSsrExternalMiddleware = exports.createAngularIndexHtmlMiddleware = exports.angularHtmlFallbackMiddleware = exports.createAngularAssetsMiddleware = void 0;
|
|
10
|
+
exports.createAngularComponentMiddleware = exports.createAngularHeadersMiddleware = exports.createAngularSsrInternalMiddleware = exports.createAngularSsrExternalMiddleware = exports.createAngularIndexHtmlMiddleware = exports.angularHtmlFallbackMiddleware = exports.createAngularAssetsMiddleware = void 0;
|
|
11
11
|
var assets_middleware_1 = require("./assets-middleware");
|
|
12
12
|
Object.defineProperty(exports, "createAngularAssetsMiddleware", { enumerable: true, get: function () { return assets_middleware_1.createAngularAssetsMiddleware; } });
|
|
13
13
|
var html_fallback_middleware_1 = require("./html-fallback-middleware");
|
|
@@ -19,3 +19,5 @@ Object.defineProperty(exports, "createAngularSsrExternalMiddleware", { enumerabl
|
|
|
19
19
|
Object.defineProperty(exports, "createAngularSsrInternalMiddleware", { enumerable: true, get: function () { return ssr_middleware_1.createAngularSsrInternalMiddleware; } });
|
|
20
20
|
var headers_middleware_1 = require("./headers-middleware");
|
|
21
21
|
Object.defineProperty(exports, "createAngularHeadersMiddleware", { enumerable: true, get: function () { return headers_middleware_1.createAngularHeadersMiddleware; } });
|
|
22
|
+
var component_middleware_1 = require("./component-middleware");
|
|
23
|
+
Object.defineProperty(exports, "createAngularComponentMiddleware", { enumerable: true, get: function () { return component_middleware_1.createAngularComponentMiddleware; } });
|
|
@@ -53,11 +53,11 @@ async function createAngularSsrExternalMiddleware(server, indexHtmlTransformer)
|
|
|
53
53
|
const { createWebRequestFromNodeRequest, writeResponseToNodeResponse } = await (0, load_esm_1.loadEsmModule)('@angular/ssr/node');
|
|
54
54
|
return function angularSsrExternalMiddleware(req, res, next) {
|
|
55
55
|
(async () => {
|
|
56
|
-
const {
|
|
57
|
-
if (!(0, utils_1.isSsrNodeRequestHandler)(
|
|
56
|
+
const { reqHandler, AngularAppEngine } = (await server.ssrLoadModule('./server.mjs'));
|
|
57
|
+
if (!(0, utils_1.isSsrNodeRequestHandler)(reqHandler) && !(0, utils_1.isSsrRequestHandler)(reqHandler)) {
|
|
58
58
|
if (!fallbackWarningShown) {
|
|
59
59
|
// eslint-disable-next-line no-console
|
|
60
|
-
console.warn(`The
|
|
60
|
+
console.warn(`The 'reqHandler' export in 'server.ts' is either undefined or does not provide a recognized request handler. ` +
|
|
61
61
|
'Using the internal SSR middleware instead.');
|
|
62
62
|
fallbackWarningShown = true;
|
|
63
63
|
}
|
|
@@ -73,11 +73,11 @@ async function createAngularSsrExternalMiddleware(server, indexHtmlTransformer)
|
|
|
73
73
|
cachedAngularAppEngine = AngularAppEngine;
|
|
74
74
|
}
|
|
75
75
|
// Forward the request to the middleware in server.ts
|
|
76
|
-
if ((0, utils_1.isSsrNodeRequestHandler)(
|
|
77
|
-
await
|
|
76
|
+
if ((0, utils_1.isSsrNodeRequestHandler)(reqHandler)) {
|
|
77
|
+
await reqHandler(req, res, next);
|
|
78
78
|
}
|
|
79
79
|
else {
|
|
80
|
-
const webRes = await
|
|
80
|
+
const webRes = await reqHandler(createWebRequestFromNodeRequest(req));
|
|
81
81
|
if (!webRes) {
|
|
82
82
|
next();
|
|
83
83
|
return;
|
|
@@ -34,7 +34,8 @@ interface AngularSetupMiddlewaresPluginOptions {
|
|
|
34
34
|
assets: Map<string, string>;
|
|
35
35
|
extensionMiddleware?: Connect.NextHandleFunction[];
|
|
36
36
|
indexHtmlTransformer?: (content: string) => Promise<string>;
|
|
37
|
-
usedComponentStyles: Map<string, string
|
|
37
|
+
usedComponentStyles: Map<string, Set<string>>;
|
|
38
|
+
templateUpdates: Map<string, string>;
|
|
38
39
|
ssrMode: ServerSsrMode;
|
|
39
40
|
}
|
|
40
41
|
export declare function createAngularSetupMiddlewaresPlugin(options: AngularSetupMiddlewaresPluginOptions): Plugin;
|
|
@@ -38,9 +38,10 @@ function createAngularSetupMiddlewaresPlugin(options) {
|
|
|
38
38
|
name: 'vite:angular-setup-middlewares',
|
|
39
39
|
enforce: 'pre',
|
|
40
40
|
configureServer(server) {
|
|
41
|
-
const { indexHtmlTransformer, outputFiles, extensionMiddleware, assets, usedComponentStyles, ssrMode, } = options;
|
|
41
|
+
const { indexHtmlTransformer, outputFiles, extensionMiddleware, assets, usedComponentStyles, templateUpdates, ssrMode, } = options;
|
|
42
42
|
// Headers, assets and resources get handled first
|
|
43
43
|
server.middlewares.use((0, middlewares_1.createAngularHeadersMiddleware)(server));
|
|
44
|
+
server.middlewares.use((0, middlewares_1.createAngularComponentMiddleware)(templateUpdates));
|
|
44
45
|
server.middlewares.use((0, middlewares_1.createAngularAssetsMiddleware)(server, assets, outputFiles, usedComponentStyles));
|
|
45
46
|
extensionMiddleware?.forEach((middleware) => server.middlewares.use(middleware));
|
|
46
47
|
// Returning a function, installs middleware after the main transform middleware but
|
|
@@ -83,6 +83,6 @@ exports.useJSONBuildLogs = isPresent(buildLogsJsonVariable) && isEnabled(buildLo
|
|
|
83
83
|
const optimizeChunksVariable = process.env['NG_BUILD_OPTIMIZE_CHUNKS'];
|
|
84
84
|
exports.shouldOptimizeChunks = isPresent(optimizeChunksVariable) && isEnabled(optimizeChunksVariable);
|
|
85
85
|
const hmrComponentStylesVariable = process.env['NG_HMR_CSTYLES'];
|
|
86
|
-
exports.useComponentStyleHmr = isPresent(hmrComponentStylesVariable)
|
|
86
|
+
exports.useComponentStyleHmr = !isPresent(hmrComponentStylesVariable) || !isDisabled(hmrComponentStylesVariable);
|
|
87
87
|
const partialSsrBuildVariable = process.env['NG_BUILD_PARTIAL_SSR'];
|
|
88
88
|
exports.usePartialSsrBuild = isPresent(partialSsrBuildVariable) && isEnabled(partialSsrBuildVariable);
|
|
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.normalizeCacheOptions = normalizeCacheOptions;
|
|
11
11
|
const node_path_1 = require("node:path");
|
|
12
12
|
/** Version placeholder is replaced during the build process with actual package version */
|
|
13
|
-
const VERSION = '19.0.0-next.
|
|
13
|
+
const VERSION = '19.0.0-next.11';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|