@nx/angular 23.2.1 → 23.3.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/src/generators/application/application.js +1 -10
  2. package/dist/src/generators/component-test/component-test.js +8 -2
  3. package/dist/src/generators/convert-to-rspack/convert-to-rspack.js +23 -0
  4. package/dist/src/generators/convert-to-rspack/lib/merge-server-tsconfig.d.ts +8 -0
  5. package/dist/src/generators/convert-to-rspack/lib/merge-server-tsconfig.js +91 -0
  6. package/dist/src/generators/cypress-component-configuration/cypress-component-configuration.js +14 -8
  7. package/dist/src/generators/host/files/common/src/main.server.ts__tmpl__ +5 -1
  8. package/dist/src/generators/host/lib/update-ssr-setup.js +1 -0
  9. package/dist/src/generators/remote/files/common/src/main.server.ts__tmpl__ +5 -1
  10. package/dist/src/generators/remote/lib/update-ssr-setup.js +1 -0
  11. package/dist/src/generators/setup-ssr/files/v20+/server-builder/server/__serverFileName__ +5 -1
  12. package/dist/src/generators/setup-ssr/lib/add-dependencies.d.ts +2 -1
  13. package/dist/src/generators/setup-ssr/lib/add-dependencies.js +11 -7
  14. package/dist/src/generators/setup-ssr/lib/add-server-file.js +14 -6
  15. package/dist/src/generators/setup-ssr/lib/constants.d.ts +1 -0
  16. package/dist/src/generators/setup-ssr/lib/constants.js +2 -1
  17. package/dist/src/generators/setup-ssr/lib/generate-files.js +1 -1
  18. package/dist/src/generators/setup-ssr/lib/generate-server-ts-config.d.ts +1 -1
  19. package/dist/src/generators/setup-ssr/lib/generate-server-ts-config.js +6 -6
  20. package/dist/src/generators/setup-ssr/lib/normalize-options.js +1 -0
  21. package/dist/src/generators/setup-ssr/lib/update-project-config.js +7 -0
  22. package/dist/src/generators/setup-ssr/schema.d.ts +6 -0
  23. package/dist/src/generators/setup-ssr/setup-ssr.js +8 -2
  24. package/dist/src/generators/utils/tsconfig-utils.d.ts +6 -0
  25. package/dist/src/generators/utils/tsconfig-utils.js +14 -0
  26. package/dist/src/generators/utils/version-utils.d.ts +14 -0
  27. package/dist/src/generators/utils/version-utils.js +52 -0
  28. package/dist/src/utils/assert-cypress-component-testing-support.d.ts +11 -0
  29. package/dist/src/utils/assert-cypress-component-testing-support.js +36 -11
  30. package/dist/src/utils/versions.d.ts +1 -1
  31. package/dist/src/utils/versions.js +1 -1
  32. package/migrations.json +12 -0
  33. package/package.json +13 -13
  34. package/dist/src/generators/application/files/rspack-ssr/server.ts__tmpl__ +0 -78
@@ -57,6 +57,7 @@ async function applicationGenerator(tree, schema) {
57
57
  project: options.name,
58
58
  standalone: options.standalone,
59
59
  skipPackageJson: options.skipPackageJson,
60
+ isRspack,
60
61
  });
61
62
  }
62
63
  if (isRspack) {
@@ -65,16 +66,6 @@ async function applicationGenerator(tree, schema) {
65
66
  skipInstall: options.skipPackageJson,
66
67
  skipFormat: true,
67
68
  });
68
- if (options.ssr) {
69
- const { major: angularMajorVersion } = (0, version_utils_1.getInstalledAngularVersionInfo)(tree);
70
- (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, './files/rspack-ssr'), options.appProjectSourceRoot, {
71
- pathToDistFolder: (0, devkit_1.joinPathFragments)((0, devkit_1.offsetFromRoot)(options.appProjectRoot), options.outputPath, 'browser'),
72
- zoneless: options.zoneless,
73
- useDefaultImport: angularMajorVersion >= 21,
74
- angularMajorVersion,
75
- tmpl: '',
76
- });
77
- }
78
69
  }
79
70
  if (!options.skipPackageJson) {
80
71
  const devDependencies = {};
@@ -27,8 +27,7 @@ async function componentTestGenerator(tree, options) {
27
27
  });
28
28
  }
29
29
  const tasks = [];
30
- if (!options.skipPackageJson) {
31
- // Cypress CT still requires @angular/platform-browser-dynamic
30
+ if (!options.skipPackageJson && usesPlatformBrowserDynamic(tree)) {
32
31
  tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
33
32
  '@angular/platform-browser-dynamic': (0, version_utils_1.versions)(tree).angularVersion,
34
33
  }, undefined, true));
@@ -38,4 +37,11 @@ async function componentTestGenerator(tree, options) {
38
37
  }
39
38
  return (0, devkit_1.runTasksInSerial)(...tasks);
40
39
  }
40
+ // The Cypress 16 harness bootstraps through @angular/platform-browser/testing;
41
+ // earlier harnesses need @angular/platform-browser-dynamic/testing.
42
+ function usesPlatformBrowserDynamic(tree) {
43
+ const { getInstalledCypressMajorVersion, } = require('@nx/cypress/internal');
44
+ const cypressMajorVersion = getInstalledCypressMajorVersion(tree);
45
+ return cypressMajorVersion !== null && cypressMajorVersion < 16;
46
+ }
41
47
  exports.default = componentTestGenerator;
@@ -10,6 +10,7 @@ const versions_1 = require("../../utils/versions");
10
10
  const version_utils_1 = require("../utils/version-utils");
11
11
  const create_config_1 = require("./lib/create-config");
12
12
  const get_custom_webpack_config_1 = require("./lib/get-custom-webpack-config");
13
+ const merge_server_tsconfig_1 = require("./lib/merge-server-tsconfig");
13
14
  const update_tsconfig_1 = require("./lib/update-tsconfig");
14
15
  const validate_supported_executor_1 = require("./lib/validate-supported-executor");
15
16
  const SUPPORTED_EXECUTORS = [
@@ -244,6 +245,8 @@ async function convertToRspack(tree, schema) {
244
245
  const configurationOptions = {};
245
246
  let buildTarget;
246
247
  let serveTarget;
248
+ const buildTsConfigPaths = new Set();
249
+ let serverTsConfigPath;
247
250
  const targetsToRemove = [];
248
251
  let customWebpackConfigPath;
249
252
  (0, validate_supported_executor_1.validateSupportedBuildExecutor)(Object.values(project.targets));
@@ -253,10 +256,16 @@ async function convertToRspack(tree, schema) {
253
256
  if (target.executor === '@angular-devkit/build-angular:browser' ||
254
257
  target.executor === '@nx/angular:webpack-browser') {
255
258
  customWebpackConfigPath = handleBuildTargetOptions(tree, target.options, createConfigOptions, project.root);
259
+ if (target.options?.tsConfig) {
260
+ buildTsConfigPaths.add((0, devkit_1.joinPathFragments)(target.options.tsConfig));
261
+ }
256
262
  if (target.configurations) {
257
263
  for (const [configurationName, configuration] of Object.entries(target.configurations)) {
258
264
  configurationOptions[configurationName] = {};
259
265
  handleBuildTargetOptions(tree, configuration, configurationOptions[configurationName], project.root);
266
+ if (configuration.tsConfig) {
267
+ buildTsConfigPaths.add((0, devkit_1.joinPathFragments)(configuration.tsConfig));
268
+ }
260
269
  }
261
270
  }
262
271
  buildTarget = { name: targetName, config: target };
@@ -267,6 +276,10 @@ async function convertToRspack(tree, schema) {
267
276
  createConfigOptions.ssr ??= {};
268
277
  createConfigOptions.ssr.entry ??= normalizeFromProjectRoot(tree, target.options.main, project.root);
269
278
  createConfigOptions.server = './src/main.server.ts';
279
+ serverTsConfigPath = target.options?.tsConfig
280
+ ? // each target can spell the same path differently
281
+ (0, devkit_1.joinPathFragments)(target.options.tsConfig)
282
+ : undefined;
270
283
  targetsToRemove.push(targetName);
271
284
  }
272
285
  else if (target.executor === '@angular-devkit/build-angular:dev-server' ||
@@ -320,11 +333,21 @@ async function convertToRspack(tree, schema) {
320
333
  targetsToRemove.push(targetName);
321
334
  }
322
335
  }
336
+ if (createConfigOptions.ssr && (0, version_utils_1.supportsSsrAllowedHosts)(tree)) {
337
+ // The engine matches the request host against this list and an unset list
338
+ // matches nothing, so surface it for the deployment to fill in. Serving
339
+ // seeds its own hosts and does not read it.
340
+ createConfigOptions.security ??= {};
341
+ createConfigOptions.security.allowedHosts ??= [];
342
+ }
323
343
  const customWebpackConfigInfo = customWebpackConfigPath
324
344
  ? await (0, get_custom_webpack_config_1.getCustomWebpackConfig)(tree, project.root, customWebpackConfigPath)
325
345
  : undefined;
326
346
  (0, create_config_1.createConfig)(tree, createConfigOptions, configurationOptions, customWebpackConfigInfo?.normalizedPathToCustomWebpackConfig, customWebpackConfigInfo?.isWebpackConfigFunction);
327
347
  (0, update_tsconfig_1.updateTsconfig)(tree, project.root);
348
+ if (serverTsConfigPath) {
349
+ (0, merge_server_tsconfig_1.mergeServerTsConfig)(tree, project.root, serverTsConfigPath, buildTsConfigPaths);
350
+ }
328
351
  for (const targetName of targetsToRemove) {
329
352
  delete project.targets[targetName];
330
353
  }
@@ -0,0 +1,8 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ /**
3
+ * Folds the tsconfig the server builder used into every tsconfig the rspack
4
+ * build compiles with. The rspack build compiles the browser and the server
5
+ * bundles from a single tsconfig, so the server sources have to be part of it.
6
+ * The server tsconfig is then deleted, unless a build target also points at it.
7
+ */
8
+ export declare function mergeServerTsConfig(tree: Tree, projectRoot: string, serverTsConfigPath: string, buildTsConfigPaths: Set<string>): void;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mergeServerTsConfig = mergeServerTsConfig;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const posix_1 = require("path/posix");
6
+ const constants_1 = require("../../setup-ssr/lib/constants");
7
+ const tsconfig_utils_1 = require("../../utils/tsconfig-utils");
8
+ /**
9
+ * Folds the tsconfig the server builder used into every tsconfig the rspack
10
+ * build compiles with. The rspack build compiles the browser and the server
11
+ * bundles from a single tsconfig, so the server sources have to be part of it.
12
+ * The server tsconfig is then deleted, unless a build target also points at it.
13
+ */
14
+ function mergeServerTsConfig(tree, projectRoot, serverTsConfigPath, buildTsConfigPaths) {
15
+ if (!tree.exists(serverTsConfigPath)) {
16
+ return;
17
+ }
18
+ const serverTsConfig = (0, tsconfig_utils_1.readResolvedTsConfig)(tree, serverTsConfigPath);
19
+ const serverTsConfigDir = (0, posix_1.dirname)(serverTsConfigPath);
20
+ // entries in each tsconfig are relative to it, so compare them from the
21
+ // workspace root and write them back relative to the tsconfig receiving them
22
+ const serverEntries = (serverTsConfig.raw.files ?? []).map((file) => (0, devkit_1.joinPathFragments)(serverTsConfigDir, file));
23
+ const serverSources = new Set([
24
+ ...serverEntries,
25
+ // excluded alongside the server entries, and reachable from them
26
+ (0, devkit_1.joinPathFragments)(projectRoot, constants_1.SERVER_APP_CONFIG_FILE),
27
+ ]);
28
+ for (const buildTsConfigPath of buildTsConfigPaths) {
29
+ // the server entries come from this tsconfig, so folding it into itself
30
+ // would only rewrite what it already declares
31
+ if (buildTsConfigPath === serverTsConfigPath ||
32
+ !tree.exists(buildTsConfigPath)) {
33
+ continue;
34
+ }
35
+ const buildTsConfigDir = (0, posix_1.dirname)(buildTsConfigPath);
36
+ (0, devkit_1.updateJson)(tree, buildTsConfigPath, (json) => {
37
+ if (json.exclude) {
38
+ json.exclude = json.exclude.filter((pattern) => !serverSources.has((0, devkit_1.joinPathFragments)(buildTsConfigDir, pattern)));
39
+ }
40
+ return json;
41
+ });
42
+ // `files`, `include`, `exclude` and `types` are all inherited through
43
+ // `extends`, so what the build tsconfig compiles is only visible with the
44
+ // chain applied, and the entries it contributes have to be kept when this
45
+ // config takes them over
46
+ const { raw, options } = (0, tsconfig_utils_1.readResolvedTsConfig)(tree, buildTsConfigPath);
47
+ // `exclude` cannot drop a `files` entry, so list the server sources instead
48
+ // of working out whether the config's globs already reach them. A config
49
+ // declaring none of the three takes everything beside it, which already
50
+ // covers entries sitting there.
51
+ const mustListServerEntries = !!raw.files ||
52
+ !!raw.include ||
53
+ !!raw.exclude ||
54
+ serverEntries.some((entry) => (0, posix_1.relative)(buildTsConfigDir, entry).startsWith('../'));
55
+ const types = new Set([
56
+ ...(options.types ?? []),
57
+ ...(serverTsConfig.options.types ?? []),
58
+ ]);
59
+ (0, devkit_1.updateJson)(tree, buildTsConfigPath, (json) => {
60
+ if (mustListServerEntries) {
61
+ const inheritedEntries = (raw.files ?? []).map((file) => (0, devkit_1.joinPathFragments)(buildTsConfigDir, file));
62
+ json.files = Array.from(new Set([...inheritedEntries, ...serverEntries])).map((entry) => (0, posix_1.relative)(buildTsConfigDir, entry));
63
+ }
64
+ if (types.size) {
65
+ json.compilerOptions ??= {};
66
+ json.compilerOptions.types = Array.from(types);
67
+ }
68
+ return json;
69
+ });
70
+ }
71
+ // a build target or one of its configurations can point at the tsconfig the
72
+ // server target used, and the rspack build still compiles with it
73
+ if (buildTsConfigPaths.has(serverTsConfigPath)) {
74
+ return;
75
+ }
76
+ tree.delete(serverTsConfigPath);
77
+ const projectTsConfigPath = (0, devkit_1.joinPathFragments)(projectRoot, 'tsconfig.json');
78
+ if (!tree.exists(projectTsConfigPath)) {
79
+ return;
80
+ }
81
+ (0, devkit_1.updateJson)(tree, projectTsConfigPath, (json) => {
82
+ if (json.references) {
83
+ json.references = json.references.filter((reference) => (0, devkit_1.joinPathFragments)(projectRoot, reference.path) !==
84
+ serverTsConfigPath &&
85
+ // setups generated before the reference path was corrected wrote it
86
+ // relative to the workspace root
87
+ reference.path !== serverTsConfigPath);
88
+ }
89
+ return json;
90
+ });
91
+ }
@@ -43,15 +43,21 @@ async function cypressComponentConfiguration(tree, options) {
43
43
  // For libraries, check if zone.js is installed in the workspace
44
44
  isZoneless = (0, devkit_1.getDependencyVersionFromPackageJson)(tree, 'zone.js') === null;
45
45
  }
46
+ // Cypress 16 dropped `cypress/angular-zoneless`; `cypress/angular` is zoneless there.
47
+ let mountModule = 'cypress/angular';
46
48
  if (isZoneless) {
47
49
  const { getInstalledCypressVersion, } = require('@nx/cypress/internal');
48
50
  const installedCypressVersion = getInstalledCypressVersion(tree);
49
- // Zoneless support was introduced in Cypress 15.8.0
50
51
  // If Cypress is not yet installed, we'll install the latest version, which will have zoneless support
51
- if (installedCypressVersion && (0, semver_1.lt)(installedCypressVersion, '15.8.0')) {
52
- throw new Error(`Cypress Component Testing doesn't support Zoneless Angular projects for your installed Cypress version (${installedCypressVersion}). ` +
53
- `The project "${options.project}" is configured without Zone.js. ` +
54
- `Please upgrade Cypress to version 15.8.0 or higher.`);
52
+ if (installedCypressVersion && (0, semver_1.major)(installedCypressVersion) < 16) {
53
+ // Zoneless support was introduced in Cypress 15.8.0
54
+ const unsupportedCypressVersion = (0, assert_cypress_component_testing_support_1.findCypressBelow)(tree, '15.8.0');
55
+ if (unsupportedCypressVersion) {
56
+ throw new Error(`Cypress Component Testing doesn't support Zoneless Angular projects for your Cypress version (${unsupportedCypressVersion}). ` +
57
+ `The project "${options.project}" is configured without Zone.js. ` +
58
+ `Please upgrade Cypress to version 15.8.0 or higher.`);
59
+ }
60
+ mountModule = 'cypress/angular-zoneless';
55
61
  }
56
62
  }
57
63
  const tasks = [];
@@ -63,7 +69,7 @@ async function cypressComponentConfiguration(tree, options) {
63
69
  skipPackageJson: options.skipPackageJson,
64
70
  }));
65
71
  await configureCypressCT(tree, options);
66
- tasks.push(await addFiles(tree, projectConfig, options, isZoneless));
72
+ tasks.push(await addFiles(tree, projectConfig, options, mountModule));
67
73
  if (projectConfig.projectType === 'application') {
68
74
  (0, update_app_editor_tsconfig_excluded_files_1.updateAppEditorTsConfigExcludedFiles)(tree, projectConfig);
69
75
  }
@@ -72,11 +78,11 @@ async function cypressComponentConfiguration(tree, options) {
72
78
  }
73
79
  return (0, devkit_1.runTasksInSerial)(...tasks);
74
80
  }
75
- async function addFiles(tree, projectConfig, options, isZoneless) {
81
+ async function addFiles(tree, projectConfig, options, mountModule) {
76
82
  const componentFile = (0, devkit_1.joinPathFragments)(projectConfig.root, 'cypress', 'support', 'component.ts');
77
83
  const { addMountDefinition } = (require('@nx/cypress/internal'));
78
84
  const updatedCmpContents = await addMountDefinition(tree.read(componentFile, 'utf-8'));
79
- tree.write(componentFile, `import { mount } from '${isZoneless ? 'cypress/angular-zoneless' : 'cypress/angular'}';\n${updatedCmpContents}`);
85
+ tree.write(componentFile, `import { mount } from '${mountModule}';\n${updatedCmpContents}`);
80
86
  if (!options.generateTests) {
81
87
  return () => { };
82
88
  }
@@ -25,7 +25,11 @@ export function app(): express.Express {
25
25
 
26
26
  server.use(cors());
27
27
 
28
- const commonEngine = new CommonEngine();
28
+ const commonEngine = new CommonEngine(<%_ if (supportsAllowedHosts) { _%>{
29
+ // The engine rejects any host that is not listed here. Add the hosts this
30
+ // server is reached through before deploying it, or set NG_ALLOWED_HOSTS.
31
+ allowedHosts: ['localhost', '127.0.0.1', '[::1]'],
32
+ }<%_ } _%>);
29
33
 
30
34
  server.set('view engine', 'html');
31
35
  server.set('views', distFolder);
@@ -20,6 +20,7 @@ async function updateSsrSetup(tree, options, appName, typescriptConfiguration) {
20
20
  zoneless: options.zoneless,
21
21
  useDefaultImport: angularMajorVersion >= 21,
22
22
  angularMajorVersion,
23
+ supportsAllowedHosts: (0, version_utils_1.supportsSsrAllowedHosts)(tree),
23
24
  tmpl: '',
24
25
  });
25
26
  const pathToTemplateFiles = typescriptConfiguration ? 'ts' : 'js';
@@ -26,7 +26,11 @@ export function app(): express.Express {
26
26
 
27
27
  server.use(cors());
28
28
 
29
- const commonEngine = new CommonEngine();
29
+ const commonEngine = new CommonEngine(<%_ if (supportsAllowedHosts) { _%>{
30
+ // The engine rejects any host that is not listed here. Add the hosts this
31
+ // server is reached through before deploying it, or set NG_ALLOWED_HOSTS.
32
+ allowedHosts: ['localhost', '127.0.0.1', '[::1]'],
33
+ }<%_ } _%>);
30
34
 
31
35
  server.set('view engine', 'html');
32
36
  server.set('views', browserBundles);
@@ -25,6 +25,7 @@ async function updateSsrSetup(tree, { appName, port, standalone, typescriptConfi
25
25
  zoneless,
26
26
  useDefaultImport: angularMajorVersion >= 21,
27
27
  angularMajorVersion,
28
+ supportsAllowedHosts: (0, version_utils_1.supportsSsrAllowedHosts)(tree),
28
29
  tmpl: '',
29
30
  });
30
31
  const pathToTemplateFiles = typescriptConfiguration ? 'base-ts' : 'base';
@@ -21,7 +21,11 @@ export function app(): express.Express {
21
21
  ? join(distFolder, 'index.original.html')
22
22
  : join(distFolder, 'index.html');
23
23
 
24
- const commonEngine = new CommonEngine();
24
+ const commonEngine = new CommonEngine(<%_ if (supportsAllowedHosts) { _%>{
25
+ // The engine rejects any host that is not listed here. Add the hosts this
26
+ // server is reached through before deploying it, or set NG_ALLOWED_HOSTS.
27
+ allowedHosts: ['localhost', '127.0.0.1', '[::1]'],
28
+ }<%_ } _%>);
25
29
 
26
30
  server.set('view engine', 'html');
27
31
  server.set('views', distFolder);
@@ -1,2 +1,3 @@
1
1
  import { type Tree } from '@nx/devkit';
2
- export declare function addDependencies(tree: Tree, isUsingApplicationBuilder: boolean, isUsingWebpackBuilder: boolean): void;
2
+ import type { NormalizedGeneratorOptions } from '../schema';
3
+ export declare function addDependencies(tree: Tree, options: NormalizedGeneratorOptions): void;
@@ -4,7 +4,7 @@ exports.addDependencies = addDependencies;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const versions_1 = require("../../../utils/versions");
6
6
  const version_utils_1 = require("../../utils/version-utils");
7
- function addDependencies(tree, isUsingApplicationBuilder, isUsingWebpackBuilder) {
7
+ function addDependencies(tree, options) {
8
8
  const pkgVersions = (0, version_utils_1.versions)(tree);
9
9
  const dependencies = {
10
10
  '@angular/platform-server': (0, devkit_1.getDependencyVersionFromPackageJson)(tree, '@angular/platform-server') ??
@@ -16,16 +16,20 @@ function addDependencies(tree, isUsingApplicationBuilder, isUsingWebpackBuilder)
16
16
  '@types/node': pkgVersions.typesNodeVersion,
17
17
  };
18
18
  const angularDevkitVersion = (0, version_utils_1.getInstalledAngularDevkitVersion)(tree) ?? pkgVersions.angularDevkitVersion;
19
- dependencies['@angular/ssr'] = angularDevkitVersion;
20
- if (!isUsingApplicationBuilder) {
19
+ // The setup below configures the allowed hosts when the version allows it,
20
+ // so ask for one that does rather than for whichever the range resolves to
21
+ dependencies['@angular/ssr'] =
22
+ (0, version_utils_1.withSsrAllowedHostsSupport)(angularDevkitVersion);
23
+ if (options.isUsingApplicationBuilder) {
24
+ dependencies['@angular-devkit/build-angular'] = angularDevkitVersion;
25
+ }
26
+ else if (!options.isRspack) {
27
+ // The rspack conversion removes the targets that use these packages
21
28
  devDependencies['browser-sync'] = pkgVersions.browserSyncVersion;
22
- if (isUsingWebpackBuilder) {
29
+ if (options.isUsingWebpackBuilder) {
23
30
  devDependencies['@nx/webpack'] = versions_1.nxVersion;
24
31
  devDependencies['webpack-merge'] = pkgVersions.webpackMergeVersion;
25
32
  }
26
33
  }
27
- else {
28
- dependencies['@angular-devkit/build-angular'] = angularDevkitVersion;
29
- }
30
34
  (0, devkit_1.addDependenciesToPackageJson)(tree, dependencies, devDependencies, undefined, true);
31
35
  }
@@ -10,13 +10,20 @@ const constants_1 = require("./constants");
10
10
  function addServerFile(tree, options) {
11
11
  const project = (0, devkit_1.readProjectConfiguration)(tree, options.project);
12
12
  const { outputPath } = project.targets.build.options;
13
- const browserDistDirectory = options.isUsingApplicationBuilder
14
- ? getApplicationBuilderBrowserOutputPath(outputPath)
15
- : outputPath;
13
+ const usesApplicationEngine = options.isUsingApplicationBuilder || options.isRspack;
14
+ let browserDistDirectory;
15
+ if (options.isRspack) {
16
+ // rspack always emits the browser bundle under the default directory name
17
+ browserDistDirectory = constants_1.DEFAULT_BROWSER_DIR;
18
+ }
19
+ else if (options.isUsingApplicationBuilder) {
20
+ browserDistDirectory = getApplicationBuilderBrowserOutputPath(outputPath);
21
+ }
22
+ else {
23
+ browserDistDirectory = outputPath;
24
+ }
16
25
  const { major: angularMajorVersion } = (0, version_utils_1.getInstalledAngularVersionInfo)(tree);
17
- const pathToFiles = (0, path_1.join)(__dirname, '..', 'files', 'v20+', options.isUsingApplicationBuilder
18
- ? 'application-builder'
19
- : 'server-builder', 'server');
26
+ const pathToFiles = (0, path_1.join)(__dirname, '..', 'files', 'v20+', usesApplicationEngine ? 'application-builder' : 'server-builder', 'server');
20
27
  const sourceRoot = (0, internal_1.getProjectSourceRoot)(project, tree);
21
28
  const zoneless = (0, zoneless_1.isZonelessApp)(project);
22
29
  (0, devkit_1.generateFiles)(tree, pathToFiles, sourceRoot, {
@@ -25,6 +32,7 @@ function addServerFile(tree, options) {
25
32
  zoneless,
26
33
  useDefaultImport: angularMajorVersion >= 21,
27
34
  angularMajorVersion,
35
+ supportsAllowedHosts: (0, version_utils_1.supportsSsrAllowedHosts)(tree),
28
36
  tpl: '',
29
37
  });
30
38
  }
@@ -1,3 +1,4 @@
1
1
  export declare const DEFAULT_BROWSER_DIR = "browser";
2
2
  export declare const DEFAULT_MEDIA_DIR = "media";
3
3
  export declare const DEFAULT_SERVER_DIR = "server";
4
+ export declare const SERVER_APP_CONFIG_FILE = "src/app/app.config.server.ts";
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_SERVER_DIR = exports.DEFAULT_MEDIA_DIR = exports.DEFAULT_BROWSER_DIR = void 0;
3
+ exports.SERVER_APP_CONFIG_FILE = exports.DEFAULT_SERVER_DIR = exports.DEFAULT_MEDIA_DIR = exports.DEFAULT_BROWSER_DIR = void 0;
4
4
  exports.DEFAULT_BROWSER_DIR = 'browser';
5
5
  exports.DEFAULT_MEDIA_DIR = 'media';
6
6
  exports.DEFAULT_SERVER_DIR = 'server';
7
+ exports.SERVER_APP_CONFIG_FILE = 'src/app/app.config.server.ts';
@@ -17,7 +17,7 @@ function generateSSRFiles(tree, options) {
17
17
  return;
18
18
  }
19
19
  const { version: angularVersion } = (0, version_utils_1.getInstalledAngularVersionInfo)(tree);
20
- const pathToFiles = (0, path_1.join)(__dirname, '..', 'files', 'v20+', options.isUsingApplicationBuilder
20
+ const pathToFiles = (0, path_1.join)(__dirname, '..', 'files', 'v20+', options.isUsingApplicationBuilder || options.isRspack
21
21
  ? 'application-builder'
22
22
  : 'server-builder', options.standalone ? 'standalone-src' : 'ngmodule-src');
23
23
  const sourceRoot = (0, internal_1.getProjectSourceRoot)(project, tree);
@@ -1,4 +1,4 @@
1
1
  import { type Tree } from '@nx/devkit';
2
2
  import type { NormalizedGeneratorOptions } from '../schema';
3
- export declare function setServerTsConfigOptionsForApplicationBuilder(tree: Tree, options: NormalizedGeneratorOptions): void;
3
+ export declare function setServerTsConfigOptionsForSingleProgramBuild(tree: Tree, options: NormalizedGeneratorOptions): void;
4
4
  export declare function generateTsConfigServerJsonForBrowserBuilder(tree: Tree, options: NormalizedGeneratorOptions): void;
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setServerTsConfigOptionsForApplicationBuilder = setServerTsConfigOptionsForApplicationBuilder;
3
+ exports.setServerTsConfigOptionsForSingleProgramBuild = setServerTsConfigOptionsForSingleProgramBuild;
4
4
  exports.generateTsConfigServerJsonForBrowserBuilder = generateTsConfigServerJsonForBrowserBuilder;
5
5
  const devkit_1 = require("@nx/devkit");
6
6
  const internal_1 = require("@nx/js/internal");
7
7
  const path_1 = require("path");
8
8
  const tsconfig_utils_1 = require("../../utils/tsconfig-utils");
9
9
  const version_utils_1 = require("../../utils/version-utils");
10
- function setServerTsConfigOptionsForApplicationBuilder(tree, options) {
10
+ const constants_1 = require("./constants");
11
+ function setServerTsConfigOptionsForSingleProgramBuild(tree, options) {
11
12
  const { targets } = (0, devkit_1.readProjectConfiguration)(tree, options.project);
12
13
  const tsConfigPath = targets.build.options.tsConfig;
13
14
  (0, devkit_1.updateJson)(tree, tsConfigPath, (json) => {
@@ -42,9 +43,8 @@ function generateTsConfigServerJsonForBrowserBuilder(tree, options) {
42
43
  const tsconfigServerPath = (0, devkit_1.joinPathFragments)(project.root, 'tsconfig.server.json');
43
44
  (0, devkit_1.updateJson)(tree, (0, devkit_1.joinPathFragments)(project.root, 'tsconfig.json'), (json) => {
44
45
  json.references ??= [];
45
- json.references.push({
46
- path: tsconfigServerPath,
47
- });
46
+ // TypeScript resolves a reference relative to the file declaring it
47
+ json.references.push({ path: './tsconfig.server.json' });
48
48
  return json;
49
49
  });
50
50
  (0, devkit_1.updateJson)(tree, options.buildTargetTsConfigPath, (json) => {
@@ -52,7 +52,7 @@ function generateTsConfigServerJsonForBrowserBuilder(tree, options) {
52
52
  exclude.add(`src/${options.main}`);
53
53
  exclude.add(`src/${options.serverFileName}`);
54
54
  if (options.standalone) {
55
- exclude.add('src/app/app.config.server.ts');
55
+ exclude.add(constants_1.SERVER_APP_CONFIG_FILE);
56
56
  }
57
57
  json.exclude = Array.from(exclude);
58
58
  return json;
@@ -32,6 +32,7 @@ async function normalizeOptions(tree, options) {
32
32
  hydration: options.hydration ?? true,
33
33
  isUsingApplicationBuilder,
34
34
  isUsingWebpackBuilder,
35
+ isRspack: options.isRspack ?? false,
35
36
  buildTargetExecutor,
36
37
  buildTargetTsConfigPath: targets.build.options?.tsConfig ??
37
38
  (0, devkit_1.joinPathFragments)(root, 'tsconfig.app.json'),
@@ -5,6 +5,7 @@ exports.updateProjectConfigForBrowserBuilder = updateProjectConfigForBrowserBuil
5
5
  const devkit_1 = require("@nx/devkit");
6
6
  const internal_1 = require("@nx/devkit/internal");
7
7
  const internal_2 = require("@nx/js/internal");
8
+ const version_utils_1 = require("../../utils/version-utils");
8
9
  const constants_1 = require("./constants");
9
10
  function updateProjectConfigForApplicationBuilder(tree, options) {
10
11
  const project = (0, devkit_1.readProjectConfiguration)(tree, options.project);
@@ -37,6 +38,12 @@ function updateProjectConfigForApplicationBuilder(tree, options) {
37
38
  entry: (0, devkit_1.joinPathFragments)(sourceRoot, options.serverFileName),
38
39
  };
39
40
  buildTarget.options.outputMode = 'server';
41
+ if ((0, version_utils_1.supportsSsrAllowedHosts)(tree)) {
42
+ // The engine matches the request host against this list and an unset list
43
+ // matches nothing, so surface it for the deployment to fill in
44
+ buildTarget.options.security ??= {};
45
+ buildTarget.options.security.allowedHosts ??= [];
46
+ }
40
47
  (0, devkit_1.updateProjectConfiguration)(tree, options.project, project);
41
48
  }
42
49
  function updateProjectConfigForBrowserBuilder(tree, options) {
@@ -10,6 +10,12 @@ export interface Schema {
10
10
  hydration?: boolean;
11
11
  skipFormat?: boolean;
12
12
  skipPackageJson?: boolean;
13
+ /**
14
+ * Internal. The project's build is converted to `@nx/angular-rspack` right
15
+ * after this generator runs, so the setup must match what the rspack build
16
+ * supports rather than the build executor the project has right now.
17
+ */
18
+ isRspack?: boolean;
13
19
  }
14
20
 
15
21
  export interface NormalizedGeneratorOptions extends Schema {
@@ -9,7 +9,7 @@ async function setupSsr(tree, schema) {
9
9
  (0, lib_1.validateOptions)(tree, schema);
10
10
  const options = await (0, lib_1.normalizeOptions)(tree, schema);
11
11
  if (!schema.skipPackageJson) {
12
- (0, lib_1.addDependencies)(tree, options.isUsingApplicationBuilder, options.isUsingWebpackBuilder);
12
+ (0, lib_1.addDependencies)(tree, options);
13
13
  }
14
14
  (0, lib_1.generateSSRFiles)(tree, options);
15
15
  if (options.hydration) {
@@ -20,10 +20,16 @@ async function setupSsr(tree, schema) {
20
20
  }
21
21
  if (options.isUsingApplicationBuilder) {
22
22
  (0, lib_1.updateProjectConfigForApplicationBuilder)(tree, options);
23
- (0, lib_1.setServerTsConfigOptionsForApplicationBuilder)(tree, options);
24
23
  }
25
24
  else {
26
25
  (0, lib_1.updateProjectConfigForBrowserBuilder)(tree, options);
26
+ }
27
+ // rspack compiles the browser and the server bundles from the build tsconfig,
28
+ // so the separate tsconfig.server.json the server builder needs is dead weight
29
+ if (options.isUsingApplicationBuilder || options.isRspack) {
30
+ (0, lib_1.setServerTsConfigOptionsForSingleProgramBuild)(tree, options);
31
+ }
32
+ else {
27
33
  (0, lib_1.generateTsConfigServerJsonForBrowserBuilder)(tree, options);
28
34
  }
29
35
  (0, lib_1.addServerFile)(tree, options);
@@ -9,4 +9,10 @@ import type * as ts from 'typescript';
9
9
  * @returns The resolved value of the compiler option, or undefined if not set
10
10
  */
11
11
  export declare function getDefinedCompilerOption(tree: Tree, tsConfigPath: string, optionName: keyof ts.CompilerOptions): any | undefined;
12
+ /**
13
+ * Reads a tsconfig with its `extends` chain applied. The `files`, `include` and
14
+ * `exclude` entries come back relative to `tsConfigPath` no matter which config
15
+ * in the chain declared them.
16
+ */
17
+ export declare function readResolvedTsConfig(tree: Tree, tsConfigPath: string): ts.ParsedCommandLine;
12
18
  export declare function readCompilerOptionsFromTsConfig(tree: Tree, tsConfigPath: string): ts.CompilerOptions;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDefinedCompilerOption = getDefinedCompilerOption;
4
+ exports.readResolvedTsConfig = readResolvedTsConfig;
4
5
  exports.readCompilerOptionsFromTsConfig = readCompilerOptionsFromTsConfig;
5
6
  const internal_1 = require("@nx/js/internal");
6
7
  const node_path_1 = require("node:path");
@@ -16,6 +17,19 @@ function getDefinedCompilerOption(tree, tsConfigPath, optionName) {
16
17
  const compilerOptions = readCompilerOptionsFromTsConfig(tree, tsConfigPath);
17
18
  return compilerOptions[optionName];
18
19
  }
20
+ /**
21
+ * Reads a tsconfig with its `extends` chain applied. The `files`, `include` and
22
+ * `exclude` entries come back relative to `tsConfigPath` no matter which config
23
+ * in the chain declared them.
24
+ */
25
+ function readResolvedTsConfig(tree, tsConfigPath) {
26
+ const ts = (0, internal_1.ensureTypescript)();
27
+ const host = (0, internal_1.createTreeParseConfigHost)(tree);
28
+ // an absolute path is what makes the inherited entries come back relative to
29
+ // this config
30
+ const absoluteTsConfigPath = (0, node_path_1.join)(tree.root, tsConfigPath);
31
+ return ts.parseJsonConfigFileContent(ts.readConfigFile(absoluteTsConfigPath, host.readFile).config, host, (0, node_path_1.dirname)(absoluteTsConfigPath));
32
+ }
19
33
  function readCompilerOptionsFromTsConfig(tree, tsConfigPath) {
20
34
  const ts = (0, internal_1.ensureTypescript)();
21
35
  const host = (0, internal_1.createTreeParseConfigHost)(tree);
@@ -11,6 +11,20 @@ export declare function getInstalledPackageVersionInfo(tree: Tree, pkgName: stri
11
11
  major: number;
12
12
  version: string;
13
13
  };
14
+ /**
15
+ * Whether every `@angular/ssr` version the workspace can end up with accepts
16
+ * an allowed hosts configuration. The application engine and `CommonEngine`
17
+ * validate the request host against it, and an unset allowlist matches nothing.
18
+ */
19
+ export declare function supportsSsrAllowedHosts(tree: Tree): boolean;
20
+ /**
21
+ * Raises the floor of an `@angular/ssr` version range to the first version in
22
+ * it that accepts an allowed hosts configuration, so the scaffolded setup can
23
+ * use the option no matter how the range is resolved. The range is returned
24
+ * unchanged when every version it allows already accepts one, when no version
25
+ * in it does, and when raising it would change the release lines it covers.
26
+ */
27
+ export declare function withSsrAllowedHostsSupport(range: string): string;
14
28
  export declare function versions(tree: Tree): PackageCompatVersions;
15
29
  export declare function versions<V extends SupportedVersion>(tree: Tree, options: {
16
30
  minAngularMajorVersion: V;
@@ -5,6 +5,8 @@ exports.getInstalledAngularVersion = getInstalledAngularVersion;
5
5
  exports.getInstalledAngularMajorVersion = getInstalledAngularMajorVersion;
6
6
  exports.getInstalledAngularVersionInfo = getInstalledAngularVersionInfo;
7
7
  exports.getInstalledPackageVersionInfo = getInstalledPackageVersionInfo;
8
+ exports.supportsSsrAllowedHosts = supportsSsrAllowedHosts;
9
+ exports.withSsrAllowedHostsSupport = withSsrAllowedHostsSupport;
8
10
  exports.versions = versions;
9
11
  const tslib_1 = require("tslib");
10
12
  const devkit_1 = require("@nx/devkit");
@@ -33,6 +35,56 @@ function getInstalledPackageVersionInfo(tree, pkgName) {
33
35
  const version = (0, devkit_1.getDependencyVersionFromPackageJson)(tree, pkgName);
34
36
  return version ? { major: (0, semver_1.major)((0, semver_1.coerce)(version)), version } : null;
35
37
  }
38
+ // Released in 20.3.17, 21.1.5 and 21.2.0, and never backported to 21.0.
39
+ // Prereleases are deliberately not matched: the option landed part-way through
40
+ // the 21.2 prerelease train, so a prerelease says nothing about whether it is
41
+ // there.
42
+ const SSR_ALLOWED_HOSTS_RANGE = '>=20.3.17 <21.0.0 || >=21.1.5';
43
+ const SSR_ALLOWED_HOSTS_FLOORS = ['20.3.17', '21.1.5', '21.2.0'];
44
+ // A single caret, tilde or exact version. Raising anything else, a union of
45
+ // ranges above all, would drop the release lines it covers.
46
+ const RAISABLE_RANGE = /^[~^]?\d+\.\d+\.\d+(?:-[\w.]+)?$/;
47
+ /**
48
+ * Whether every `@angular/ssr` version a range allows accepts an allowed hosts
49
+ * configuration. A range is not always resolved to its highest version, the
50
+ * `resolution-mode` setting in pnpm being one way to ask for the lowest, so a
51
+ * range that merely reaches such a version is not enough.
52
+ */
53
+ function rangeAcceptsSsrAllowedHosts(range) {
54
+ return !!(0, semver_1.validRange)(range) && (0, semver_1.subset)(range, SSR_ALLOWED_HOSTS_RANGE);
55
+ }
56
+ /**
57
+ * Whether every `@angular/ssr` version the workspace can end up with accepts
58
+ * an allowed hosts configuration. The application engine and `CommonEngine`
59
+ * validate the request host against it, and an unset allowlist matches nothing.
60
+ */
61
+ function supportsSsrAllowedHosts(tree) {
62
+ const installed = (0, internal_1.getInstalledPackageVersionFromTree)(tree, '@angular/ssr');
63
+ if (installed) {
64
+ return (0, semver_1.satisfies)(installed, SSR_ALLOWED_HOSTS_RANGE);
65
+ }
66
+ const declared = (0, devkit_1.getDependencyVersionFromPackageJson)(tree, '@angular/ssr');
67
+ return !!declared && rangeAcceptsSsrAllowedHosts(declared);
68
+ }
69
+ /**
70
+ * Raises the floor of an `@angular/ssr` version range to the first version in
71
+ * it that accepts an allowed hosts configuration, so the scaffolded setup can
72
+ * use the option no matter how the range is resolved. The range is returned
73
+ * unchanged when every version it allows already accepts one, when no version
74
+ * in it does, and when raising it would change the release lines it covers.
75
+ */
76
+ function withSsrAllowedHostsSupport(range) {
77
+ if (rangeAcceptsSsrAllowedHosts(range) || !RAISABLE_RANGE.test(range)) {
78
+ return range;
79
+ }
80
+ const floor = SSR_ALLOWED_HOSTS_FLOORS.find((version) => (0, semver_1.satisfies)(version, range));
81
+ if (!floor) {
82
+ return range;
83
+ }
84
+ const operator = range.startsWith('~') || range.startsWith('^') ? range[0] : '';
85
+ const raised = `${operator}${floor}`;
86
+ return rangeAcceptsSsrAllowedHosts(raised) ? raised : range;
87
+ }
36
88
  function versions(tree, options) {
37
89
  const majorAngularVersion = getInstalledAngularMajorVersion(tree);
38
90
  if (options?.minAngularMajorVersion &&
@@ -4,3 +4,14 @@ import { type Tree } from '@nx/devkit';
4
4
  * Angular version. Must be called after `@nx/cypress` has been ensured.
5
5
  */
6
6
  export declare function assertCypressComponentTestingSupport(tree: Tree): void;
7
+ /**
8
+ * Returns the installed Cypress version, or the declared range when nothing
9
+ * satisfying is installed, if it cannot reach `floor`; `null` otherwise.
10
+ *
11
+ * A satisfying install decides. Without one, only a range capped below the
12
+ * floor fails: `^15.17.0` installs 15.20.1+, so its lower bound cannot be
13
+ * compared. Declarations that are not ranges (`latest`, `file:`) are not
14
+ * gated.
15
+ * When Cypress is not declared, the generators install `cypressVersion`.
16
+ */
17
+ export declare function findCypressBelow(tree: Tree, floor: string): string | null;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assertCypressComponentTestingSupport = assertCypressComponentTestingSupport;
4
+ exports.findCypressBelow = findCypressBelow;
4
5
  const devkit_1 = require("@nx/devkit");
5
6
  const internal_1 = require("@nx/devkit/internal");
6
7
  const semver_1 = require("semver");
@@ -10,22 +11,46 @@ const minCypressVersion = '15.20.1';
10
11
  * Angular version. Must be called after `@nx/cypress` has been ensured.
11
12
  */
12
13
  function assertCypressComponentTestingSupport(tree) {
13
- const angularVersion = (0, internal_1.getDeclaredPackageVersion)(tree, '@angular/core');
14
- if (!angularVersion || (0, semver_1.lt)(angularVersion, '22.1.0')) {
14
+ const angularVersion = (0, internal_1.getResolvedPackageVersion)(tree, '@angular/core');
15
+ if (!angularVersion) {
15
16
  return;
16
17
  }
17
- const { cypressVersion, } = require('@nx/cypress/internal');
18
- // When Cypress is not installed, the generators install `cypressVersion`
19
- const declaredCypressVersion = (0, devkit_1.getDependencyVersionFromPackageJson)(tree, 'cypress') ?? cypressVersion;
20
- // Gate only ranges capped below the floor. `^15.17.0` installs 15.20.1+, so
21
- // comparing its lower bound would reject workspaces that work. Dist tags
22
- // (`latest`, `next`) aren't ranges and aren't gated.
23
- if (!(0, semver_1.validRange)(declaredCypressVersion) ||
24
- !(0, semver_1.subset)(declaredCypressVersion, `<${minCypressVersion}`)) {
18
+ // A prerelease of 22.1 counts as 22.1.
19
+ const angularRelease = (0, semver_1.coerce)(angularVersion)?.version ?? angularVersion;
20
+ if ((0, semver_1.lt)(angularRelease, '22.1.0')) {
25
21
  return;
26
22
  }
23
+ const found = findCypressBelow(tree, minCypressVersion);
24
+ if (found) {
25
+ throwForUnsupportedCypress(found);
26
+ }
27
+ }
28
+ /**
29
+ * Returns the installed Cypress version, or the declared range when nothing
30
+ * satisfying is installed, if it cannot reach `floor`; `null` otherwise.
31
+ *
32
+ * A satisfying install decides. Without one, only a range capped below the
33
+ * floor fails: `^15.17.0` installs 15.20.1+, so its lower bound cannot be
34
+ * compared. Declarations that are not ranges (`latest`, `file:`) are not
35
+ * gated.
36
+ * When Cypress is not declared, the generators install `cypressVersion`.
37
+ */
38
+ function findCypressBelow(tree, floor) {
39
+ const { cypressVersion, } = require('@nx/cypress/internal');
40
+ const declaredCypressVersion = (0, devkit_1.getDependencyVersionFromPackageJson)(tree, 'cypress');
41
+ const installedCypressVersion = declaredCypressVersion
42
+ ? (0, internal_1.getSatisfyingInstalledPackageVersion)(tree, 'cypress', declaredCypressVersion)
43
+ : null;
44
+ if (installedCypressVersion) {
45
+ const release = (0, semver_1.coerce)(installedCypressVersion)?.version ?? installedCypressVersion;
46
+ return (0, semver_1.lt)(release, floor) ? installedCypressVersion : null;
47
+ }
48
+ const range = declaredCypressVersion ?? cypressVersion;
49
+ return (0, semver_1.validRange)(range) && (0, semver_1.subset)(range, `<${floor}`) ? range : null;
50
+ }
51
+ function throwForUnsupportedCypress(found) {
27
52
  throw new Error(`Cypress Component Testing with Angular 22.1 and higher requires Cypress ${minCypressVersion} or higher. ` +
28
- `Found Cypress ${declaredCypressVersion}. Earlier Cypress versions can't load Angular's Babel 8 dependencies. ` +
53
+ `Found Cypress ${found}. Earlier Cypress versions can't load Angular's Babel 8 dependencies. ` +
29
54
  `Please upgrade Cypress. ` +
30
55
  `See https://github.com/cypress-io/cypress/issues/34461.`);
31
56
  }
@@ -2,7 +2,7 @@ export declare const nxVersion: any;
2
2
  export declare const angularVersion = "~22.1.0";
3
3
  export declare const angularDevkitVersion = "~22.1.0";
4
4
  export declare const ngPackagrVersion = "~22.1.0";
5
- export declare const ngrxVersion = "^21.0.0";
5
+ export declare const ngrxVersion = "^22.0.0";
6
6
  export declare const rxjsVersion = "~7.8.0";
7
7
  export declare const zoneJsVersion = "~0.16.2";
8
8
  export declare const tsLibVersion = "^2.3.0";
@@ -6,7 +6,7 @@ exports.nxVersion = require((0, path_1.join)('@nx/angular', 'package.json')).ver
6
6
  exports.angularVersion = '~22.1.0';
7
7
  exports.angularDevkitVersion = '~22.1.0';
8
8
  exports.ngPackagrVersion = '~22.1.0';
9
- exports.ngrxVersion = '^21.0.0';
9
+ exports.ngrxVersion = '^22.0.0';
10
10
  exports.rxjsVersion = '~7.8.0';
11
11
  exports.zoneJsVersion = '~0.16.2';
12
12
  exports.tsLibVersion = '^2.3.0';
package/migrations.json CHANGED
@@ -2311,6 +2311,18 @@
2311
2311
  "alwaysAddToPackageJson": false
2312
2312
  }
2313
2313
  }
2314
+ },
2315
+ "23.3.0-ngrx": {
2316
+ "version": "23.3.0-beta.1",
2317
+ "requires": {
2318
+ "@angular/core": "^22.0.0"
2319
+ },
2320
+ "packages": {
2321
+ "@ngrx/store": {
2322
+ "version": "^22.0.0",
2323
+ "alwaysAddToPackageJson": false
2324
+ }
2325
+ }
2314
2326
  }
2315
2327
  }
2316
2328
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/angular",
3
- "version": "23.2.1",
3
+ "version": "23.3.0-beta.1",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "description": "The Nx Plugin for Angular contains executors, generators, and utilities for managing Angular applications and libraries within an Nx workspace. It provides: \n\n- Integration with libraries such as Storybook, Jest, ESLint, Playwright and Cypress. \n\n- Generators to help scaffold code quickly (like: Micro Frontends, Libraries, both internal to your codebase and publishable to npm) \n\n- Single Component Application Modules (SCAMs) \n\n- NgRx helpers. \n\n- Utilities for automatic workspace refactoring.",
@@ -79,15 +79,15 @@
79
79
  "picomatch": "4.0.4",
80
80
  "semver": "^7.6.3",
81
81
  "tslib": "^2.3.0",
82
- "@nx/js": "23.2.1",
83
- "@nx/web": "23.2.1",
84
- "@nx/devkit": "23.2.1",
85
- "@nx/eslint": "23.2.1"
82
+ "@nx/devkit": "23.3.0-beta.1",
83
+ "@nx/eslint": "23.3.0-beta.1",
84
+ "@nx/web": "23.3.0-beta.1",
85
+ "@nx/js": "23.3.0-beta.1"
86
86
  },
87
87
  "devDependencies": {
88
- "@nx/storybook": "23.2.1",
89
- "@nx/vitest": "23.2.1",
90
- "nx": "23.2.1"
88
+ "@nx/storybook": "23.3.0-beta.1",
89
+ "@nx/vitest": "23.3.0-beta.1",
90
+ "nx": "23.3.0-beta.1"
91
91
  },
92
92
  "peerDependencies": {
93
93
  "@angular/build": ">= 20.0.0 < 23.0.0",
@@ -98,11 +98,11 @@
98
98
  "ng-packagr": ">= 20.0.0 < 23.0.0",
99
99
  "rxjs": "^6.5.3 || ^7.5.0",
100
100
  "webpack-merge": "^5.8.0",
101
- "@nx/cypress": "23.2.1",
102
- "@nx/playwright": "23.2.1",
103
- "@nx/rspack": "23.2.1",
104
- "@nx/module-federation": "23.2.1",
105
- "@nx/webpack": "23.2.1"
101
+ "@nx/cypress": "23.3.0-beta.1",
102
+ "@nx/module-federation": "23.3.0-beta.1",
103
+ "@nx/playwright": "23.3.0-beta.1",
104
+ "@nx/rspack": "23.3.0-beta.1",
105
+ "@nx/webpack": "23.3.0-beta.1"
106
106
  },
107
107
  "peerDependenciesMeta": {
108
108
  "@angular/build": {
@@ -1,78 +0,0 @@
1
- <%_ if (!zoneless && angularMajorVersion < 21) { _%>
2
- import 'zone.js/node';
3
-
4
- <%_ } _%>
5
- import { APP_BASE_HREF } from '@angular/common';
6
- import { CommonEngine } from '@angular/ssr/node';
7
- <%_ if (useDefaultImport) { _%>
8
- import express from 'express';
9
- <%_ } else { _%>
10
- import * as express from 'express';
11
- <%_ } _%>
12
- import { existsSync } from 'node:fs';
13
- import { join } from 'node:path';
14
- import bootstrap from './main.server';
15
-
16
- // The Express app is exported so that it can be used by serverless Functions.
17
- export function app(): express.Express {
18
- const server = express();
19
- const distFolder = join(process.cwd(), "<%= pathToDistFolder %>");
20
- const indexHtml = existsSync(join(distFolder, 'index.original.html'))
21
- ? join(distFolder, 'index.original.html')
22
- : join(distFolder, 'index.html');
23
-
24
- const commonEngine = new CommonEngine();
25
-
26
- server.set('view engine', 'html');
27
- server.set('views', distFolder);
28
-
29
- // Example Express Rest API endpoints
30
- // server.get('/api/**', (req, res) => { });
31
- // Serve static files from /browser
32
- server.get(
33
- '*.*',
34
- express.static(distFolder, {
35
- maxAge: '1y',
36
- })
37
- );
38
-
39
- // All regular routes use the Angular engine
40
- server.get('*', (req, res, next) => {
41
- const { protocol, originalUrl, baseUrl, headers } = req;
42
-
43
- commonEngine
44
- .render({
45
- bootstrap,
46
- documentFilePath: indexHtml,
47
- url: `${protocol}://${headers.host}${originalUrl}`,
48
- publicPath: distFolder,
49
- providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
50
- })
51
- .then((html) => res.send(html))
52
- .catch((err) => next(err));
53
- });
54
-
55
- return server;
56
- }
57
-
58
- function run(): void {
59
- const port = process.env['PORT'] || 4000;
60
-
61
- // Start up the Node server
62
- const server = app();
63
- server.listen(port, () => {
64
- console.log(`Node Express server listening on http://localhost:${port}`);
65
- });
66
- }
67
-
68
- // Webpack will replace 'require' with '__webpack_require__'
69
- // '__non_webpack_require__' is a proxy to Node 'require'
70
- // The below code is to ensure that the server is run only when not requiring the bundle.
71
- declare const __non_webpack_require__: NodeRequire;
72
- const mainModule = __non_webpack_require__.main;
73
- const moduleFilename = (mainModule && mainModule.filename) || '';
74
- if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
75
- run();
76
- }
77
-
78
- export default bootstrap;