@nx/next 17.0.2 → 17.0.4

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 (73) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +9 -4
  3. package/generators.json +2 -2
  4. package/migrations.json +24 -0
  5. package/package.json +12 -10
  6. package/plugin.d.ts +1 -0
  7. package/plugin.js +5 -0
  8. package/plugins/component-testing.d.ts +1 -11
  9. package/plugins/component-testing.js +26 -10
  10. package/plugins/with-nx.d.ts +1 -1
  11. package/plugins/with-nx.js +68 -86
  12. package/plugins/with-stylus.js +1 -1
  13. package/src/executors/build/build.impl.js +20 -9
  14. package/src/executors/build/lib/create-next-config-file.js +5 -2
  15. package/src/executors/build/lib/test-fixtures/ensure-exts/baz.json +1 -0
  16. package/src/executors/build/lib/update-package-json.js +10 -1
  17. package/src/executors/build/schema.json +1 -1
  18. package/src/executors/export/export.impl.js +9 -9
  19. package/src/executors/server/custom-server.impl.js +3 -2
  20. package/src/executors/server/schema.json +4 -0
  21. package/src/executors/server/server.impl.js +13 -11
  22. package/src/generators/application/application.js +24 -0
  23. package/src/generators/application/files/app/page.tsx__tmpl__ +1 -1
  24. package/src/generators/application/files/common/specs/__fileName__.spec.tsx__tmpl__ +10 -3
  25. package/src/generators/application/files/common/tsconfig.json__tmpl__ +5 -5
  26. package/src/generators/application/files/pages/__fileName__.tsx__tmpl__ +1 -1
  27. package/src/generators/application/lib/add-e2e.js +27 -3
  28. package/src/generators/application/lib/add-linting.js +13 -16
  29. package/src/generators/application/lib/add-plugin.d.ts +2 -0
  30. package/src/generators/application/lib/add-plugin.js +25 -0
  31. package/src/generators/application/lib/add-project.js +43 -33
  32. package/src/generators/application/lib/create-application-files.helpers.js +67 -5
  33. package/src/generators/application/lib/create-application-files.js +23 -11
  34. package/src/generators/application/lib/normalize-options.d.ts +3 -0
  35. package/src/generators/application/lib/normalize-options.js +31 -0
  36. package/src/generators/application/schema.d.ts +2 -0
  37. package/src/generators/application/schema.json +9 -3
  38. package/src/generators/component/component.d.ts +4 -4
  39. package/src/generators/component/component.js +3 -2
  40. package/src/generators/component/schema.json +7 -7
  41. package/src/generators/custom-server/custom-server.d.ts +1 -1
  42. package/src/generators/custom-server/custom-server.js +34 -9
  43. package/src/generators/custom-server/files/server/main.ts__tmpl__ +4 -4
  44. package/src/generators/custom-server/files/tsconfig.server.json__tmpl__ +2 -0
  45. package/src/generators/custom-server/schema.json +1 -1
  46. package/src/generators/cypress-component-configuration/cypress-component-configuration.d.ts +1 -0
  47. package/src/generators/cypress-component-configuration/cypress-component-configuration.js +23 -10
  48. package/src/generators/cypress-component-configuration/schema.d.ts +1 -0
  49. package/src/generators/cypress-component-configuration/schema.json +1 -1
  50. package/src/generators/init/init.d.ts +4 -3
  51. package/src/generators/init/init.js +30 -44
  52. package/src/generators/init/lib/add-plugin.d.ts +2 -0
  53. package/src/generators/init/lib/add-plugin.js +26 -0
  54. package/src/generators/init/schema.d.ts +3 -4
  55. package/src/generators/init/schema.json +11 -23
  56. package/src/generators/library/lib/normalize-options.js +5 -0
  57. package/src/generators/library/library.js +19 -1
  58. package/src/generators/library/schema.d.ts +2 -1
  59. package/src/generators/library/schema.json +3 -3
  60. package/src/generators/page/page.js +21 -4
  61. package/src/generators/page/schema.d.ts +3 -3
  62. package/src/generators/page/schema.json +5 -5
  63. package/src/migrations/update-17-2-7/remove-eslint-rules-patch.d.ts +2 -0
  64. package/src/migrations/update-17-2-7/remove-eslint-rules-patch.js +15 -0
  65. package/src/plugins/plugin.d.ts +11 -0
  66. package/src/plugins/plugin.js +184 -0
  67. package/src/utils/add-gitignore-entry.js +1 -1
  68. package/src/utils/add-swc-to-custom-server.d.ts +2 -0
  69. package/src/utils/add-swc-to-custom-server.js +37 -0
  70. package/src/utils/styles.d.ts +4 -4
  71. package/src/utils/types.d.ts +1 -0
  72. package/src/utils/versions.d.ts +6 -2
  73. package/src/utils/versions.js +7 -3
@@ -9,6 +9,14 @@ function createApplicationFiles(host, options) {
9
9
  const offsetFromRoot = (0, devkit_1.offsetFromRoot)(options.appProjectRoot);
10
10
  const layoutTypeSrcPath = (0, devkit_1.joinPathFragments)(offsetFromRoot, options.appProjectRoot, '.next/types/**/*.ts');
11
11
  const layoutTypeDistPath = (0, devkit_1.joinPathFragments)(offsetFromRoot, options.outputPath, '.next/types/**/*.ts');
12
+ // scope tsconfig to the project directory so that it doesn't include other projects/libs
13
+ const rootPath = options.rootProject
14
+ ? options.src
15
+ ? 'src/'
16
+ : options.appDir
17
+ ? 'app/'
18
+ : 'pages/'
19
+ : '';
12
20
  const templateVariables = {
13
21
  ...(0, devkit_1.names)(options.name),
14
22
  ...options,
@@ -16,6 +24,7 @@ function createApplicationFiles(host, options) {
16
24
  tmpl: '',
17
25
  offsetFromRoot,
18
26
  layoutTypeSrcPath,
27
+ rootPath,
19
28
  layoutTypeDistPath,
20
29
  rootTsConfigPath: (0, js_1.getRelativePathToRootTsConfig)(host, options.appProjectRoot),
21
30
  appContent: (0, create_application_files_helpers_1.createAppJsx)(options.projectName),
@@ -23,23 +32,27 @@ function createApplicationFiles(host, options) {
23
32
  pageStyleContent: `.page {}`,
24
33
  stylesExt: options.style === 'less' ? options.style : 'css',
25
34
  };
35
+ const generatedAppFilePath = options.src
36
+ ? (0, path_1.join)(options.appProjectRoot, 'src')
37
+ : options.appProjectRoot;
26
38
  (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/common'), options.appProjectRoot, templateVariables);
27
39
  if (options.appDir) {
28
- (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/app'), (0, path_1.join)(options.appProjectRoot, 'app'), templateVariables);
29
- // RSC is not possible to unit test without extra helpers for data fetching. Leaving it to the user to figure out.
30
- host.delete((0, devkit_1.joinPathFragments)(options.appProjectRoot, 'specs', `index.spec.${options.js ? 'jsx' : 'tsx'}`));
40
+ (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/app'), (0, path_1.join)(generatedAppFilePath, 'app'), templateVariables);
41
+ if (options.unitTestRunner === 'none') {
42
+ host.delete((0, devkit_1.joinPathFragments)(options.appProjectRoot, 'specs', `index.spec.${options.js ? 'jsx' : 'tsx'}`));
43
+ }
31
44
  if (options.style === 'styled-components') {
32
- (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/app-styled-components'), (0, path_1.join)(options.appProjectRoot, 'app'), templateVariables);
45
+ (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/app-styled-components'), (0, path_1.join)(generatedAppFilePath, 'app'), templateVariables);
33
46
  }
34
47
  else if (options.style === 'styled-jsx') {
35
- (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/app-styled-jsx'), (0, path_1.join)(options.appProjectRoot, 'app'), templateVariables);
48
+ (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/app-styled-jsx'), (0, path_1.join)(generatedAppFilePath, 'app'), templateVariables);
36
49
  }
37
50
  else {
38
- (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/app-default-layout'), (0, path_1.join)(options.appProjectRoot, 'app'), templateVariables);
51
+ (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/app-default-layout'), (0, path_1.join)(generatedAppFilePath, 'app'), templateVariables);
39
52
  }
40
53
  }
41
54
  else {
42
- (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/pages'), (0, path_1.join)(options.appProjectRoot, 'pages'), templateVariables);
55
+ (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/pages'), (0, path_1.join)(generatedAppFilePath, 'pages'), templateVariables);
43
56
  }
44
57
  if (options.rootProject) {
45
58
  (0, devkit_1.updateJson)(host, 'tsconfig.base.json', (json) => {
@@ -64,7 +77,6 @@ function createApplicationFiles(host, options) {
64
77
  ...new Set([
65
78
  ...(updatedJson.exclude || []),
66
79
  ...(appJSON.exclude || []),
67
- '**e2e/**/*',
68
80
  `dist/${options.projectName}/**/*`,
69
81
  ]),
70
82
  ],
@@ -84,14 +96,14 @@ function createApplicationFiles(host, options) {
84
96
  }
85
97
  if (options.styledModule) {
86
98
  if (options.appDir) {
87
- host.delete(`${options.appProjectRoot}/app/page.module.${options.style}`);
99
+ host.delete(`${generatedAppFilePath}/app/page.module.${options.style}`);
88
100
  }
89
101
  else {
90
- host.delete(`${options.appProjectRoot}/pages/${options.fileName}.module.${options.style}`);
102
+ host.delete(`${generatedAppFilePath}/pages/${options.fileName}.module.${options.style}`);
91
103
  }
92
104
  }
93
105
  if (options.style !== 'styled-components') {
94
- host.delete(`${options.appProjectRoot}/pages/_document.tsx`);
106
+ host.delete(`${generatedAppFilePath}/pages/_document.tsx`);
95
107
  }
96
108
  if (options.js) {
97
109
  host.delete(`${options.appProjectRoot}/index.d.ts`);
@@ -6,6 +6,9 @@ export interface NormalizedSchema extends Schema {
6
6
  outputPath: string;
7
7
  e2eProjectName: string;
8
8
  e2eProjectRoot: string;
9
+ e2eWebServerAddress: string;
10
+ e2eWebServerTarget: string;
11
+ e2ePort: number;
9
12
  parsedTags: string[];
10
13
  fileName: string;
11
14
  styledModule: null | string;
@@ -16,8 +16,34 @@ async function normalizeOptions(host, options) {
16
16
  });
17
17
  options.rootProject = appProjectRoot === '.';
18
18
  options.projectNameAndRootFormat = projectNameAndRootFormat;
19
+ const nxJson = (0, devkit_1.readNxJson)(host);
20
+ const addPlugin = process.env.NX_ADD_PLUGINS !== 'false' &&
21
+ nxJson.useInferencePlugins !== false;
22
+ options.addPlugin ??= addPlugin;
23
+ let e2eWebServerTarget = options.addPlugin ? 'start' : 'serve';
24
+ if (options.addPlugin) {
25
+ if (nxJson.plugins) {
26
+ for (const plugin of nxJson.plugins) {
27
+ if (typeof plugin === 'object' &&
28
+ plugin.plugin === '@nx/next/plugin' &&
29
+ plugin.options.startTargetName) {
30
+ e2eWebServerTarget = plugin.options
31
+ .startTargetName;
32
+ }
33
+ }
34
+ }
35
+ }
36
+ let e2ePort = options.addPlugin ? 3000 : 4200;
37
+ if (nxJson.targetDefaults?.[e2eWebServerTarget] &&
38
+ (nxJson.targetDefaults?.[e2eWebServerTarget].options?.port ||
39
+ nxJson.targetDefaults?.[e2eWebServerTarget].options?.env?.PORT)) {
40
+ e2ePort =
41
+ nxJson.targetDefaults?.[e2eWebServerTarget].options?.port ||
42
+ nxJson.targetDefaults?.[e2eWebServerTarget].options?.env?.PORT;
43
+ }
19
44
  const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
20
45
  const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
46
+ const e2eWebServerAddress = `http://localhost:${e2ePort}`;
21
47
  const name = (0, devkit_1.names)(options.name).fileName;
22
48
  const outputPath = (0, devkit_1.joinPathFragments)('dist', appProjectRoot, ...(options.rootProject ? [name] : []));
23
49
  const parsedTags = options.tags
@@ -25,6 +51,7 @@ async function normalizeOptions(host, options) {
25
51
  : [];
26
52
  const fileName = 'index';
27
53
  const appDir = options.appDir ?? true;
54
+ const src = options.src ?? true;
28
55
  const styledModule = /^(css|scss|less)$/.test(options.style)
29
56
  ? null
30
57
  : options.style;
@@ -32,9 +59,13 @@ async function normalizeOptions(host, options) {
32
59
  return {
33
60
  ...options,
34
61
  appDir,
62
+ src,
35
63
  appProjectRoot,
36
64
  e2eProjectName,
37
65
  e2eProjectRoot,
66
+ e2eWebServerAddress,
67
+ e2eWebServerTarget,
68
+ e2ePort,
38
69
  e2eTestRunner: options.e2eTestRunner || 'cypress',
39
70
  fileName,
40
71
  linter: options.linter || eslint_1.Linter.EsLint,
@@ -18,5 +18,7 @@ export interface Schema {
18
18
  customServer?: boolean;
19
19
  skipPackageJson?: boolean;
20
20
  appDir?: boolean;
21
+ src?: boolean;
21
22
  rootProject?: boolean;
23
+ addPlugin?: boolean;
22
24
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "http://json-schema.org/schema",
2
+ "$schema": "https://json-schema.org/schema",
3
3
  "cli": "nx",
4
4
  "$id": "NxNextApp",
5
5
  "title": "Create a Next.js Application for Nx",
@@ -40,11 +40,11 @@
40
40
  { "value": "css", "label": "CSS" },
41
41
  {
42
42
  "value": "scss",
43
- "label": "SASS(.scss) [ http://sass-lang.com ]"
43
+ "label": "SASS(.scss) [ https://sass-lang.com ]"
44
44
  },
45
45
  {
46
46
  "value": "less",
47
- "label": "LESS [ http://lesscss.org ]"
47
+ "label": "LESS [ https://lesscss.org ]"
48
48
  },
49
49
  {
50
50
  "value": "styled-components",
@@ -127,6 +127,12 @@
127
127
  "description": "Enable the App Router for this project.",
128
128
  "x-prompt": "Would you like to use the App Router (recommended)?"
129
129
  },
130
+ "src": {
131
+ "type": "boolean",
132
+ "default": true,
133
+ "description": "Generate a `src` directory for the project.",
134
+ "x-prompt": "Would you like to use `src/` directory?"
135
+ },
130
136
  "rootProject": {
131
137
  "description": "Create an application at the root of the workspace.",
132
138
  "type": "boolean",
@@ -3,21 +3,21 @@ import type { SupportedStyles } from '@nx/react';
3
3
  interface Schema {
4
4
  name: string;
5
5
  /**
6
- * @deprecated Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v18.
6
+ * @deprecated Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v19.
7
7
  */
8
8
  project?: string;
9
9
  style: SupportedStyles;
10
10
  directory?: string;
11
11
  /**
12
- * @deprecated Provide the `directory` option instead and use the `as-provided` format. This option will be removed in Nx v18.
12
+ * @deprecated Provide the `directory` option instead and use the `as-provided` format. This option will be removed in Nx v19.
13
13
  */
14
14
  flat?: boolean;
15
15
  /**
16
- * @deprecated Provide the `name` in pascal-case and use the `as-provided` format. This option will be removed in Nx v18.
16
+ * @deprecated Provide the `name` in pascal-case and use the `as-provided` format. This option will be removed in Nx v19.
17
17
  */
18
18
  pascalCaseFiles?: boolean;
19
19
  /**
20
- * @deprecated Provide the `directory` in pascal-case and use the `as-provided` format. This option will be removed in Nx v18.
20
+ * @deprecated Provide the `directory` in pascal-case and use the `as-provided` format. This option will be removed in Nx v19.
21
21
  */
22
22
  pascalCaseDirectory?: boolean;
23
23
  nameAndDirectoryFormat?: 'as-provided' | 'derived';
@@ -5,7 +5,7 @@ const devkit_1 = require("@nx/devkit");
5
5
  const react_1 = require("@nx/react");
6
6
  const styles_1 = require("../../utils/styles");
7
7
  const artifact_name_and_directory_utils_1 = require("@nx/devkit/src/generators/artifact-name-and-directory-utils");
8
- // TODO(v18): Remove this logic once we no longer derive directory.
8
+ // TODO(v19): Remove this logic once we no longer derive directory.
9
9
  function maybeGetDerivedDirectory(host, options) {
10
10
  if (!options.project)
11
11
  return options.directory;
@@ -44,7 +44,8 @@ async function componentGeneratorInternal(host, options) {
44
44
  });
45
45
  const componentInstall = await (0, react_1.componentGenerator)(host, {
46
46
  ...options,
47
- nameAndDirectoryFormat: 'as-provided',
47
+ name,
48
+ nameAndDirectoryFormat: 'as-provided', // already determined the directory so use as is
48
49
  project: undefined,
49
50
  directory,
50
51
  classComponent: false,
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "http://json-schema.org/schema",
2
+ "$schema": "https://json-schema.org/schema",
3
3
  "cli": "nx",
4
4
  "$id": "NxNextReactComponent",
5
5
  "title": "Create a React Component for Next",
@@ -13,7 +13,7 @@
13
13
  "$default": {
14
14
  "$source": "projectName"
15
15
  },
16
- "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v18."
16
+ "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v19."
17
17
  },
18
18
  "name": {
19
19
  "type": "string",
@@ -40,11 +40,11 @@
40
40
  },
41
41
  {
42
42
  "value": "scss",
43
- "label": "SASS(.scss) [ http://sass-lang.com ]"
43
+ "label": "SASS(.scss) [ https://sass-lang.com ]"
44
44
  },
45
45
  {
46
46
  "value": "less",
47
- "label": "LESS [ http://lesscss.org ]"
47
+ "label": "LESS [ https://lesscss.org ]"
48
48
  },
49
49
  {
50
50
  "value": "styled-components",
@@ -97,21 +97,21 @@
97
97
  "type": "boolean",
98
98
  "description": "Create component at the source root rather than its own directory.",
99
99
  "default": false,
100
- "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. This option will be removed in Nx v18."
100
+ "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. This option will be removed in Nx v19."
101
101
  },
102
102
  "pascalCaseFiles": {
103
103
  "type": "boolean",
104
104
  "description": "Use pascal case component file name (e.g. `App.tsx`).",
105
105
  "alias": "P",
106
106
  "default": false,
107
- "x-deprecated": "Provide the `name` in pascal-case and use the `as-provided` format. This option will be removed in Nx v18."
107
+ "x-deprecated": "Provide the `name` in pascal-case and use the `as-provided` format. This option will be removed in Nx v19."
108
108
  },
109
109
  "pascalCaseDirectory": {
110
110
  "type": "boolean",
111
111
  "description": "Use pascal case directory name (e.g. `App/App.tsx`).",
112
112
  "alias": "R",
113
113
  "default": false,
114
- "x-deprecated": "Provide the `directory` in pascal-case and use the `as-provided` format. This option will be removed in Nx v18."
114
+ "x-deprecated": "Provide the `directory` in pascal-case and use the `as-provided` format. This option will be removed in Nx v19."
115
115
  },
116
116
  "skipFormat": {
117
117
  "description": "Skip formatting files.",
@@ -1,3 +1,3 @@
1
1
  import type { Tree } from '@nx/devkit';
2
2
  import { CustomServerSchema } from './schema';
3
- export declare function customServerGenerator(host: Tree, options: CustomServerSchema): Promise<void>;
3
+ export declare function customServerGenerator(host: Tree, options: CustomServerSchema): Promise<() => void>;
@@ -3,19 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.customServerGenerator = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const path_1 = require("path");
6
+ const add_swc_to_custom_server_1 = require("../../utils/add-swc-to-custom-server");
6
7
  async function customServerGenerator(host, options) {
7
8
  const project = (0, devkit_1.readProjectConfiguration)(host, options.project);
9
+ const nxJson = (0, devkit_1.readNxJson)(host);
10
+ const hasPlugin = nxJson.plugins?.some((p) => typeof p === 'string'
11
+ ? p === '@nx/next/plugin'
12
+ : p.plugin === '@nx/next/plugin');
8
13
  if (project.targets?.build?.executor !== '@nx/next:build' &&
9
- project.targets?.build?.executor !== '@nrwl/next:build') {
14
+ project.targets?.build?.executor !== '@nrwl/next:build' &&
15
+ !hasPlugin) {
10
16
  devkit_1.logger.error(`Project ${options.project} is not a Next.js project. Did you generate it with "nx g @nx/next:app"?`);
11
17
  return;
12
18
  }
13
- const outputPath = project.targets?.build?.options?.outputPath;
19
+ // In Nx 18 next artifacts are inside the project root .next/ & dist/ (for custom server)
20
+ const outputPath = hasPlugin
21
+ ? `dist/${project.root}`
22
+ : project.targets?.build?.options?.outputPath;
14
23
  const root = project.root;
15
- if (!root ||
24
+ if ((!root ||
16
25
  !outputPath ||
17
26
  !project.targets?.build?.configurations?.development ||
18
- !project.targets?.build?.configurations?.production) {
27
+ !project.targets?.build?.configurations?.production) &&
28
+ !hasPlugin) {
19
29
  devkit_1.logger.error(`Project ${options.project} has invalid config. Did you generate it with "nx g @nx/next:app"?`);
20
30
  return;
21
31
  }
@@ -24,18 +34,30 @@ async function customServerGenerator(host, options) {
24
34
  devkit_1.logger.warn(`Project ${options.project} has custom server targets already: build-custom-server, serve-custom-server. Remove these targets from project and try again.`);
25
35
  return;
26
36
  }
37
+ // In Nx 18 next artifacts are inside the project root .next/ & dist/ (for custom server)
38
+ // So we need ensure the mapping is correct from dist to the project root
39
+ const projectPathFromDist = `../../${(0, devkit_1.offsetFromRoot)(project.root)}${project.root}`;
27
40
  (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, 'files'), project.root, {
28
41
  ...options,
42
+ hasPlugin,
43
+ projectPathFromDist,
29
44
  offsetFromRoot: (0, devkit_1.offsetFromRoot)(project.root),
30
45
  projectRoot: project.root,
31
46
  tmpl: '',
32
47
  });
33
- project.targets.build.dependsOn = ['build-custom-server'];
34
- project.targets.serve.options.customServerTarget = `${options.project}:serve-custom-server`;
35
- project.targets.serve.configurations.development.customServerTarget = `${options.project}:serve-custom-server:development`;
36
- project.targets.serve.configurations.production.customServerTarget = `${options.project}:serve-custom-server:production`;
48
+ if (!hasPlugin) {
49
+ project.targets.build.dependsOn = ['build-custom-server'];
50
+ project.targets.serve.options.customServerTarget = `${options.project}:serve-custom-server`;
51
+ project.targets.serve.configurations.development.customServerTarget = `${options.project}:serve-custom-server:development`;
52
+ project.targets.serve.configurations.production.customServerTarget = `${options.project}:serve-custom-server:production`;
53
+ }
54
+ else {
55
+ project.targets['build'] = {
56
+ dependsOn: ['^build', 'build-custom-server'],
57
+ };
58
+ }
37
59
  project.targets['build-custom-server'] = {
38
- executor: '@nx/js:tsc',
60
+ executor: options.compiler === 'tsc' ? '@nx/js:tsc' : '@nx/js:swc',
39
61
  defaultConfiguration: 'production',
40
62
  options: {
41
63
  outputPath,
@@ -75,5 +97,8 @@ async function customServerGenerator(host, options) {
75
97
  json.targetDefaults['build-custom-server'].cache ??= true;
76
98
  return json;
77
99
  });
100
+ if (options.compiler === 'swc') {
101
+ return (0, add_swc_to_custom_server_1.configureForSwc)(host, project.root);
102
+ }
78
103
  }
79
104
  exports.customServerGenerator = customServerGenerator;
@@ -2,9 +2,8 @@
2
2
  * This is only a minimal custom server to get started.
3
3
  * You may want to consider using Express or another server framework, and enable security features such as CORS.
4
4
  *
5
- * For more examples, see the Next.js repo:
6
- * - Express: https://github.com/vercel/next.js/tree/canary/examples/custom-server-express
7
- * - Hapi: https://github.com/vercel/next.js/tree/canary/examples/custom-server-hapi
5
+ * For an example, see the Next.js repo:
6
+ * Node - https://github.com/vercel/next.js/blob/canary/examples/custom-server
8
7
  */
9
8
  import { createServer } from 'http';
10
9
  import { parse } from 'node:url';
@@ -15,7 +14,8 @@ import next from 'next';
15
14
  // - The environment variable is set by `@nx/next:server` when running the dev server.
16
15
  // - The fallback `__dirname` is for production builds.
17
16
  // - Feel free to change this to suit your needs.
18
- const dir = process.env.NX_NEXT_DIR || path.join(__dirname, '..');
17
+
18
+ const dir = process.env.NX_NEXT_DIR || <%- hasPlugin ? `path.join(__dirname, '${projectPathFromDist}')` : `path.join(__dirname, '..')`; %>
19
19
  const dev = process.env.NODE_ENV === 'development';
20
20
 
21
21
  // HTTP Server options:
@@ -4,7 +4,9 @@
4
4
  "module": "commonjs",
5
5
  "noEmit": false,
6
6
  "incremental": true,
7
+ <% if(hasPlugin && compiler === 'tsc') { %>
7
8
  "tsBuildInfoFile": "<%= offsetFromRoot %>tmp/buildcache/<%= projectRoot %>/server",
9
+ <% } %>
8
10
  "types": [
9
11
  "node"
10
12
  ]
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "http://json-schema.org/schema",
2
+ "$schema": "https://json-schema.org/schema",
3
3
  "cli": "nx",
4
4
  "$id": "NxNextCustomServer",
5
5
  "title": "Add custom server",
@@ -1,4 +1,5 @@
1
1
  import { GeneratorCallback, Tree } from '@nx/devkit';
2
2
  import { CypressComponentConfigurationGeneratorSchema } from './schema';
3
3
  export declare function cypressComponentConfiguration(tree: Tree, options: CypressComponentConfigurationGeneratorSchema): Promise<GeneratorCallback>;
4
+ export declare function cypressComponentConfigurationInternal(tree: Tree, options: CypressComponentConfigurationGeneratorSchema): Promise<GeneratorCallback>;
4
5
  export default cypressComponentConfiguration;
@@ -1,38 +1,51 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.cypressComponentConfiguration = void 0;
3
+ exports.cypressComponentConfigurationInternal = exports.cypressComponentConfiguration = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const ct_utils_1 = require("@nx/react/src/utils/ct-utils");
6
6
  const versions_1 = require("../../utils/versions");
7
7
  const react_1 = require("@nx/react");
8
8
  const path_1 = require("path");
9
- async function cypressComponentConfiguration(tree, options) {
9
+ function cypressComponentConfiguration(tree, options) {
10
+ return cypressComponentConfigurationInternal(tree, {
11
+ addPlugin: false,
12
+ ...options,
13
+ });
14
+ }
15
+ exports.cypressComponentConfiguration = cypressComponentConfiguration;
16
+ async function cypressComponentConfigurationInternal(tree, options) {
10
17
  const tasks = [];
11
18
  const { componentConfigurationGenerator: baseCyCtConfig } = (0, devkit_1.ensurePackage)('@nx/cypress', versions_1.nxVersion);
12
19
  tasks.push(await baseCyCtConfig(tree, {
13
20
  project: options.project,
14
21
  skipFormat: true,
22
+ framework: 'next',
15
23
  jsx: true,
24
+ addPlugin: options.addPlugin,
16
25
  }));
17
26
  const { webpackInitGenerator } = (0, devkit_1.ensurePackage)('@nx/webpack', versions_1.nxVersion);
18
27
  tasks.push(await webpackInitGenerator(tree, {
19
- compiler: 'swc',
20
- uiFramework: 'react',
21
28
  skipFormat: true,
29
+ addPlugin: options.addPlugin,
22
30
  }));
31
+ const { ensureDependencies } = await Promise.resolve().then(() => require('@nx/webpack/src/utils/ensure-dependencies'));
32
+ tasks.push(ensureDependencies(tree, { compiler: 'swc', uiFramework: 'react' }));
23
33
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
24
- projectConfig.targets['component-test'].options = {
25
- ...projectConfig.targets['component-test'].options,
26
- skipServe: true,
27
- };
28
- (0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
34
+ if (projectConfig.targets?.['component-test']?.executor ===
35
+ '@nx/cypress:cypress') {
36
+ projectConfig.targets['component-test'].options = {
37
+ ...projectConfig.targets['component-test'].options,
38
+ skipServe: true,
39
+ };
40
+ (0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
41
+ }
29
42
  await addFiles(tree, projectConfig, options);
30
43
  if (!options.skipFormat) {
31
44
  await (0, devkit_1.formatFiles)(tree);
32
45
  }
33
46
  return (0, devkit_1.runTasksInSerial)(...tasks);
34
47
  }
35
- exports.cypressComponentConfiguration = cypressComponentConfiguration;
48
+ exports.cypressComponentConfigurationInternal = cypressComponentConfigurationInternal;
36
49
  async function addFiles(tree, projectConfig, opts) {
37
50
  const { addMountDefinition, addDefaultCTConfig } = await Promise.resolve().then(() => require('@nx/cypress/src/utils/config'));
38
51
  const ctFile = (0, devkit_1.joinPathFragments)(projectConfig.root, 'cypress', 'support', 'component.ts');
@@ -2,4 +2,5 @@ export interface CypressComponentConfigurationGeneratorSchema {
2
2
  project: string;
3
3
  generateTests: boolean;
4
4
  skipFormat?: boolean;
5
+ addPlugin?: boolean;
5
6
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "http://json-schema.org/schema",
2
+ "$schema": "https://json-schema.org/schema",
3
3
  "cli": "nx",
4
4
  "$id": "CypressComponentConfiguration",
5
5
  "title": "NextJS Component Testing Configuration",
@@ -1,4 +1,5 @@
1
- import { GeneratorCallback, Tree } from '@nx/devkit';
2
- import { InitSchema } from './schema';
3
- export declare function nextInitGenerator(host: Tree, schema: InitSchema): Promise<GeneratorCallback>;
1
+ import { type GeneratorCallback, type Tree } from '@nx/devkit';
2
+ import type { InitSchema } from './schema';
3
+ export declare function nextInitGenerator(tree: Tree, schema: InitSchema): Promise<GeneratorCallback>;
4
+ export declare function nextInitGeneratorInternal(host: Tree, schema: InitSchema): Promise<GeneratorCallback>;
4
5
  export default nextInitGenerator;
@@ -1,60 +1,46 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.nextInitGenerator = void 0;
3
+ exports.nextInitGeneratorInternal = exports.nextInitGenerator = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
+ const update_package_scripts_1 = require("@nx/devkit/src/utils/update-package-scripts");
5
6
  const versions_1 = require("@nx/react/src/utils/versions");
6
- const init_1 = require("@nx/react/src/generators/init/init");
7
- const js_1 = require("@nx/js");
8
- const versions_2 = require("../../utils/versions");
9
7
  const add_gitignore_entry_1 = require("../../utils/add-gitignore-entry");
10
- function updateDependencies(host) {
11
- return (0, devkit_1.addDependenciesToPackageJson)(host, {
8
+ const versions_2 = require("../../utils/versions");
9
+ const add_plugin_1 = require("./lib/add-plugin");
10
+ function updateDependencies(host, schema) {
11
+ const tasks = [];
12
+ tasks.push((0, devkit_1.removeDependenciesFromPackageJson)(host, ['@nx/next'], []));
13
+ tasks.push((0, devkit_1.addDependenciesToPackageJson)(host, {
12
14
  next: versions_2.nextVersion,
13
15
  react: versions_1.reactVersion,
14
16
  'react-dom': versions_1.reactDomVersion,
15
- tslib: versions_2.tsLibVersion,
16
17
  }, {
17
18
  '@nx/next': versions_2.nxVersion,
18
- 'eslint-config-next': versions_2.eslintConfigNextVersion,
19
- });
19
+ }, undefined, schema.keepExistingVersions));
20
+ return (0, devkit_1.runTasksInSerial)(...tasks);
20
21
  }
21
- async function nextInitGenerator(host, schema) {
22
- const tasks = [];
23
- tasks.push(await (0, js_1.initGenerator)(host, {
24
- ...schema,
25
- skipFormat: true,
26
- }));
27
- if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') {
28
- const { jestInitGenerator } = (0, devkit_1.ensurePackage)('@nx/jest', versions_2.nxVersion);
29
- const jestTask = await jestInitGenerator(host, schema);
30
- tasks.push(jestTask);
31
- }
32
- if (schema.e2eTestRunner === 'cypress') {
33
- const { cypressInitGenerator } = (0, devkit_1.ensurePackage)('@nx/cypress', versions_2.nxVersion);
34
- const cypressTask = await cypressInitGenerator(host, {});
35
- tasks.push(cypressTask);
36
- }
37
- else if (schema.e2eTestRunner === 'playwright') {
38
- const { initGenerator } = (0, devkit_1.ensurePackage)('@nx/playwright', versions_2.nxVersion);
39
- const playwrightTask = await initGenerator(host, {
40
- skipFormat: true,
41
- skipPackageJson: schema.skipPackageJson,
42
- });
43
- tasks.push(playwrightTask);
22
+ function nextInitGenerator(tree, schema) {
23
+ return nextInitGeneratorInternal(tree, { addPlugin: false, ...schema });
24
+ }
25
+ exports.nextInitGenerator = nextInitGenerator;
26
+ async function nextInitGeneratorInternal(host, schema) {
27
+ const nxJson = (0, devkit_1.readNxJson)(host);
28
+ const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
29
+ nxJson.useInferencePlugins !== false;
30
+ schema.addPlugin ??= addPluginDefault;
31
+ if (schema.addPlugin) {
32
+ (0, add_plugin_1.addPlugin)(host);
44
33
  }
45
- // @ts-ignore
46
- // TODO(jack): remove once the React Playwright PR lands first
47
- const reactTask = await (0, init_1.default)(host, {
48
- ...schema,
49
- skipFormat: true,
50
- });
51
- tasks.push(reactTask);
34
+ (0, add_gitignore_entry_1.addGitIgnoreEntry)(host);
35
+ let installTask = () => { };
52
36
  if (!schema.skipPackageJson) {
53
- const installTask = updateDependencies(host);
54
- tasks.push(installTask);
37
+ installTask = updateDependencies(host, schema);
55
38
  }
56
- (0, add_gitignore_entry_1.addGitIgnoreEntry)(host);
57
- return (0, devkit_1.runTasksInSerial)(...tasks);
39
+ if (schema.updatePackageScripts) {
40
+ const { createNodes } = await Promise.resolve().then(() => require('../../plugins/plugin'));
41
+ await (0, update_package_scripts_1.updatePackageScripts)(host, createNodes);
42
+ }
43
+ return installTask;
58
44
  }
59
- exports.nextInitGenerator = nextInitGenerator;
45
+ exports.nextInitGeneratorInternal = nextInitGeneratorInternal;
60
46
  exports.default = nextInitGenerator;
@@ -0,0 +1,2 @@
1
+ import { Tree } from '@nx/devkit';
2
+ export declare function addPlugin(tree: Tree): void;