@nx/angular 17.0.1 → 17.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/angular",
3
- "version": "17.0.1",
3
+ "version": "17.0.3",
4
4
  "private": false,
5
5
  "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, Tailwind CSS, 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- Upgrading AngularJS applications \n\n- Single Component Application Modules (SCAMs) \n\n- NgRx helpers. \n\n- Utilities for automatic workspace refactoring.",
6
6
  "repository": {
@@ -79,15 +79,15 @@
79
79
  "webpack": "^5.80.0",
80
80
  "webpack-merge": "^5.8.0",
81
81
  "enquirer": "^2.3.6",
82
- "@nx/devkit": "17.0.1",
83
- "@nx/cypress": "17.0.1",
84
- "@nx/jest": "17.0.1",
85
- "@nx/js": "17.0.1",
86
- "@nx/eslint": "17.0.1",
87
- "@nx/webpack": "17.0.1",
88
- "@nx/web": "17.0.1",
89
- "@nx/workspace": "17.0.1",
90
- "@nrwl/angular": "17.0.1"
82
+ "@nx/devkit": "17.0.3",
83
+ "@nx/cypress": "17.0.3",
84
+ "@nx/jest": "17.0.3",
85
+ "@nx/js": "17.0.3",
86
+ "@nx/eslint": "17.0.3",
87
+ "@nx/webpack": "17.0.3",
88
+ "@nx/web": "17.0.3",
89
+ "@nx/workspace": "17.0.3",
90
+ "@nrwl/angular": "17.0.3"
91
91
  },
92
92
  "peerDependencies": {
93
93
  "@angular-devkit/build-angular": ">= 14.0.0 < 17.0.0",
@@ -13,7 +13,8 @@ const module_federation_2 = require("@nx/webpack/src/utils/module-federation");
13
13
  const child_process_1 = require("child_process");
14
14
  const rxjs_1 = require("rxjs");
15
15
  function executeModuleFederationDevServerBuilder(schema, context) {
16
- const nxBin = require.resolve('nx');
16
+ // Force Node to resolve to look for the nx binary that is inside node_modules
17
+ const nxBin = require.resolve('nx/bin/nx');
17
18
  const { ...options } = schema;
18
19
  const projectGraph = (0, devkit_1.readCachedProjectGraph)();
19
20
  const { projects: workspaceProjects } = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
@@ -6,7 +6,9 @@ const internal_1 = require("@nx/js/src/internal");
6
6
  const devkit_1 = require("@nx/devkit");
7
7
  const path_1 = require("path");
8
8
  async function mergeCustomWebpackConfig(baseWebpackConfig, pathToWebpackConfig, options, target) {
9
- const customWebpackConfiguration = resolveCustomWebpackConfig(pathToWebpackConfig, (0, path_1.join)(devkit_1.workspaceRoot, options.tsConfig));
9
+ const customWebpackConfiguration = resolveCustomWebpackConfig(pathToWebpackConfig, options.tsConfig.startsWith(devkit_1.workspaceRoot)
10
+ ? options.tsConfig
11
+ : (0, path_1.join)(devkit_1.workspaceRoot, options.tsConfig));
10
12
  // The extra Webpack configuration file can also export a Promise, for instance:
11
13
  // `module.exports = new Promise(...)`. If it exports a single object, but not a Promise,
12
14
  // then await will just resolve that object.
@@ -1,4 +1,4 @@
1
- import { ApplicationConfig } from '@angular/core';<% if (routing) { %>
1
+ import { ApplicationConfig } from <% if (installedAngularInfo.major >= 16) { %>'@angular/core';<% } else { %>'@angular/platform-browser';<% } %><% if (routing) { %>
2
2
  import { provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router';
3
3
  import { appRoutes } from './app.routes';<% } %>
4
4
 
@@ -1,5 +1,11 @@
1
1
  import { bootstrapApplication } from '@angular/platform-browser';
2
2
  import { appConfig } from './app/app.config';
3
- import { AppComponent } from './app/app.component';
3
+ import { AppComponent } from './app/app.component';<% if(installedAngularInfo.major === 14) { %>
4
+ import { enableProdMode } from '@angular/core';
5
+ import { environment } from './environments/environment';
6
+
7
+ if(environment.production) {
8
+ enableProdMode();
9
+ }<% } %>
4
10
 
5
11
  bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
@@ -8,21 +8,28 @@ async function addE2e(tree, options) {
8
8
  if (options.e2eTestRunner === 'cypress') {
9
9
  // TODO: This can call `@nx/web:static-config` generator when ready
10
10
  addFileServerTarget(tree, options, 'serve-static');
11
- await (0, cypress_1.cypressProjectGenerator)(tree, {
12
- name: options.e2eProjectName,
13
- directory: options.e2eProjectRoot,
14
- // the name and root are already normalized, instruct the generator to use them as is
15
- projectNameAndRootFormat: 'as-provided',
16
- project: options.name,
11
+ (0, devkit_1.addProjectConfiguration)(tree, options.e2eProjectName, {
12
+ projectType: 'application',
13
+ root: options.e2eProjectRoot,
14
+ sourceRoot: (0, devkit_1.joinPathFragments)(options.e2eProjectRoot, 'src'),
15
+ targets: {},
16
+ tags: [],
17
+ implicitDependencies: [options.name],
18
+ });
19
+ await (0, cypress_1.configurationGenerator)(tree, {
20
+ project: options.e2eProjectName,
21
+ directory: 'src',
17
22
  linter: options.linter,
18
- standaloneConfig: options.standaloneConfig,
19
23
  skipPackageJson: options.skipPackageJson,
20
24
  skipFormat: true,
25
+ devServerTarget: `${options.name}:serve:development`,
26
+ rootProject: options.rootProject,
21
27
  });
22
28
  }
23
29
  else if (options.e2eTestRunner === 'playwright') {
24
30
  const { configurationGenerator: playwrightConfigurationGenerator } = (0, devkit_1.ensurePackage)('@nx/playwright', versions_1.nxVersion);
25
31
  (0, devkit_1.addProjectConfiguration)(tree, options.e2eProjectName, {
32
+ projectType: 'application',
26
33
  root: options.e2eProjectRoot,
27
34
  sourceRoot: (0, devkit_1.joinPathFragments)(options.e2eProjectRoot, 'src'),
28
35
  targets: {},
@@ -38,6 +45,7 @@ async function addE2e(tree, options) {
38
45
  setParserOptionsProject: options.setParserOptionsProject,
39
46
  webServerCommand: `${(0, devkit_1.getPackageManagerCommand)().exec} nx serve ${options.name}`,
40
47
  webServerAddress: `http://localhost:${options.port ?? 4200}`,
48
+ rootProject: options.rootProject,
41
49
  });
42
50
  }
43
51
  }
@@ -12,22 +12,22 @@
12
12
  ],
13
13
  "type": "object",
14
14
  "properties": {
15
- "name": {
16
- "description": "The name of the module.",
15
+ "path": {
17
16
  "type": "string",
18
17
  "$default": {
19
18
  "$source": "argv",
20
19
  "index": 0
21
20
  },
21
+ "description": "The path to locate the federated module.",
22
+ "x-prompt": "What is the path to the module to be federated?"
23
+ },
24
+ "name": {
25
+ "description": "The name of the module.",
26
+ "type": "string",
22
27
  "x-prompt": "What name would you like to use for the module?",
23
28
  "pattern": "^[a-zA-Z][^:]*$",
24
29
  "x-priority": "important"
25
30
  },
26
- "path": {
27
- "type": "string",
28
- "description": "The path to locate the federated module.",
29
- "x-prompt": "What is the path to the module to be federated?"
30
- },
31
31
  "remote": {
32
32
  "type": "string",
33
33
  "description": "The name of the remote.",
@@ -228,12 +228,20 @@ class E2eMigrator extends project_migrator_1.ProjectMigrator {
228
228
  }
229
229
  async migrateCypressE2eProject() {
230
230
  const oldCypressConfigFilePath = this.getOldCypressConfigFilePath();
231
- await (0, cypress_1.cypressProjectGenerator)(this.tree, {
232
- name: this.project.name,
233
- project: this.appName,
231
+ (0, devkit_1.addProjectConfiguration)(this.tree, this.project.name, {
232
+ projectType: 'application',
233
+ root: this.project.newRoot,
234
+ sourceRoot: this.project.newSourceRoot,
235
+ targets: {},
236
+ tags: [],
237
+ implicitDependencies: [this.appName],
238
+ });
239
+ await (0, cypress_1.configurationGenerator)(this.tree, {
240
+ project: this.project.name,
234
241
  linter: this.isProjectUsingEsLint ? eslint_1.Linter.EsLint : eslint_1.Linter.None,
235
- standaloneConfig: true,
236
242
  skipFormat: true,
243
+ // any target would do, we replace it later with the target existing in the project being migrated
244
+ devServerTarget: `${this.appName}:serve`,
237
245
  });
238
246
  const cypressConfigFilePath = this.updateOrCreateCypressConfigFile(oldCypressConfigFilePath);
239
247
  this.updateCypressProjectConfiguration(cypressConfigFilePath);
@@ -258,34 +266,14 @@ class E2eMigrator extends project_migrator_1.ProjectMigrator {
258
266
  return cypressConfigFilePath;
259
267
  }
260
268
  updateCypressProjectConfiguration(cypressConfigPath) {
261
- /**
262
- * The `cypressProjectGenerator` function normalizes the project name. The
263
- * migration keeps the names for existing projects as-is to avoid any
264
- * confusion. The e2e project is technically new, but it's associated
265
- * to an existing application, so we keep it familiar.
266
- */
267
- const generatedProjectName = (0, devkit_1.names)(this.project.name).fileName;
268
- if (this.project.name !== generatedProjectName) {
269
- // If the names are different, we "rename" the newly added project.
270
- this.projectConfig = (0, devkit_1.readProjectConfiguration)(this.tree, generatedProjectName);
271
- this.projectConfig.root = this.project.newRoot;
272
- this.projectConfig.sourceRoot = this.project.newSourceRoot;
273
- (0, devkit_1.removeProjectConfiguration)(this.tree, generatedProjectName);
274
- (0, devkit_1.addProjectConfiguration)(this.tree, this.project.name, { ...this.projectConfig }, true);
275
- }
276
- else {
277
- this.projectConfig = (0, devkit_1.readProjectConfiguration)(this.tree, this.project.name);
278
- }
269
+ this.projectConfig = (0, devkit_1.readProjectConfiguration)(this.tree, this.project.name);
279
270
  if (this.isProjectUsingEsLint) {
280
271
  // the generated cypress project always generates a "lint" target,
281
272
  // in case the app was using a different name for it, we use it
282
- const lintTarget = this.projectConfig.targets.lint;
283
273
  if (this.lintTargetName && this.lintTargetName !== 'lint') {
284
274
  this.projectConfig.targets[this.lintTargetName] =
285
275
  this.projectConfig.targets.lint;
286
276
  }
287
- lintTarget.options.lintFilePatterns =
288
- lintTarget.options.lintFilePatterns.map((pattern) => pattern.replace(`apps/${generatedProjectName}`, this.project.newRoot));
289
277
  }
290
278
  [this.targetNames.e2e, 'cypress-run', 'cypress-open'].forEach((target) => {
291
279
  if (this.appConfig.targets[target]) {
@@ -10,9 +10,11 @@ describe('AppComponent', () => {
10
10
  imports: [
11
11
  RouterTestingModule.withRoutes([
12
12
  { path: '', component: NxWelcomeComponent },
13
- ]),
14
- ],
15
- declarations: [AppComponent, NxWelcomeComponent],
13
+ ]),<% if (standalone) { %>
14
+ AppComponent,
15
+ NxWelcomeComponent,<% } %>
16
+ ],<% if (!standalone) { %>
17
+ declarations: [AppComponent, NxWelcomeComponent],<% } %>
16
18
  }).compileComponents();
17
19
  });
18
20
 
@@ -37,4 +39,4 @@ describe('AppComponent', () => {
37
39
  const compiled = fixture.nativeElement as HTMLElement;
38
40
  expect(compiled.querySelector('h1')?.textContent).toContain('Welcome <%= appName %>');
39
41
  }));
40
- });
42
+ });
@@ -7,7 +7,7 @@ function fixBootstrap(tree, appRoot, options) {
7
7
  const mainFilePath = (0, devkit_1.joinPathFragments)(appRoot, 'src/main.ts');
8
8
  const bootstrapCode = tree.read(mainFilePath, 'utf-8');
9
9
  const installedAngularMajor = (0, version_utils_1.getInstalledAngularMajorVersion)(tree);
10
- if (options.standalone) {
10
+ if (options.standalone && options.mfType === 'remote') {
11
11
  tree.write(`${appRoot}/src/bootstrap.ts`, standaloneBootstrapCode(installedAngularMajor === 14));
12
12
  }
13
13
  else {
@@ -34,6 +34,7 @@ function updateHostAppRoutes(tree, options) {
34
34
  ${tree.read(pathToHostRootRoutingFile, 'utf-8')}`);
35
35
  (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, '../files/host-files'), (0, devkit_1.joinPathFragments)(sourceRoot, 'app'), {
36
36
  appName: options.appName,
37
+ standalone: options.standalone,
37
38
  tmpl: '',
38
39
  });
39
40
  }
@@ -6,11 +6,11 @@ const get_npm_scope_1 = require("@nx/js/src/utils/package-json/get-npm-scope");
6
6
  function normalizeNewProjectPrefix(prefix, npmScope, fallbackPrefix) {
7
7
  // Prefix needs to be a valid html selector, if npmScope it's not valid, we don't default
8
8
  // to it and let it fall through to the Angular schematic to handle it
9
- // https://github.com/angular/angular-cli/blob/1c634cd327e5a850553b258aa2d5e6a6b2c75c65/packages/schematics/angular/component/index.ts#L130
10
- const htmlSelectorRegex = /^[a-zA-Z][.0-9a-zA-Z]*(:?-[a-zA-Z][.0-9a-zA-Z]*)*$/;
9
+ // https://github.com/angular/angular-cli/blob/aa9f0528f174e856a4923cb24861fdf6e6f96b48/packages/schematics/angular/component/index.ts#L64
10
+ const htmlSelectorRegex = /^[a-zA-Z][.0-9a-zA-Z]*((:?-[0-9]+)*|(:?-[a-zA-Z][.0-9a-zA-Z]*(:?-[0-9]+)*)*)$/;
11
11
  if (prefix) {
12
12
  if (!htmlSelectorRegex.test(prefix)) {
13
- throw new Error('The provided "prefix" is invalid. The prefix must start with a letter, and must contain only alphanumeric characters or dashes. When adding a dash the segment after the dash must also start with a letter.');
13
+ throw new Error('The provided "prefix" is invalid. The prefix must start with a letter, and must contain only alphanumeric characters or dashes.');
14
14
  }
15
15
  return prefix;
16
16
  }
@@ -23,7 +23,7 @@ There are two options that can be followed to resolve this issue:
23
23
 
24
24
  If you encountered this error when creating a new Nx Workspace, the workspace name or "npmScope" is invalid to use as the selector prefix for the application being generated.
25
25
 
26
- Valid selector prefixes must start with a letter, and must contain only alphanumeric characters or dashes. When adding a dash the segment after the dash must also start with a letter.`);
26
+ Valid selector prefixes must start with a letter, and must contain only alphanumeric characters or dashes.`);
27
27
  }
28
28
  return npmScope || fallbackPrefix;
29
29
  }
@@ -30,7 +30,13 @@ function getFunctionDeterminateRemoteUrl(isServer = false) {
30
30
  const target = 'serve';
31
31
  const remoteEntry = isServer ? 'server/remoteEntry.js' : 'remoteEntry.mjs';
32
32
  return function (remote) {
33
- const remoteConfiguration = (0, project_graph_1.readCachedProjectConfiguration)(remote);
33
+ let remoteConfiguration = null;
34
+ try {
35
+ remoteConfiguration = (0, project_graph_1.readCachedProjectConfiguration)(remote);
36
+ }
37
+ catch (e) {
38
+ throw new Error(`Cannot find remote "${remote}". Check that the remote name is correct in your module federation config file.\n`);
39
+ }
34
40
  const serveTarget = remoteConfiguration?.targets?.[target];
35
41
  if (!serveTarget) {
36
42
  throw new Error(`Cannot automatically determine URL of remote (${remote}). Looked for property "host" in the project's "serve" target.\n