@angular-devkit/build-angular 18.0.0-next.1 → 18.0.0-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/package.json +20 -20
  2. package/src/builders/application/execute-build.js +2 -4
  3. package/src/builders/application/execute-post-bundle.js +9 -12
  4. package/src/builders/application/options.js +50 -32
  5. package/src/builders/browser/index.js +1 -1
  6. package/src/builders/dev-server/vite-server.js +3 -3
  7. package/src/builders/dev-server/webpack-server.js +2 -2
  8. package/src/builders/ssr-dev-server/index.js +29 -29
  9. package/src/tools/esbuild/angular/compiler-plugin.js +12 -4
  10. package/src/tools/esbuild/index-html-generator.d.ts +2 -2
  11. package/src/tools/esbuild/index-html-generator.js +5 -53
  12. package/src/tools/esbuild/javascript-transformer.js +5 -1
  13. package/src/tools/esbuild/stylesheets/css-resource-plugin.js +15 -8
  14. package/src/tools/esbuild/utils.js +2 -2
  15. package/src/tools/sass/rebasing-importer.js +3 -6
  16. package/src/tools/sass/sass-service.d.ts +24 -1
  17. package/src/tools/sass/worker.js +32 -4
  18. package/src/tools/webpack/plugins/any-component-style-budget-checker.d.ts +2 -2
  19. package/src/tools/webpack/plugins/any-component-style-budget-checker.js +13 -16
  20. package/src/tools/webpack/plugins/index-html-webpack-plugin.js +1 -1
  21. package/src/tools/webpack/utils/stats.d.ts +0 -13
  22. package/src/tools/webpack/utils/stats.js +3 -207
  23. package/src/utils/action-executor.d.ts +1 -1
  24. package/src/utils/bundle-calculator.d.ts +5 -5
  25. package/src/utils/bundle-calculator.js +8 -7
  26. package/src/utils/format-bytes.d.ts +8 -0
  27. package/src/utils/format-bytes.js +22 -0
  28. package/src/utils/i18n-inlining.d.ts +1 -1
  29. package/src/utils/i18n-options.d.ts +2 -9
  30. package/src/utils/i18n-options.js +4 -97
  31. package/src/utils/i18n-webpack.d.ts +16 -0
  32. package/src/utils/i18n-webpack.js +108 -0
  33. package/src/utils/index-file/add-event-dispatch-contract.d.ts +8 -0
  34. package/src/utils/index-file/add-event-dispatch-contract.js +28 -0
  35. package/src/utils/index-file/augment-index-html.js +1 -0
  36. package/src/utils/index-file/index-html-generator.d.ts +12 -2
  37. package/src/utils/index-file/index-html-generator.js +38 -22
  38. package/src/utils/index-file/inline-fonts.js +1 -1
  39. package/src/utils/index-file/{style-nonce.d.ts → nonce.d.ts} +2 -2
  40. package/src/utils/index-file/{style-nonce.js → nonce.js} +7 -5
  41. package/src/utils/load-proxy-config.d.ts +1 -1
  42. package/src/utils/load-proxy-config.js +2 -5
  43. package/src/utils/normalize-cache.js +1 -1
  44. package/src/utils/output-paths.d.ts +1 -1
  45. package/src/utils/postcss-configuration.d.ts +7 -1
  46. package/src/utils/postcss-configuration.js +13 -4
  47. package/src/utils/resolve-assets.d.ts +18 -0
  48. package/src/utils/resolve-assets.js +35 -0
  49. package/src/utils/stats-table.d.ts +20 -0
  50. package/src/utils/stats-table.js +205 -0
  51. package/src/utils/webpack-browser-config.d.ts +1 -1
  52. package/src/utils/webpack-browser-config.js +2 -2
@@ -10,18 +10,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
10
10
  return (mod && mod.__esModule) ? mod : { "default": mod };
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.loadTranslations = exports.configureI18nBuild = exports.createI18nOptions = void 0;
14
- const node_fs_1 = __importDefault(require("node:fs"));
15
- const node_module_1 = require("node:module");
16
- const node_os_1 = __importDefault(require("node:os"));
13
+ exports.loadTranslations = exports.createI18nOptions = void 0;
17
14
  const node_path_1 = __importDefault(require("node:path"));
18
- const schema_1 = require("../builders/browser/schema");
19
- const read_tsconfig_1 = require("../utils/read-tsconfig");
20
- const load_translations_1 = require("./load-translations");
21
- /**
22
- * The base module location used to search for locale specific data.
23
- */
24
- const LOCALE_DATA_BASE_MODULE = '@angular/common/locales/global';
25
15
  function normalizeTranslationFileOption(option, locale, expectObjectInError) {
26
16
  if (typeof option === 'string') {
27
17
  return [option];
@@ -123,89 +113,6 @@ function createI18nOptions(projectMetadata, inline) {
123
113
  return i18n;
124
114
  }
125
115
  exports.createI18nOptions = createI18nOptions;
126
- async function configureI18nBuild(context, options) {
127
- if (!context.target) {
128
- throw new Error('The builder requires a target.');
129
- }
130
- const buildOptions = { ...options };
131
- const tsConfig = await (0, read_tsconfig_1.readTsconfig)(buildOptions.tsConfig, context.workspaceRoot);
132
- const metadata = await context.getProjectMetadata(context.target);
133
- const i18n = createI18nOptions(metadata, buildOptions.localize);
134
- // No additional processing needed if no inlining requested and no source locale defined.
135
- if (!i18n.shouldInline && !i18n.hasDefinedSourceLocale) {
136
- return { buildOptions, i18n };
137
- }
138
- const projectRoot = node_path_1.default.join(context.workspaceRoot, metadata.root || '');
139
- // The trailing slash is required to signal that the path is a directory and not a file.
140
- const projectRequire = (0, node_module_1.createRequire)(projectRoot + '/');
141
- const localeResolver = (locale) => projectRequire.resolve(node_path_1.default.join(LOCALE_DATA_BASE_MODULE, locale));
142
- // Load locale data and translations (if present)
143
- let loader;
144
- const usedFormats = new Set();
145
- for (const [locale, desc] of Object.entries(i18n.locales)) {
146
- if (!i18n.inlineLocales.has(locale) && locale !== i18n.sourceLocale) {
147
- continue;
148
- }
149
- let localeDataPath = findLocaleDataPath(locale, localeResolver);
150
- if (!localeDataPath) {
151
- const [first] = locale.split('-');
152
- if (first) {
153
- localeDataPath = findLocaleDataPath(first.toLowerCase(), localeResolver);
154
- if (localeDataPath) {
155
- context.logger.warn(`Locale data for '${locale}' cannot be found. Using locale data for '${first}'.`);
156
- }
157
- }
158
- }
159
- if (!localeDataPath) {
160
- context.logger.warn(`Locale data for '${locale}' cannot be found. No locale data will be included for this locale.`);
161
- }
162
- else {
163
- desc.dataPath = localeDataPath;
164
- }
165
- if (!desc.files.length) {
166
- continue;
167
- }
168
- loader ??= await (0, load_translations_1.createTranslationLoader)();
169
- loadTranslations(locale, desc, context.workspaceRoot, loader, {
170
- warn(message) {
171
- context.logger.warn(message);
172
- },
173
- error(message) {
174
- throw new Error(message);
175
- },
176
- }, usedFormats, buildOptions.i18nDuplicateTranslation);
177
- if (usedFormats.size > 1 && tsConfig.options.enableI18nLegacyMessageIdFormat !== false) {
178
- // This limitation is only for legacy message id support (defaults to true as of 9.0)
179
- throw new Error('Localization currently only supports using one type of translation file format for the entire application.');
180
- }
181
- }
182
- // If inlining store the output in a temporary location to facilitate post-processing
183
- if (i18n.shouldInline) {
184
- // TODO: we should likely save these in the .angular directory in the next major version.
185
- // We'd need to do a migration to add the temp directory to gitignore.
186
- const tempPath = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_fs_1.default.realpathSync(node_os_1.default.tmpdir()), 'angular-cli-i18n-'));
187
- buildOptions.outputPath = tempPath;
188
- process.on('exit', () => {
189
- try {
190
- node_fs_1.default.rmSync(tempPath, { force: true, recursive: true, maxRetries: 3 });
191
- }
192
- catch { }
193
- });
194
- }
195
- return { buildOptions, i18n };
196
- }
197
- exports.configureI18nBuild = configureI18nBuild;
198
- function findLocaleDataPath(locale, resolver) {
199
- // Remove private use subtags
200
- const scrubbedLocale = locale.replace(/-x(-[a-zA-Z0-9]{1,8})+$/, '');
201
- try {
202
- return resolver(scrubbedLocale);
203
- }
204
- catch {
205
- // fallback to known existing en-US locale data as of 14.0
206
- return scrubbedLocale === 'en-US' ? findLocaleDataPath('en', resolver) : null;
207
- }
208
- }
209
116
  function loadTranslations(locale, desc, workspaceRoot, loader, logger, usedFormats, duplicateTranslation) {
210
117
  let translations = undefined;
211
118
  for (const file of desc.files) {
@@ -230,12 +137,12 @@ function loadTranslations(locale, desc, workspaceRoot, loader, logger, usedForma
230
137
  if (translations[id] !== undefined) {
231
138
  const duplicateTranslationMessage = `[${file.path}]: Duplicate translations for message '${id}' when merging.`;
232
139
  switch (duplicateTranslation) {
233
- case schema_1.I18NTranslation.Ignore:
140
+ case 'ignore':
234
141
  break;
235
- case schema_1.I18NTranslation.Error:
142
+ case 'error':
236
143
  logger.error(`ERROR ${duplicateTranslationMessage}`);
237
144
  break;
238
- case schema_1.I18NTranslation.Warning:
145
+ case 'warning':
239
146
  default:
240
147
  logger.warn(`WARNING ${duplicateTranslationMessage}`);
241
148
  break;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.io/license
7
+ */
8
+ import { BuilderContext } from '@angular-devkit/architect';
9
+ import { Schema as BrowserBuilderSchema } from '../builders/browser/schema';
10
+ import { Schema as ServerBuilderSchema } from '../builders/server/schema';
11
+ import { I18nOptions, loadTranslations } from './i18n-options';
12
+ export { I18nOptions, loadTranslations };
13
+ export declare function configureI18nBuild<T extends BrowserBuilderSchema | ServerBuilderSchema>(context: BuilderContext, options: T): Promise<{
14
+ buildOptions: T;
15
+ i18n: I18nOptions;
16
+ }>;
@@ -0,0 +1,108 @@
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.configureI18nBuild = exports.loadTranslations = void 0;
14
+ const node_fs_1 = __importDefault(require("node:fs"));
15
+ const node_module_1 = require("node:module");
16
+ const node_os_1 = __importDefault(require("node:os"));
17
+ const node_path_1 = __importDefault(require("node:path"));
18
+ const read_tsconfig_1 = require("../utils/read-tsconfig");
19
+ const i18n_options_1 = require("./i18n-options");
20
+ Object.defineProperty(exports, "loadTranslations", { enumerable: true, get: function () { return i18n_options_1.loadTranslations; } });
21
+ const load_translations_1 = require("./load-translations");
22
+ /**
23
+ * The base module location used to search for locale specific data.
24
+ */
25
+ const LOCALE_DATA_BASE_MODULE = '@angular/common/locales/global';
26
+ async function configureI18nBuild(context, options) {
27
+ if (!context.target) {
28
+ throw new Error('The builder requires a target.');
29
+ }
30
+ const buildOptions = { ...options };
31
+ const tsConfig = await (0, read_tsconfig_1.readTsconfig)(buildOptions.tsConfig, context.workspaceRoot);
32
+ const metadata = await context.getProjectMetadata(context.target);
33
+ const i18n = (0, i18n_options_1.createI18nOptions)(metadata, buildOptions.localize);
34
+ // No additional processing needed if no inlining requested and no source locale defined.
35
+ if (!i18n.shouldInline && !i18n.hasDefinedSourceLocale) {
36
+ return { buildOptions, i18n };
37
+ }
38
+ const projectRoot = node_path_1.default.join(context.workspaceRoot, metadata.root || '');
39
+ // The trailing slash is required to signal that the path is a directory and not a file.
40
+ const projectRequire = (0, node_module_1.createRequire)(projectRoot + '/');
41
+ const localeResolver = (locale) => projectRequire.resolve(node_path_1.default.join(LOCALE_DATA_BASE_MODULE, locale));
42
+ // Load locale data and translations (if present)
43
+ let loader;
44
+ const usedFormats = new Set();
45
+ for (const [locale, desc] of Object.entries(i18n.locales)) {
46
+ if (!i18n.inlineLocales.has(locale) && locale !== i18n.sourceLocale) {
47
+ continue;
48
+ }
49
+ let localeDataPath = findLocaleDataPath(locale, localeResolver);
50
+ if (!localeDataPath) {
51
+ const [first] = locale.split('-');
52
+ if (first) {
53
+ localeDataPath = findLocaleDataPath(first.toLowerCase(), localeResolver);
54
+ if (localeDataPath) {
55
+ context.logger.warn(`Locale data for '${locale}' cannot be found. Using locale data for '${first}'.`);
56
+ }
57
+ }
58
+ }
59
+ if (!localeDataPath) {
60
+ context.logger.warn(`Locale data for '${locale}' cannot be found. No locale data will be included for this locale.`);
61
+ }
62
+ else {
63
+ desc.dataPath = localeDataPath;
64
+ }
65
+ if (!desc.files.length) {
66
+ continue;
67
+ }
68
+ loader ??= await (0, load_translations_1.createTranslationLoader)();
69
+ (0, i18n_options_1.loadTranslations)(locale, desc, context.workspaceRoot, loader, {
70
+ warn(message) {
71
+ context.logger.warn(message);
72
+ },
73
+ error(message) {
74
+ throw new Error(message);
75
+ },
76
+ }, usedFormats, buildOptions.i18nDuplicateTranslation);
77
+ if (usedFormats.size > 1 && tsConfig.options.enableI18nLegacyMessageIdFormat !== false) {
78
+ // This limitation is only for legacy message id support (defaults to true as of 9.0)
79
+ throw new Error('Localization currently only supports using one type of translation file format for the entire application.');
80
+ }
81
+ }
82
+ // If inlining store the output in a temporary location to facilitate post-processing
83
+ if (i18n.shouldInline) {
84
+ // TODO: we should likely save these in the .angular directory in the next major version.
85
+ // We'd need to do a migration to add the temp directory to gitignore.
86
+ const tempPath = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_fs_1.default.realpathSync(node_os_1.default.tmpdir()), 'angular-cli-i18n-'));
87
+ buildOptions.outputPath = tempPath;
88
+ process.on('exit', () => {
89
+ try {
90
+ node_fs_1.default.rmSync(tempPath, { force: true, recursive: true, maxRetries: 3 });
91
+ }
92
+ catch { }
93
+ });
94
+ }
95
+ return { buildOptions, i18n };
96
+ }
97
+ exports.configureI18nBuild = configureI18nBuild;
98
+ function findLocaleDataPath(locale, resolver) {
99
+ // Remove private use subtags
100
+ const scrubbedLocale = locale.replace(/-x(-[a-zA-Z0-9]{1,8})+$/, '');
101
+ try {
102
+ return resolver(scrubbedLocale);
103
+ }
104
+ catch {
105
+ // fallback to known existing en-US locale data as of 14.0
106
+ return scrubbedLocale === 'en-US' ? findLocaleDataPath('en', resolver) : null;
107
+ }
108
+ }
@@ -0,0 +1,8 @@
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
+ export declare function addEventDispatchContract(html: string): Promise<string>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.io/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.addEventDispatchContract = void 0;
11
+ const promises_1 = require("node:fs/promises");
12
+ const html_rewriting_stream_1 = require("./html-rewriting-stream");
13
+ let jsActionContractScript;
14
+ async function addEventDispatchContract(html) {
15
+ const { rewriter, transformedContent } = await (0, html_rewriting_stream_1.htmlRewritingStream)(html);
16
+ jsActionContractScript ??=
17
+ '<script type="text/javascript" id="ng-event-dispatch-contract">' +
18
+ (await (0, promises_1.readFile)(require.resolve('@angular/core/event-dispatch-contract.min.js'), 'utf-8')) +
19
+ '</script>';
20
+ rewriter.on('startTag', (tag) => {
21
+ rewriter.emitStartTag(tag);
22
+ if (tag.tagName === 'body') {
23
+ rewriter.emitRaw(jsActionContractScript);
24
+ }
25
+ });
26
+ return transformedContent();
27
+ }
28
+ exports.addEventDispatchContract = addEventDispatchContract;
@@ -152,6 +152,7 @@ async function augmentIndexHtml(params) {
152
152
  foundPreconnects.add(href);
153
153
  }
154
154
  }
155
+ break;
155
156
  }
156
157
  rewriter.emitStartTag(tag);
157
158
  })
@@ -30,18 +30,28 @@ export interface IndexHtmlGeneratorOptions {
30
30
  optimization?: NormalizedOptimizationOptions;
31
31
  cache?: NormalizedCachedOptions;
32
32
  imageDomains?: string[];
33
+ generateDedicatedSSRContent?: boolean;
33
34
  }
34
35
  export type IndexHtmlTransform = (content: string) => Promise<string>;
35
- export interface IndexHtmlTransformResult {
36
+ export interface IndexHtmlPluginTransformResult {
36
37
  content: string;
37
38
  warnings: string[];
38
39
  errors: string[];
39
40
  }
41
+ export interface IndexHtmlProcessResult {
42
+ csrContent: string;
43
+ ssrContent?: string;
44
+ warnings: string[];
45
+ errors: string[];
46
+ }
40
47
  export declare class IndexHtmlGenerator {
41
48
  readonly options: IndexHtmlGeneratorOptions;
42
49
  private readonly plugins;
50
+ private readonly csrPlugins;
51
+ private readonly ssrPlugins;
43
52
  constructor(options: IndexHtmlGeneratorOptions);
44
- process(options: IndexHtmlGeneratorProcessOptions): Promise<IndexHtmlTransformResult>;
53
+ process(options: IndexHtmlGeneratorProcessOptions): Promise<IndexHtmlProcessResult>;
54
+ private runPlugins;
45
55
  readAsset(path: string): Promise<string>;
46
56
  protected readIndex(path: string): Promise<string>;
47
57
  }
@@ -10,36 +10,53 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.IndexHtmlGenerator = void 0;
11
11
  const promises_1 = require("node:fs/promises");
12
12
  const node_path_1 = require("node:path");
13
+ const add_event_dispatch_contract_1 = require("./add-event-dispatch-contract");
13
14
  const augment_index_html_1 = require("./augment-index-html");
14
15
  const inline_critical_css_1 = require("./inline-critical-css");
15
16
  const inline_fonts_1 = require("./inline-fonts");
16
- const style_nonce_1 = require("./style-nonce");
17
+ const nonce_1 = require("./nonce");
17
18
  class IndexHtmlGenerator {
18
19
  options;
19
20
  plugins;
21
+ csrPlugins = [];
22
+ ssrPlugins = [];
20
23
  constructor(options) {
21
24
  this.options = options;
22
- const extraPlugins = [];
23
- if (this.options.optimization?.fonts.inline) {
24
- extraPlugins.push(inlineFontsPlugin(this));
25
+ const extraCommonPlugins = [];
26
+ if (options?.optimization?.fonts.inline) {
27
+ extraCommonPlugins.push(inlineFontsPlugin(this), nonce_1.addNonce);
25
28
  }
26
- if (this.options.optimization?.styles.inlineCritical) {
27
- extraPlugins.push(inlineCriticalCssPlugin(this));
29
+ // Common plugins
30
+ this.plugins = [augmentIndexHtmlPlugin(this), ...extraCommonPlugins, postTransformPlugin(this)];
31
+ // CSR plugins
32
+ if (options?.optimization?.styles?.inlineCritical) {
33
+ this.csrPlugins.push(inlineCriticalCssPlugin(this));
34
+ }
35
+ // SSR plugins
36
+ if (options.generateDedicatedSSRContent) {
37
+ this.ssrPlugins.push(addEventDispatchContractPlugin(), addNoncePlugin());
28
38
  }
29
- this.plugins = [
30
- augmentIndexHtmlPlugin(this),
31
- ...extraPlugins,
32
- // Runs after the `extraPlugins` to capture any nonce or
33
- // `style` tags that might've been added by them.
34
- addStyleNoncePlugin(),
35
- postTransformPlugin(this),
36
- ];
37
39
  }
38
40
  async process(options) {
39
41
  let content = await this.readIndex(this.options.indexPath);
40
42
  const warnings = [];
41
43
  const errors = [];
42
- for (const plugin of this.plugins) {
44
+ content = await this.runPlugins(content, this.plugins, options, warnings, errors);
45
+ const [csrContent, ssrContent] = await Promise.all([
46
+ this.runPlugins(content, this.csrPlugins, options, warnings, errors),
47
+ this.ssrPlugins.length
48
+ ? this.runPlugins(content, this.ssrPlugins, options, warnings, errors)
49
+ : undefined,
50
+ ]);
51
+ return {
52
+ ssrContent,
53
+ csrContent,
54
+ warnings,
55
+ errors,
56
+ };
57
+ }
58
+ async runPlugins(content, plugins, options, warnings, errors) {
59
+ for (const plugin of plugins) {
43
60
  const result = await plugin(content, options);
44
61
  if (typeof result === 'string') {
45
62
  content = result;
@@ -54,11 +71,7 @@ class IndexHtmlGenerator {
54
71
  }
55
72
  }
56
73
  }
57
- return {
58
- content,
59
- warnings,
60
- errors,
61
- };
74
+ return content;
62
75
  }
63
76
  async readAsset(path) {
64
77
  try {
@@ -111,9 +124,12 @@ function inlineCriticalCssPlugin(generator) {
111
124
  });
112
125
  return async (html, options) => inlineCriticalCssProcessor.process(html, { outputPath: options.outputPath });
113
126
  }
114
- function addStyleNoncePlugin() {
115
- return (html) => (0, style_nonce_1.addStyleNonce)(html);
127
+ function addNoncePlugin() {
128
+ return (html) => (0, nonce_1.addNonce)(html);
116
129
  }
117
130
  function postTransformPlugin({ options }) {
118
131
  return async (html) => (options.postTransform ? options.postTransform(html) : html);
119
132
  }
133
+ function addEventDispatchContractPlugin() {
134
+ return (html) => (0, add_event_dispatch_contract_1.addEventDispatchContract)(html);
135
+ }
@@ -143,7 +143,7 @@ class InlineFontsProcessor {
143
143
  if (hrefAttr) {
144
144
  const href = hrefAttr.value;
145
145
  const cssContent = hrefsContent.get(href);
146
- rewriter.emitRaw(`<style type="text/css">${cssContent}</style>`);
146
+ rewriter.emitRaw(`<style>${cssContent}</style>`);
147
147
  }
148
148
  else {
149
149
  rewriter.emitStartTag(tag);
@@ -6,7 +6,7 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  /**
9
- * Finds the `ngCspNonce` value and copies it to all inline `<style>` tags.
9
+ * Finds the `ngCspNonce` value and copies it to all inline `<style>` and `<script> `tags.
10
10
  * @param html Markup that should be processed.
11
11
  */
12
- export declare function addStyleNonce(html: string): Promise<string>;
12
+ export declare function addNonce(html: string): Promise<string>;
@@ -7,7 +7,7 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.addStyleNonce = void 0;
10
+ exports.addNonce = void 0;
11
11
  const html_rewriting_stream_1 = require("./html-rewriting-stream");
12
12
  /**
13
13
  * Pattern matching the name of the Angular nonce attribute. Note that this is
@@ -15,24 +15,26 @@ const html_rewriting_stream_1 = require("./html-rewriting-stream");
15
15
  */
16
16
  const NONCE_ATTR_PATTERN = /ngCspNonce/i;
17
17
  /**
18
- * Finds the `ngCspNonce` value and copies it to all inline `<style>` tags.
18
+ * Finds the `ngCspNonce` value and copies it to all inline `<style>` and `<script> `tags.
19
19
  * @param html Markup that should be processed.
20
20
  */
21
- async function addStyleNonce(html) {
21
+ async function addNonce(html) {
22
22
  const nonce = await findNonce(html);
23
23
  if (!nonce) {
24
24
  return html;
25
25
  }
26
26
  const { rewriter, transformedContent } = await (0, html_rewriting_stream_1.htmlRewritingStream)(html);
27
27
  rewriter.on('startTag', (tag) => {
28
- if (tag.tagName === 'style' && !tag.attrs.some((attr) => attr.name === 'nonce')) {
28
+ if ((tag.tagName === 'style' ||
29
+ (tag.tagName === 'script' && !tag.attrs.some((attr) => attr.name === 'src'))) &&
30
+ !tag.attrs.some((attr) => attr.name === 'nonce')) {
29
31
  tag.attrs.push({ name: 'nonce', value: nonce });
30
32
  }
31
33
  rewriter.emitStartTag(tag);
32
34
  });
33
35
  return transformedContent();
34
36
  }
35
- exports.addStyleNonce = addStyleNonce;
37
+ exports.addNonce = addNonce;
36
38
  /** Finds the Angular nonce in an HTML string. */
37
39
  async function findNonce(html) {
38
40
  // Inexpensive check to avoid parsing the HTML when we're sure there's no nonce.
@@ -5,4 +5,4 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
- export declare function loadProxyConfiguration(root: string, proxyConfig: string | undefined, normalize?: boolean): Promise<any>;
8
+ export declare function loadProxyConfiguration(root: string, proxyConfig: string | undefined): Promise<Record<string, object> | undefined>;
@@ -39,7 +39,7 @@ const node_url_1 = require("node:url");
39
39
  const picomatch_1 = require("picomatch");
40
40
  const error_1 = require("./error");
41
41
  const load_esm_1 = require("./load-esm");
42
- async function loadProxyConfiguration(root, proxyConfig, normalize = false) {
42
+ async function loadProxyConfiguration(root, proxyConfig) {
43
43
  if (!proxyConfig) {
44
44
  return undefined;
45
45
  }
@@ -94,10 +94,7 @@ async function loadProxyConfiguration(root, proxyConfig, normalize = false) {
94
94
  throw e;
95
95
  }
96
96
  }
97
- if (normalize) {
98
- proxyConfiguration = normalizeProxyConfiguration(proxyConfiguration);
99
- }
100
- return proxyConfiguration;
97
+ return normalizeProxyConfiguration(proxyConfiguration);
101
98
  }
102
99
  exports.loadProxyConfiguration = loadProxyConfiguration;
103
100
  /**
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.normalizeCacheOptions = void 0;
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 = '18.0.0-next.1';
13
+ const VERSION = '18.0.0-next.3';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&
@@ -5,5 +5,5 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
- import { I18nOptions } from './i18n-options';
8
+ import { I18nOptions } from './i18n-webpack';
9
9
  export declare function ensureOutputPaths(baseOutputPath: string, i18n: I18nOptions): Map<string, string>;
@@ -8,4 +8,10 @@
8
8
  export interface PostcssConfiguration {
9
9
  plugins: [name: string, options?: object | string][];
10
10
  }
11
- export declare function loadPostcssConfiguration(workspaceRoot: string, projectRoot: string): Promise<PostcssConfiguration | undefined>;
11
+ export interface SearchDirectory {
12
+ root: string;
13
+ files: Set<string>;
14
+ }
15
+ export declare function generateSearchDirectories(roots: string[]): Promise<SearchDirectory[]>;
16
+ export declare function findTailwindConfiguration(searchDirectories: SearchDirectory[]): string | undefined;
17
+ export declare function loadPostcssConfiguration(searchDirectories: SearchDirectory[]): Promise<PostcssConfiguration | undefined>;
@@ -7,16 +7,23 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.loadPostcssConfiguration = void 0;
10
+ exports.loadPostcssConfiguration = exports.findTailwindConfiguration = exports.generateSearchDirectories = void 0;
11
11
  const promises_1 = require("node:fs/promises");
12
12
  const node_path_1 = require("node:path");
13
13
  const postcssConfigurationFiles = ['postcss.config.json', '.postcssrc.json'];
14
+ const tailwindConfigFiles = [
15
+ 'tailwind.config.js',
16
+ 'tailwind.config.cjs',
17
+ 'tailwind.config.mjs',
18
+ 'tailwind.config.ts',
19
+ ];
14
20
  async function generateSearchDirectories(roots) {
15
21
  return await Promise.all(roots.map((root) => (0, promises_1.readdir)(root, { withFileTypes: true }).then((entries) => ({
16
22
  root,
17
23
  files: new Set(entries.filter((entry) => entry.isFile()).map((entry) => entry.name)),
18
24
  }))));
19
25
  }
26
+ exports.generateSearchDirectories = generateSearchDirectories;
20
27
  function findFile(searchDirectories, potentialFiles) {
21
28
  for (const { root, files } of searchDirectories) {
22
29
  for (const potential of potentialFiles) {
@@ -27,14 +34,16 @@ function findFile(searchDirectories, potentialFiles) {
27
34
  }
28
35
  return undefined;
29
36
  }
37
+ function findTailwindConfiguration(searchDirectories) {
38
+ return findFile(searchDirectories, tailwindConfigFiles);
39
+ }
40
+ exports.findTailwindConfiguration = findTailwindConfiguration;
30
41
  async function readPostcssConfiguration(configurationFile) {
31
42
  const data = await (0, promises_1.readFile)(configurationFile, 'utf-8');
32
43
  const config = JSON.parse(data);
33
44
  return config;
34
45
  }
35
- async function loadPostcssConfiguration(workspaceRoot, projectRoot) {
36
- // A configuration file can exist in the project or workspace root
37
- const searchDirectories = await generateSearchDirectories([projectRoot, workspaceRoot]);
46
+ async function loadPostcssConfiguration(searchDirectories) {
38
47
  const configPath = findFile(searchDirectories, postcssConfigurationFiles);
39
48
  if (!configPath) {
40
49
  return undefined;
@@ -0,0 +1,18 @@
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
+ export declare function resolveAssets(entries: {
9
+ glob: string;
10
+ ignore?: string[];
11
+ input: string;
12
+ output: string;
13
+ flatten?: boolean;
14
+ followSymlinks?: boolean;
15
+ }[], root: string): Promise<{
16
+ source: string;
17
+ destination: string;
18
+ }[]>;
@@ -0,0 +1,35 @@
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.resolveAssets = void 0;
14
+ const fast_glob_1 = __importDefault(require("fast-glob"));
15
+ const node_path_1 = __importDefault(require("node:path"));
16
+ async function resolveAssets(entries, root) {
17
+ const defaultIgnore = ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'];
18
+ const outputFiles = [];
19
+ for (const entry of entries) {
20
+ const cwd = node_path_1.default.resolve(root, entry.input);
21
+ const files = await (0, fast_glob_1.default)(entry.glob, {
22
+ cwd,
23
+ dot: true,
24
+ ignore: entry.ignore ? defaultIgnore.concat(entry.ignore) : defaultIgnore,
25
+ followSymbolicLinks: entry.followSymlinks,
26
+ });
27
+ for (const file of files) {
28
+ const src = node_path_1.default.join(cwd, file);
29
+ const filePath = entry.flatten ? node_path_1.default.basename(file) : file;
30
+ outputFiles.push({ source: src, destination: node_path_1.default.join(entry.output, filePath) });
31
+ }
32
+ }
33
+ return outputFiles;
34
+ }
35
+ exports.resolveAssets = resolveAssets;