@angular-devkit/build-angular 17.1.0-next.1 → 17.1.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 (51) hide show
  1. package/package.json +18 -18
  2. package/src/builders/application/build-action.d.ts +4 -3
  3. package/src/builders/application/build-action.js +24 -14
  4. package/src/builders/application/execute-build.js +3 -3
  5. package/src/builders/application/index.d.ts +20 -10
  6. package/src/builders/application/index.js +38 -26
  7. package/src/builders/application/options.d.ts +11 -3
  8. package/src/builders/application/options.js +39 -26
  9. package/src/builders/application/schema.d.ts +32 -2
  10. package/src/builders/application/schema.json +40 -2
  11. package/src/builders/browser-esbuild/builder-status-warnings.js +1 -3
  12. package/src/builders/browser-esbuild/index.js +8 -4
  13. package/src/builders/dev-server/builder.js +5 -0
  14. package/src/builders/dev-server/vite-server.js +16 -16
  15. package/src/builders/karma/index.js +4 -1
  16. package/src/builders/karma/schema.d.ts +6 -2
  17. package/src/builders/karma/schema.json +12 -2
  18. package/src/builders/ssr-dev-server/index.js +17 -31
  19. package/src/tools/esbuild/angular/angular-host.js +7 -1
  20. package/src/tools/esbuild/angular/compiler-plugin.js +11 -27
  21. package/src/tools/esbuild/angular/component-stylesheets.d.ts +3 -6
  22. package/src/tools/esbuild/angular/component-stylesheets.js +42 -47
  23. package/src/tools/esbuild/angular/jit-plugin-callbacks.d.ts +2 -1
  24. package/src/tools/esbuild/angular/jit-plugin-callbacks.js +16 -16
  25. package/src/tools/esbuild/angular/source-file-cache.js +0 -1
  26. package/src/tools/esbuild/bundler-context.d.ts +1 -1
  27. package/src/tools/esbuild/bundler-context.js +18 -2
  28. package/src/tools/esbuild/compiler-plugin-options.js +5 -3
  29. package/src/tools/esbuild/global-styles.js +4 -2
  30. package/src/tools/esbuild/index-html-generator.js +3 -1
  31. package/src/tools/esbuild/stylesheets/bundle-options.d.ts +4 -1
  32. package/src/tools/esbuild/stylesheets/bundle-options.js +11 -6
  33. package/src/tools/esbuild/stylesheets/css-inline-fonts-plugin.d.ts +25 -0
  34. package/src/tools/esbuild/stylesheets/css-inline-fonts-plugin.js +57 -0
  35. package/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.js +9 -1
  36. package/src/tools/esbuild/utils.d.ts +2 -2
  37. package/src/tools/esbuild/utils.js +61 -74
  38. package/src/tools/esbuild/watcher.js +56 -121
  39. package/src/utils/check-port.js +15 -29
  40. package/src/utils/delete-output-dir.d.ts +1 -1
  41. package/src/utils/delete-output-dir.js +11 -2
  42. package/src/utils/index-file/index-html-generator.js +15 -28
  43. package/src/utils/index-file/inline-fonts.d.ts +6 -1
  44. package/src/utils/index-file/inline-fonts.js +30 -14
  45. package/src/utils/index.d.ts +1 -0
  46. package/src/utils/index.js +1 -0
  47. package/src/{builders/dev-server → utils}/load-proxy-config.js +2 -2
  48. package/src/utils/server-rendering/esm-in-memory-loader/node-18-utils.js +6 -5
  49. package/src/tools/esbuild/normalize-path.d.ts +0 -8
  50. package/src/tools/esbuild/normalize-path.js +0 -22
  51. /package/src/{builders/dev-server → utils}/load-proxy-config.d.ts +0 -0
package/package.json CHANGED
@@ -1,37 +1,36 @@
1
1
  {
2
2
  "name": "@angular-devkit/build-angular",
3
- "version": "17.1.0-next.1",
3
+ "version": "17.1.0-next.3",
4
4
  "description": "Angular Webpack Build Facade",
5
5
  "main": "src/index.js",
6
6
  "typings": "src/index.d.ts",
7
7
  "builders": "builders.json",
8
8
  "dependencies": {
9
9
  "@ampproject/remapping": "2.2.1",
10
- "@angular-devkit/architect": "0.1701.0-next.1",
11
- "@angular-devkit/build-webpack": "0.1701.0-next.1",
12
- "@angular-devkit/core": "17.1.0-next.1",
13
- "@babel/core": "7.23.5",
14
- "@babel/generator": "7.23.5",
10
+ "@angular-devkit/architect": "0.1701.0-next.3",
11
+ "@angular-devkit/build-webpack": "0.1701.0-next.3",
12
+ "@angular-devkit/core": "17.1.0-next.3",
13
+ "@babel/core": "7.23.6",
14
+ "@babel/generator": "7.23.6",
15
15
  "@babel/helper-annotate-as-pure": "7.22.5",
16
16
  "@babel/helper-split-export-declaration": "7.22.6",
17
17
  "@babel/plugin-transform-async-generator-functions": "7.23.4",
18
18
  "@babel/plugin-transform-async-to-generator": "7.23.3",
19
- "@babel/plugin-transform-runtime": "7.23.4",
20
- "@babel/preset-env": "7.23.5",
21
- "@babel/runtime": "7.23.5",
19
+ "@babel/plugin-transform-runtime": "7.23.6",
20
+ "@babel/preset-env": "7.23.6",
21
+ "@babel/runtime": "7.23.6",
22
22
  "@discoveryjs/json-ext": "0.5.7",
23
- "@ngtools/webpack": "17.1.0-next.1",
23
+ "@ngtools/webpack": "17.1.0-next.3",
24
24
  "@vitejs/plugin-basic-ssl": "1.0.2",
25
25
  "ansi-colors": "4.1.3",
26
26
  "autoprefixer": "10.4.16",
27
27
  "babel-loader": "9.1.3",
28
28
  "babel-plugin-istanbul": "6.1.1",
29
29
  "browserslist": "^4.21.5",
30
- "chokidar": "3.5.3",
31
30
  "copy-webpack-plugin": "11.0.0",
32
31
  "critters": "0.0.20",
33
32
  "css-loader": "6.8.1",
34
- "esbuild-wasm": "0.19.8",
33
+ "esbuild-wasm": "0.19.10",
35
34
  "fast-glob": "3.3.2",
36
35
  "https-proxy-agent": "7.0.2",
37
36
  "http-proxy-middleware": "2.0.6",
@@ -44,12 +43,12 @@
44
43
  "loader-utils": "3.2.1",
45
44
  "magic-string": "0.30.5",
46
45
  "mini-css-extract-plugin": "2.7.6",
47
- "mrmime": "1.0.1",
46
+ "mrmime": "2.0.0",
48
47
  "open": "8.4.2",
49
48
  "ora": "5.4.1",
50
49
  "parse5-html-rewriting-stream": "7.0.0",
51
50
  "picomatch": "3.0.1",
52
- "piscina": "4.2.0",
51
+ "piscina": "4.2.1",
53
52
  "postcss": "8.4.32",
54
53
  "postcss-loader": "7.3.3",
55
54
  "resolve-url-loader": "5.0.0",
@@ -59,12 +58,13 @@
59
58
  "semver": "7.5.4",
60
59
  "source-map-loader": "4.0.1",
61
60
  "source-map-support": "0.5.21",
62
- "terser": "5.25.0",
61
+ "terser": "5.26.0",
63
62
  "text-table": "0.2.0",
64
63
  "tree-kill": "1.2.2",
65
64
  "tslib": "2.6.2",
66
- "undici": "6.0.1",
67
- "vite": "5.0.6",
65
+ "undici": "6.2.0",
66
+ "vite": "5.0.10",
67
+ "watchpack": "2.4.0",
68
68
  "webpack": "5.89.0",
69
69
  "webpack-dev-middleware": "6.1.1",
70
70
  "webpack-dev-server": "4.15.1",
@@ -72,7 +72,7 @@
72
72
  "webpack-subresource-integrity": "5.1.0"
73
73
  },
74
74
  "optionalDependencies": {
75
- "esbuild": "0.19.8"
75
+ "esbuild": "0.19.10"
76
76
  },
77
77
  "peerDependencies": {
78
78
  "@angular/compiler-cli": "^17.0.0 || ^17.1.0-next.0",
@@ -10,14 +10,15 @@ import type { logging } from '@angular-devkit/core';
10
10
  import { BuildOutputFile } from '../../tools/esbuild/bundler-context';
11
11
  import { ExecutionResult, RebuildState } from '../../tools/esbuild/bundler-execution-result';
12
12
  import { NormalizedCachedOptions } from '../../utils/normalize-cache';
13
+ import { NormalizedOutputOptions } from './options';
13
14
  export declare function runEsBuildBuildAction(action: (rebuildState?: RebuildState) => ExecutionResult | Promise<ExecutionResult>, options: {
14
15
  workspaceRoot: string;
15
16
  projectRoot: string;
16
- outputPath: string;
17
+ outputOptions: NormalizedOutputOptions;
17
18
  logger: logging.LoggerApi;
18
19
  cacheOptions: NormalizedCachedOptions;
19
- writeToFileSystem?: boolean;
20
- writeToFileSystemFilter?: (file: BuildOutputFile) => boolean;
20
+ writeToFileSystem: boolean;
21
+ writeToFileSystemFilter: ((file: BuildOutputFile) => boolean) | undefined;
21
22
  watch?: boolean;
22
23
  verbose?: boolean;
23
24
  progress?: boolean;
@@ -34,15 +34,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
34
34
  };
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.runEsBuildBuildAction = void 0;
37
+ const node_fs_1 = require("node:fs");
37
38
  const node_path_1 = __importDefault(require("node:path"));
38
39
  const sass_language_1 = require("../../tools/esbuild/stylesheets/sass-language");
39
40
  const utils_1 = require("../../tools/esbuild/utils");
40
41
  const delete_output_dir_1 = require("../../utils/delete-output-dir");
41
42
  const environment_options_1 = require("../../utils/environment-options");
42
43
  async function* runEsBuildBuildAction(action, options) {
43
- const { writeToFileSystemFilter, writeToFileSystem = true, watch, poll, logger, deleteOutputPath, cacheOptions, outputPath, verbose, projectRoot, workspaceRoot, progress, preserveSymlinks, } = options;
44
+ const { writeToFileSystemFilter, writeToFileSystem, watch, poll, logger, deleteOutputPath, cacheOptions, outputOptions, verbose, projectRoot, workspaceRoot, progress, preserveSymlinks, } = options;
44
45
  if (deleteOutputPath && writeToFileSystem) {
45
- await (0, delete_output_dir_1.deleteOutputDir)(workspaceRoot, outputPath);
46
+ await (0, delete_output_dir_1.deleteOutputDir)(workspaceRoot, outputOptions.base, [
47
+ outputOptions.browser,
48
+ outputOptions.server,
49
+ ]);
46
50
  }
47
51
  const withProgress = progress ? utils_1.withSpinner : utils_1.withNoProgress;
48
52
  // Initial build
@@ -62,21 +66,25 @@ async function* runEsBuildBuildAction(action, options) {
62
66
  if (progress) {
63
67
  logger.info('Watch mode enabled. Watching for file changes...');
64
68
  }
69
+ const ignored = [
70
+ // Ignore the output and cache paths to avoid infinite rebuild cycles
71
+ outputOptions.base,
72
+ cacheOptions.basePath,
73
+ `${workspaceRoot.replace(/\\/g, '/')}/**/.*/**`,
74
+ ];
75
+ if (!preserveSymlinks) {
76
+ // Ignore all node modules directories to avoid excessive file watchers.
77
+ // Package changes are handled below by watching manifest and lock files.
78
+ // NOTE: this is not enable when preserveSymlinks is true as this would break `npm link` usages.
79
+ ignored.push('**/node_modules/**');
80
+ }
65
81
  // Setup a watcher
66
82
  const { createWatcher } = await Promise.resolve().then(() => __importStar(require('../../tools/esbuild/watcher')));
67
83
  watcher = createWatcher({
68
84
  polling: typeof poll === 'number',
69
85
  interval: poll,
70
86
  followSymlinks: preserveSymlinks,
71
- ignored: [
72
- // Ignore the output and cache paths to avoid infinite rebuild cycles
73
- outputPath,
74
- cacheOptions.basePath,
75
- // Ignore all node modules directories to avoid excessive file watchers.
76
- // Package changes are handled below by watching manifest and lock files.
77
- '**/node_modules/**',
78
- `${workspaceRoot.replace(/\\/g, '/')}/**/.*/**`,
79
- ],
87
+ ignored,
80
88
  });
81
89
  // Setup abort support
82
90
  options.signal?.addEventListener('abort', () => void watcher?.close());
@@ -97,7 +105,9 @@ async function* runEsBuildBuildAction(action, options) {
97
105
  '.pnp.cjs',
98
106
  '.pnp.data.json',
99
107
  ];
100
- watcher.add(packageWatchFiles.map((file) => node_path_1.default.join(workspaceRoot, file)));
108
+ watcher.add(packageWatchFiles
109
+ .map((file) => node_path_1.default.join(workspaceRoot, file))
110
+ .filter((file) => (0, node_fs_1.existsSync)(file)));
101
111
  // Watch locations provided by the initial build result
102
112
  watcher.add(result.watchFiles);
103
113
  }
@@ -106,7 +116,7 @@ async function* runEsBuildBuildAction(action, options) {
106
116
  // unit tests which execute the builder and modify the file system programmatically.
107
117
  if (writeToFileSystem) {
108
118
  // Write output files
109
- await (0, utils_1.writeResultFiles)(result.outputFiles, result.assetFiles, outputPath);
119
+ await (0, utils_1.writeResultFiles)(result.outputFiles, result.assetFiles, outputOptions);
110
120
  yield result.output;
111
121
  }
112
122
  else {
@@ -151,7 +161,7 @@ async function* runEsBuildBuildAction(action, options) {
151
161
  const filesToWrite = writeToFileSystemFilter
152
162
  ? result.outputFiles.filter(writeToFileSystemFilter)
153
163
  : result.outputFiles;
154
- await (0, utils_1.writeResultFiles)(filesToWrite, result.assetFiles, outputPath);
164
+ await (0, utils_1.writeResultFiles)(filesToWrite, result.assetFiles, outputOptions);
155
165
  yield result.output;
156
166
  }
157
167
  else {
@@ -92,10 +92,10 @@ async function executeBuild(options, context, rebuildState) {
92
92
  return executionResult;
93
93
  }
94
94
  // Analyze external imports if external options are enabled
95
- if (options.externalPackages || options.externalDependencies?.length) {
95
+ if (options.externalPackages || bundlingResult.externalConfiguration) {
96
96
  const { browser = new Set(), server = new Set() } = bundlingResult.externalImports;
97
- // TODO: Filter externalImports to generate second argument to support wildcard externalDependency values
98
- executionResult.setExternalMetadata([...browser], [...server], options.externalDependencies);
97
+ // TODO: Filter externalImports to generate third argument to support wildcard externalConfiguration values
98
+ executionResult.setExternalMetadata([...browser], [...server], bundlingResult.externalConfiguration);
99
99
  }
100
100
  const { metafile, initialFiles, outputFiles } = bundlingResult;
101
101
  executionResult.outputFiles.push(...outputFiles);
@@ -8,20 +8,21 @@
8
8
  import { BuilderContext, BuilderOutput } from '@angular-devkit/architect';
9
9
  import type { Plugin } from 'esbuild';
10
10
  import { BuildOutputFile } from '../../tools/esbuild/bundler-context';
11
- import { ApplicationBuilderInternalOptions } from './options';
11
+ import { ApplicationBuilderExtensions, ApplicationBuilderInternalOptions } from './options';
12
12
  import { Schema as ApplicationBuilderOptions } from './schema';
13
13
  export { ApplicationBuilderOptions };
14
14
  export declare function buildApplicationInternal(options: ApplicationBuilderInternalOptions, context: BuilderContext & {
15
15
  signal?: AbortSignal;
16
16
  }, infrastructureSettings?: {
17
17
  write?: boolean;
18
- }, plugins?: Plugin[]): AsyncIterable<BuilderOutput & {
18
+ }, extensions?: ApplicationBuilderExtensions): AsyncIterable<ApplicationBuilderOutput>;
19
+ export interface ApplicationBuilderOutput extends BuilderOutput {
19
20
  outputFiles?: BuildOutputFile[];
20
21
  assetFiles?: {
21
22
  source: string;
22
23
  destination: string;
23
24
  }[];
24
- }>;
25
+ }
25
26
  /**
26
27
  * Builds an application using the `application` builder with the provided
27
28
  * options.
@@ -36,12 +37,21 @@ export declare function buildApplicationInternal(options: ApplicationBuilderInte
36
37
  * @param plugins An array of plugins to apply to the main code bundling.
37
38
  * @returns The build output results of the build.
38
39
  */
39
- export declare function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, plugins?: Plugin[]): AsyncIterable<BuilderOutput & {
40
- outputFiles?: BuildOutputFile[];
41
- assetFiles?: {
42
- source: string;
43
- destination: string;
44
- }[];
45
- }>;
40
+ export declare function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, plugins?: Plugin[]): AsyncIterable<ApplicationBuilderOutput>;
41
+ /**
42
+ * Builds an application using the `application` builder with the provided
43
+ * options.
44
+ *
45
+ * Usage of the `extensions` parameter is NOT supported and may cause unexpected
46
+ * build output or build failures.
47
+ *
48
+ * @experimental Direct usage of this function is considered experimental.
49
+ *
50
+ * @param options The options defined by the builder's schema to use.
51
+ * @param context An Architect builder context instance.
52
+ * @param extensions An object contain extension points for the build.
53
+ * @returns The build output results of the build.
54
+ */
55
+ export declare function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, extensions?: ApplicationBuilderExtensions): AsyncIterable<ApplicationBuilderOutput>;
46
56
  declare const _default: import("../../../../architect/src/internal").Builder<ApplicationBuilderOptions & import("../../../../core/src").JsonObject>;
47
57
  export default _default;
@@ -17,18 +17,38 @@ const execute_build_1 = require("./execute-build");
17
17
  const options_1 = require("./options");
18
18
  async function* buildApplicationInternal(options,
19
19
  // TODO: Integrate abort signal support into builder system
20
- context, infrastructureSettings, plugins) {
20
+ context, infrastructureSettings, extensions) {
21
+ const { workspaceRoot, logger, target } = context;
21
22
  // Check Angular version.
22
- (0, version_1.assertCompatibleAngularVersion)(context.workspaceRoot);
23
+ (0, version_1.assertCompatibleAngularVersion)(workspaceRoot);
23
24
  // Purge old build disk cache.
24
25
  await (0, purge_cache_1.purgeStaleBuildCache)(context);
25
26
  // Determine project name from builder context target
26
- const projectName = context.target?.project;
27
+ const projectName = target?.project;
27
28
  if (!projectName) {
28
- context.logger.error(`The 'application' builder requires a target to be specified.`);
29
+ yield { success: false, error: `The 'application' builder requires a target to be specified.` };
29
30
  return;
30
31
  }
31
- const normalizedOptions = await (0, options_1.normalizeOptions)(context, projectName, options, plugins);
32
+ const normalizedOptions = await (0, options_1.normalizeOptions)(context, projectName, options, extensions);
33
+ const writeToFileSystem = infrastructureSettings?.write ?? true;
34
+ const writeServerBundles = writeToFileSystem && !!(normalizedOptions.ssrOptions && normalizedOptions.serverEntryPoint);
35
+ if (writeServerBundles) {
36
+ const { browser, server } = normalizedOptions.outputOptions;
37
+ if (browser === '') {
38
+ yield {
39
+ success: false,
40
+ error: `'outputPath.browser' cannot be configured to an empty string when SSR is enabled.`,
41
+ };
42
+ return;
43
+ }
44
+ if (browser === server) {
45
+ yield {
46
+ success: false,
47
+ error: `'outputPath.browser' and 'outputPath.server' cannot be configured to the same value.`,
48
+ };
49
+ return;
50
+ }
51
+ }
32
52
  // Setup an abort controller with a builder teardown if no signal is present
33
53
  let signal = context.signal;
34
54
  if (!signal) {
@@ -41,7 +61,7 @@ context, infrastructureSettings, plugins) {
41
61
  const result = await (0, execute_build_1.executeBuild)(normalizedOptions, context, rebuildState);
42
62
  const buildTime = Number(process.hrtime.bigint() - startTime) / 10 ** 9;
43
63
  const status = result.errors.length > 0 ? 'failed' : 'complete';
44
- context.logger.info(`Application bundle generation ${status}. [${buildTime.toFixed(3)} seconds]`);
64
+ logger.info(`Application bundle generation ${status}. [${buildTime.toFixed(3)} seconds]`);
45
65
  return result;
46
66
  }, {
47
67
  watch: normalizedOptions.watch,
@@ -49,38 +69,30 @@ context, infrastructureSettings, plugins) {
49
69
  poll: normalizedOptions.poll,
50
70
  deleteOutputPath: normalizedOptions.deleteOutputPath,
51
71
  cacheOptions: normalizedOptions.cacheOptions,
52
- outputPath: normalizedOptions.outputPath,
72
+ outputOptions: normalizedOptions.outputOptions,
53
73
  verbose: normalizedOptions.verbose,
54
74
  projectRoot: normalizedOptions.projectRoot,
55
75
  workspaceRoot: normalizedOptions.workspaceRoot,
56
76
  progress: normalizedOptions.progress,
57
- writeToFileSystem: infrastructureSettings?.write,
77
+ writeToFileSystem,
58
78
  // For app-shell and SSG server files are not required by users.
59
79
  // Omit these when SSR is not enabled.
60
- writeToFileSystemFilter: normalizedOptions.ssrOptions && normalizedOptions.serverEntryPoint
80
+ writeToFileSystemFilter: writeServerBundles
61
81
  ? undefined
62
82
  : (file) => file.type !== bundler_context_1.BuildOutputFileType.Server,
63
- logger: context.logger,
83
+ logger,
64
84
  signal,
65
85
  });
66
86
  }
67
87
  exports.buildApplicationInternal = buildApplicationInternal;
68
- /**
69
- * Builds an application using the `application` builder with the provided
70
- * options.
71
- *
72
- * Usage of the `plugins` parameter is NOT supported and may cause unexpected
73
- * build output or build failures.
74
- *
75
- * @experimental Direct usage of this function is considered experimental.
76
- *
77
- * @param options The options defined by the builder's schema to use.
78
- * @param context An Architect builder context instance.
79
- * @param plugins An array of plugins to apply to the main code bundling.
80
- * @returns The build output results of the build.
81
- */
82
- function buildApplication(options, context, plugins) {
83
- return buildApplicationInternal(options, context, undefined, plugins);
88
+ function buildApplication(options, context, pluginsOrExtensions) {
89
+ let extensions;
90
+ if (pluginsOrExtensions && Array.isArray(pluginsOrExtensions)) {
91
+ extensions = {
92
+ codePlugins: pluginsOrExtensions,
93
+ };
94
+ }
95
+ return buildApplicationInternal(options, context, undefined, extensions);
84
96
  }
85
97
  exports.buildApplication = buildApplication;
86
98
  exports.default = (0, architect_1.createBuilder)(buildApplication);
@@ -8,8 +8,14 @@
8
8
  import { BuilderContext } from '@angular-devkit/architect';
9
9
  import type { Plugin } from 'esbuild';
10
10
  import { I18nOptions } from '../../utils/i18n-options';
11
- import { Schema as ApplicationBuilderOptions, I18NTranslation } from './schema';
11
+ import { IndexHtmlTransform } from '../../utils/index-file/index-html-generator';
12
+ import { Schema as ApplicationBuilderOptions, I18NTranslation, OutputPathClass } from './schema';
13
+ export type NormalizedOutputOptions = Required<OutputPathClass>;
12
14
  export type NormalizedApplicationBuildOptions = Awaited<ReturnType<typeof normalizeOptions>>;
15
+ export interface ApplicationBuilderExtensions {
16
+ codePlugins?: Plugin[];
17
+ indexHtmlTransformer?: IndexHtmlTransform;
18
+ }
13
19
  /** Internal options hidden from builder schema but available when invoked programmatically. */
14
20
  interface InternalOptions {
15
21
  /**
@@ -51,7 +57,7 @@ export type ApplicationBuilderInternalOptions = Omit<ApplicationBuilderOptions &
51
57
  * @param plugins An optional array of programmatically supplied build plugins.
52
58
  * @returns An object containing normalized options required to perform the build.
53
59
  */
54
- export declare function normalizeOptions(context: BuilderContext, projectName: string, options: ApplicationBuilderInternalOptions, plugins?: Plugin[]): Promise<{
60
+ export declare function normalizeOptions(context: BuilderContext, projectName: string, options: ApplicationBuilderInternalOptions, extensions?: ApplicationBuilderExtensions): Promise<{
55
61
  advancedOptimizations: boolean;
56
62
  allowedCommonJsDependencies: string[] | undefined;
57
63
  baseHref: string | undefined;
@@ -88,7 +94,7 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
88
94
  workspaceRoot: string;
89
95
  entryPoints: Record<string, string>;
90
96
  optimizationOptions: import("../../utils").NormalizedOptimizationOptions;
91
- outputPath: string;
97
+ outputOptions: Required<OutputPathClass>;
92
98
  outExtension: "js" | "mjs" | undefined;
93
99
  sourcemapOptions: import("../..").SourceMapObject;
94
100
  tsconfig: string;
@@ -114,6 +120,8 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
114
120
  input: string;
115
121
  output: string;
116
122
  insertionOrder: import("../../utils/package-chunk-sort").EntryPointsType[];
123
+ transformer: IndexHtmlTransform | undefined;
124
+ preloadInitial: boolean;
117
125
  } | undefined;
118
126
  tailwindConfiguration: {
119
127
  file: string;
@@ -35,7 +35,7 @@ const schema_1 = require("./schema");
35
35
  * @returns An object containing normalized options required to perform the build.
36
36
  */
37
37
  // eslint-disable-next-line max-lines-per-function
38
- async function normalizeOptions(context, projectName, options, plugins) {
38
+ async function normalizeOptions(context, projectName, options, extensions) {
39
39
  // If not explicitly set, default to the Node.js process argument
40
40
  const preserveSymlinks = options.preserveSymlinks ?? process.execArgv.includes('--preserve-symlinks');
41
41
  // Setup base paths based on workspace root and project information
@@ -59,20 +59,27 @@ async function normalizeOptions(context, projectName, options, plugins) {
59
59
  }
60
60
  const entryPoints = normalizeEntryPoints(workspaceRoot, options.browser, options.entryPoints);
61
61
  const tsconfig = node_path_1.default.join(workspaceRoot, options.tsConfig);
62
- const outputPath = normalizeDirectoryPath(node_path_1.default.join(workspaceRoot, options.outputPath));
63
62
  const optimizationOptions = (0, utils_1.normalizeOptimization)(options.optimization);
64
63
  const sourcemapOptions = (0, utils_1.normalizeSourceMaps)(options.sourceMap ?? false);
65
64
  const assets = options.assets?.length
66
65
  ? (0, utils_1.normalizeAssetPatterns)(options.assets, workspaceRoot, projectRoot, projectSourceRoot)
67
66
  : undefined;
67
+ const outputPath = options.outputPath;
68
+ const outputOptions = {
69
+ browser: 'browser',
70
+ server: 'server',
71
+ media: 'media',
72
+ ...(typeof outputPath === 'string' ? undefined : outputPath),
73
+ base: normalizeDirectoryPath(node_path_1.default.join(workspaceRoot, typeof outputPath === 'string' ? outputPath : outputPath.base)),
74
+ };
68
75
  const outputNames = {
69
76
  bundles: options.outputHashing === schema_1.OutputHashing.All || options.outputHashing === schema_1.OutputHashing.Bundles
70
77
  ? '[name]-[hash]'
71
78
  : '[name]',
72
- media: 'media/' +
79
+ media: outputOptions.media +
73
80
  (options.outputHashing === schema_1.OutputHashing.All || options.outputHashing === schema_1.OutputHashing.Media
74
- ? '[name]-[hash]'
75
- : '[name]'),
81
+ ? '/[name]-[hash]'
82
+ : '/[name]'),
76
83
  };
77
84
  let fileReplacements;
78
85
  if (options.fileReplacements) {
@@ -114,24 +121,6 @@ async function normalizeOptions(context, projectName, options, plugins) {
114
121
  globalScripts.push({ name: bundleName, files: paths, initial: inject });
115
122
  }
116
123
  }
117
- let tailwindConfiguration;
118
- const tailwindConfigurationPath = await (0, tailwind_1.findTailwindConfigurationFile)(workspaceRoot, projectRoot);
119
- if (tailwindConfigurationPath) {
120
- // Create a node resolver at the project root as a directory
121
- const resolver = (0, node_module_1.createRequire)(projectRoot + '/');
122
- try {
123
- tailwindConfiguration = {
124
- file: tailwindConfigurationPath,
125
- package: resolver.resolve('tailwindcss'),
126
- };
127
- }
128
- catch {
129
- const relativeTailwindConfigPath = node_path_1.default.relative(workspaceRoot, tailwindConfigurationPath);
130
- context.logger.warn(`Tailwind CSS configuration file found (${relativeTailwindConfigPath})` +
131
- ` but the 'tailwindcss' package is not installed.` +
132
- ` To enable Tailwind CSS, please install the 'tailwindcss' package.`);
133
- }
134
- }
135
124
  let indexHtmlOptions;
136
125
  // index can never have a value of `true` but in the schema it's of type `boolean`.
137
126
  if (typeof options.index !== 'boolean') {
@@ -144,6 +133,9 @@ async function normalizeOptions(context, projectName, options, plugins) {
144
133
  scripts: options.scripts ?? [],
145
134
  styles: options.styles ?? [],
146
135
  }),
136
+ transformer: extensions?.indexHtmlTransformer,
137
+ // Preload initial defaults to true
138
+ preloadInitial: typeof options.index !== 'object' || (options.index.preloadInitial ?? true),
147
139
  };
148
140
  }
149
141
  let serverEntryPoint;
@@ -208,7 +200,7 @@ async function normalizeOptions(context, projectName, options, plugins) {
208
200
  workspaceRoot,
209
201
  entryPoints,
210
202
  optimizationOptions,
211
- outputPath,
203
+ outputOptions,
212
204
  outExtension,
213
205
  sourcemapOptions,
214
206
  tsconfig,
@@ -220,16 +212,37 @@ async function normalizeOptions(context, projectName, options, plugins) {
220
212
  globalScripts,
221
213
  serviceWorker: typeof serviceWorker === 'string' ? node_path_1.default.join(workspaceRoot, serviceWorker) : undefined,
222
214
  indexHtmlOptions,
223
- tailwindConfiguration,
215
+ tailwindConfiguration: await getTailwindConfig(workspaceRoot, projectRoot, context),
224
216
  i18nOptions,
225
217
  namedChunks,
226
218
  budgets: budgets?.length ? budgets : undefined,
227
219
  publicPath: deployUrl ? deployUrl : undefined,
228
- plugins: plugins?.length ? plugins : undefined,
220
+ plugins: extensions?.codePlugins?.length ? extensions?.codePlugins : undefined,
229
221
  loaderExtensions,
230
222
  };
231
223
  }
232
224
  exports.normalizeOptions = normalizeOptions;
225
+ async function getTailwindConfig(workspaceRoot, projectRoot, context) {
226
+ const tailwindConfigurationPath = await (0, tailwind_1.findTailwindConfigurationFile)(workspaceRoot, projectRoot);
227
+ if (!tailwindConfigurationPath) {
228
+ return undefined;
229
+ }
230
+ // Create a node resolver at the project root as a directory
231
+ const resolver = (0, node_module_1.createRequire)(projectRoot + '/');
232
+ try {
233
+ return {
234
+ file: tailwindConfigurationPath,
235
+ package: resolver.resolve('tailwindcss'),
236
+ };
237
+ }
238
+ catch {
239
+ const relativeTailwindConfigPath = node_path_1.default.relative(workspaceRoot, tailwindConfigurationPath);
240
+ context.logger.warn(`Tailwind CSS configuration file found (${relativeTailwindConfigPath})` +
241
+ ` but the 'tailwindcss' package is not installed.` +
242
+ ` To enable Tailwind CSS, please install the 'tailwindcss' package.`);
243
+ }
244
+ return undefined;
245
+ }
233
246
  /**
234
247
  * Normalize entry point options. To maintain compatibility with the legacy browser builder, we need a single `browser`
235
248
  * option which defines a single entry point. However, we also want to support multiple entry points as an internal option.
@@ -99,9 +99,9 @@ export interface Schema {
99
99
  */
100
100
  outputHashing?: OutputHashing;
101
101
  /**
102
- * The full path for the new output directory, relative to the current workspace.
102
+ * Specify the output path relative to workspace root.
103
103
  */
104
- outputPath: string;
104
+ outputPath: OutputPathUnion;
105
105
  /**
106
106
  * Enable and define the file watching poll time period in milliseconds.
107
107
  */
@@ -290,6 +290,11 @@ export interface IndexObject {
290
290
  * will be used and will be considered relative to the application's configured output path.
291
291
  */
292
292
  output?: string;
293
+ /**
294
+ * Generates 'preload', `modulepreload', and 'preconnect' link elements for initial
295
+ * application files and resources.
296
+ */
297
+ preloadInitial?: boolean;
293
298
  [property: string]: any;
294
299
  }
295
300
  /**
@@ -369,6 +374,31 @@ export declare enum OutputHashing {
369
374
  Media = "media",
370
375
  None = "none"
371
376
  }
377
+ /**
378
+ * Specify the output path relative to workspace root.
379
+ */
380
+ export type OutputPathUnion = OutputPathClass | string;
381
+ export interface OutputPathClass {
382
+ /**
383
+ * Specify the output path relative to workspace root.
384
+ */
385
+ base: string;
386
+ /**
387
+ * The output directory name of your browser build within the output path base. Defaults to
388
+ * 'browser'.
389
+ */
390
+ browser?: string;
391
+ /**
392
+ * The output directory name of your media files within the output browser directory.
393
+ * Defaults to 'media'.
394
+ */
395
+ media?: string;
396
+ /**
397
+ * The output directory name of your server build within the output path base. Defaults to
398
+ * 'server'.
399
+ */
400
+ server?: string;
401
+ }
372
402
  /**
373
403
  * Prerender (SSG) pages of your application during build time.
374
404
  */
@@ -220,8 +220,41 @@
220
220
  "default": []
221
221
  },
222
222
  "outputPath": {
223
- "type": "string",
224
- "description": "The full path for the new output directory, relative to the current workspace."
223
+ "description": "Specify the output path relative to workspace root.",
224
+ "oneOf": [
225
+ {
226
+ "type": "object",
227
+ "properties": {
228
+ "base": {
229
+ "type": "string",
230
+ "description": "Specify the output path relative to workspace root."
231
+ },
232
+ "browser": {
233
+ "type": "string",
234
+ "pattern": "^[-\\w\\.]*$",
235
+ "default": "browser",
236
+ "description": "The output directory name of your browser build within the output path base. Defaults to 'browser'."
237
+ },
238
+ "server": {
239
+ "type": "string",
240
+ "pattern": "^[-\\w\\.]*$",
241
+ "default": "server",
242
+ "description": "The output directory name of your server build within the output path base. Defaults to 'server'."
243
+ },
244
+ "media": {
245
+ "type": "string",
246
+ "pattern": "^[-\\w\\.]+$",
247
+ "default": "media",
248
+ "description": "The output directory name of your media files within the output browser directory. Defaults to 'media'."
249
+ }
250
+ },
251
+ "required": ["base"],
252
+ "additionalProperties": false
253
+ },
254
+ {
255
+ "type": "string"
256
+ }
257
+ ]
225
258
  },
226
259
  "aot": {
227
260
  "type": "boolean",
@@ -383,6 +416,11 @@
383
416
  "minLength": 1,
384
417
  "default": "index.html",
385
418
  "description": "The output path of the application's generated HTML index file. The full provided path will be used and will be considered relative to the application's configured output path."
419
+ },
420
+ "preloadInitial": {
421
+ "type": "boolean",
422
+ "default": true,
423
+ "description": "Generates 'preload', `modulepreload', and 'preconnect' link elements for initial application files and resources."
386
424
  }
387
425
  },
388
426
  "required": ["input"]