@nx/next 18.0.3 → 18.0.5

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/migrations.json CHANGED
@@ -92,6 +92,15 @@
92
92
  "alwaysAddToPackageJson": false
93
93
  }
94
94
  }
95
+ },
96
+ "18.0.4": {
97
+ "version": "18.0.4-beta.0",
98
+ "packages": {
99
+ "@swc-node/register": {
100
+ "version": "~1.8.0",
101
+ "alwaysAddToPackageJson": false
102
+ }
103
+ }
95
104
  }
96
105
  }
97
106
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/next",
3
- "version": "18.0.3",
3
+ "version": "18.0.5",
4
4
  "private": false,
5
5
  "description": "The Next.js plugin for Nx contains executors and generators for managing Next.js applications and libraries within an Nx workspace. It provides:\n\n\n- Scaffolding for creating, building, serving, linting, and testing Next.js applications.\n\n- Integration with building, serving, and exporting a Next.js application.\n\n- Integration with React libraries within the workspace. \n\nWhen using Next.js in Nx, you get the out-of-the-box support for TypeScript, Cypress, and Jest. No need to configure anything: watch mode, source maps, and typings just work.",
6
6
  "repository": {
@@ -34,7 +34,7 @@
34
34
  "next": ">=14.0.0"
35
35
  },
36
36
  "dependencies": {
37
- "@nx/devkit": "18.0.3",
37
+ "@nx/devkit": "18.0.5",
38
38
  "@babel/plugin-proposal-decorators": "^7.22.7",
39
39
  "@svgr/webpack": "^8.0.1",
40
40
  "chalk": "^4.1.0",
@@ -45,13 +45,13 @@
45
45
  "url-loader": "^4.1.1",
46
46
  "tslib": "^2.3.0",
47
47
  "webpack-merge": "^5.8.0",
48
- "@nx/js": "18.0.3",
49
- "@nx/eslint": "18.0.3",
50
- "@nx/react": "18.0.3",
51
- "@nx/web": "18.0.3",
52
- "@nx/webpack": "18.0.3",
53
- "@nx/workspace": "18.0.3",
54
- "@nrwl/next": "18.0.3"
48
+ "@nx/js": "18.0.5",
49
+ "@nx/eslint": "18.0.5",
50
+ "@nx/react": "18.0.5",
51
+ "@nx/web": "18.0.5",
52
+ "@nx/webpack": "18.0.5",
53
+ "@nx/workspace": "18.0.5",
54
+ "@nrwl/next": "18.0.5"
55
55
  },
56
56
  "publishConfig": {
57
57
  "access": "public"
@@ -119,6 +119,11 @@ function withNx(_nextConfig = {}, context = getWithNxContext()) {
119
119
  ? joinPathFragments(outputDir, nextConfig.distDir)
120
120
  : joinPathFragments(outputDir, '.next');
121
121
  }
122
+ // If we are running a static serve of the Next.js app, we need to change the output to 'export' and the distDir to 'out'.
123
+ if (process.env.NX_SERVE_STATIC_BUILD_RUNNING === 'true') {
124
+ nextConfig.output = 'export';
125
+ nextConfig.distDir = 'out';
126
+ }
122
127
  const userWebpackConfig = nextConfig.webpack;
123
128
  const { createWebpackConfig } = require('@nx/next/src/utils/config');
124
129
  nextConfig.webpack = (a, b) => createWebpackConfig(workspaceRoot, projectDirectory, options.fileReplacements, options.assets)(userWebpackConfig ? userWebpackConfig(a, b) : a, b);
@@ -219,39 +224,19 @@ function getNextConfig(nextConfig = {}, context = getWithNxContext()) {
219
224
  */
220
225
  // Default SVGR support to be on for projects.
221
226
  if (nx?.svgr !== false) {
222
- config.module.rules.push({
223
- test: /\.svg$/,
224
- oneOf: [
225
- // If coming from JS/TS file, then transform into React component using SVGR.
226
- {
227
- issuer: /\.[jt]sx?$/,
228
- use: [
229
- {
230
- loader: require.resolve('@svgr/webpack'),
231
- options: {
232
- svgo: false,
233
- titleProp: true,
234
- ref: true,
235
- },
236
- },
237
- {
238
- loader: require.resolve('url-loader'),
239
- options: {
240
- limit: 10000, // 10kB
241
- name: '[name].[hash:7].[ext]',
242
- },
243
- },
244
- ],
245
- },
246
- // Fallback to plain URL loader if someone just imports the SVG and references it on the <img src> tag
247
- {
248
- loader: require.resolve('url-loader'),
249
- options: {
250
- limit: 10000, // 10kB
251
- name: '[name].[hash:7].[ext]',
252
- },
253
- },
254
- ],
227
+ config.module.rules.push(
228
+ // Apply rule for svg imports ending in ?url
229
+ {
230
+ test: /\.svg$/i,
231
+ type: 'asset',
232
+ resourceQuery: /url/, // apply to *.svg?url
233
+ },
234
+ // Convert all other svg imports to React components
235
+ {
236
+ test: /\.svg$/i,
237
+ issuer: /\.[jt]sx?$/,
238
+ resourceQuery: { not: [/url/] },
239
+ use: ['@svgr/webpack'],
255
240
  });
256
241
  }
257
242
  return userWebpack(config, options);
@@ -41,7 +41,10 @@ function createNextConfigFile(options, context) {
41
41
  const moduleFilesToCopy = getRelativeFilesToCopy(configRelativeToProjectRoot, projectRoot);
42
42
  for (const moduleFile of moduleFilesToCopy) {
43
43
  (0, fs_extra_1.ensureDirSync)((0, path_1.dirname)((0, path_1.join)(context.root, options.outputPath, moduleFile)));
44
- (0, fs_extra_1.copyFileSync)((0, path_1.join)(context.root, projectRoot, moduleFile), (0, path_1.join)(context.root, options.outputPath, moduleFile));
44
+ // We already generate a build version of package.json in the dist folder.
45
+ if (moduleFile !== 'package.json') {
46
+ (0, fs_extra_1.copyFileSync)((0, path_1.join)(context.root, projectRoot, moduleFile), (0, path_1.join)(context.root, options.outputPath, moduleFile));
47
+ }
45
48
  }
46
49
  }
47
50
  exports.createNextConfigFile = createNextConfigFile;
@@ -4,6 +4,7 @@ exports.addE2e = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const eslint_1 = require("@nx/eslint");
6
6
  const versions_1 = require("../../../utils/versions");
7
+ const web_1 = require("@nx/web");
7
8
  async function addE2e(host, options) {
8
9
  const nxJson = (0, devkit_1.readNxJson)(host);
9
10
  const hasPlugin = nxJson.plugins?.some((p) => typeof p === 'string'
@@ -11,6 +12,13 @@ async function addE2e(host, options) {
11
12
  : p.plugin === '@nx/next/plugin');
12
13
  if (options.e2eTestRunner === 'cypress') {
13
14
  const { configurationGenerator } = (0, devkit_1.ensurePackage)('@nx/cypress', versions_1.nxVersion);
15
+ if (!hasPlugin) {
16
+ (0, web_1.webStaticServeGenerator)(host, {
17
+ buildTarget: `${options.projectName}:build`,
18
+ outputPath: `${options.outputPath}/out`,
19
+ targetName: 'serve-static',
20
+ });
21
+ }
14
22
  (0, devkit_1.addProjectConfiguration)(host, options.e2eProjectName, {
15
23
  root: options.e2eProjectRoot,
16
24
  sourceRoot: (0, devkit_1.joinPathFragments)(options.e2eProjectRoot, 'src'),
@@ -27,6 +35,14 @@ async function addE2e(host, options) {
27
35
  devServerTarget: `${options.projectName}:${hasPlugin ? 'start' : 'serve'}`,
28
36
  baseUrl: `http://localhost:${hasPlugin ? '3000' : '4200'}`,
29
37
  jsx: true,
38
+ webServerCommands: hasPlugin
39
+ ? {
40
+ default: `nx run ${options.projectName}:start`,
41
+ }
42
+ : undefined,
43
+ ciWebServerCommand: hasPlugin
44
+ ? `nx run ${options.projectName}:serve-static`
45
+ : undefined,
30
46
  });
31
47
  }
32
48
  else if (options.e2eTestRunner === 'playwright') {
@@ -304,7 +304,7 @@ function createAppJsx(name) {
304
304
  You can activate distributed tasks executions and caching by
305
305
  running:
306
306
  </p>
307
- <pre>nx connect-to-nx-cloud</pre>
307
+ <pre>nx connect</pre>
308
308
  <a
309
309
  href="https://nx.app/?utm_source=nx-project"
310
310
  target="_blank"
@@ -6,17 +6,26 @@ const path_1 = require("path");
6
6
  const add_swc_to_custom_server_1 = require("../../utils/add-swc-to-custom-server");
7
7
  async function customServerGenerator(host, options) {
8
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');
9
13
  if (project.targets?.build?.executor !== '@nx/next:build' &&
10
- project.targets?.build?.executor !== '@nrwl/next:build') {
14
+ project.targets?.build?.executor !== '@nrwl/next:build' &&
15
+ !hasPlugin) {
11
16
  devkit_1.logger.error(`Project ${options.project} is not a Next.js project. Did you generate it with "nx g @nx/next:app"?`);
12
17
  return;
13
18
  }
14
- 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;
15
23
  const root = project.root;
16
- if (!root ||
24
+ if ((!root ||
17
25
  !outputPath ||
18
26
  !project.targets?.build?.configurations?.development ||
19
- !project.targets?.build?.configurations?.production) {
27
+ !project.targets?.build?.configurations?.production) &&
28
+ !hasPlugin) {
20
29
  devkit_1.logger.error(`Project ${options.project} has invalid config. Did you generate it with "nx g @nx/next:app"?`);
21
30
  return;
22
31
  }
@@ -25,16 +34,28 @@ async function customServerGenerator(host, options) {
25
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.`);
26
35
  return;
27
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}`;
28
40
  (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, 'files'), project.root, {
29
41
  ...options,
42
+ hasPlugin,
43
+ projectPathFromDist,
30
44
  offsetFromRoot: (0, devkit_1.offsetFromRoot)(project.root),
31
45
  projectRoot: project.root,
32
46
  tmpl: '',
33
47
  });
34
- project.targets.build.dependsOn = ['build-custom-server'];
35
- project.targets.serve.options.customServerTarget = `${options.project}:serve-custom-server`;
36
- project.targets.serve.configurations.development.customServerTarget = `${options.project}:serve-custom-server:development`;
37
- 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
+ }
38
59
  project.targets['build-custom-server'] = {
39
60
  executor: options.compiler === 'tsc' ? '@nx/js:tsc' : '@nx/js:swc',
40
61
  defaultConfiguration: 'production',
@@ -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
  ]
@@ -18,6 +18,7 @@ function addPlugin(tree) {
18
18
  buildTargetName: 'build',
19
19
  devTargetName: 'dev',
20
20
  startTargetName: 'start',
21
+ serveStaticTargetName: 'serve-static',
21
22
  },
22
23
  });
23
24
  (0, devkit_1.updateNxJson)(tree, nxJson);
@@ -4,6 +4,7 @@ export interface NextPluginOptions {
4
4
  buildTargetName?: string;
5
5
  devTargetName?: string;
6
6
  startTargetName?: string;
7
+ serveStaticTargetName?: string;
7
8
  }
8
9
  export declare const createDependencies: CreateDependencies;
9
10
  export declare const createNodes: CreateNodes<NextPluginOptions>;
@@ -56,6 +56,7 @@ async function buildNextTargets(nextConfigPath, projectRoot, options, context) {
56
56
  targets[options.buildTargetName] = await getBuildTargetConfig(namedInputs, projectRoot, nextConfig);
57
57
  targets[options.devTargetName] = getDevTargetConfig(projectRoot);
58
58
  targets[options.startTargetName] = getStartTargetConfig(options, projectRoot);
59
+ targets[options.serveStaticTargetName] = getStaticServeTargetConfig(options);
59
60
  return targets;
60
61
  }
61
62
  async function getBuildTargetConfig(namedInputs, projectRoot, nextConfig) {
@@ -92,6 +93,17 @@ function getStartTargetConfig(options, projectRoot) {
92
93
  };
93
94
  return targetConfig;
94
95
  }
96
+ function getStaticServeTargetConfig(options) {
97
+ const targetConfig = {
98
+ executor: '@nx/web:file-server',
99
+ options: {
100
+ buildTarget: options.buildTargetName,
101
+ staticFilePath: '{projectRoot}/out',
102
+ port: 3000,
103
+ },
104
+ };
105
+ return targetConfig;
106
+ }
95
107
  async function getOutputs(projectRoot, nextConfig) {
96
108
  let dir = '.next';
97
109
  const { PHASE_PRODUCTION_BUILD } = require('next/constants');
@@ -129,6 +141,7 @@ function normalizeOptions(options) {
129
141
  options.buildTargetName ??= 'build';
130
142
  options.devTargetName ??= 'dev';
131
143
  options.startTargetName ??= 'start';
144
+ options.serveStaticTargetName ??= 'serve-static';
132
145
  return options;
133
146
  }
134
147
  function getInputs(namedInputs) {
@@ -10,7 +10,7 @@ function addGitIgnoreEntry(host) {
10
10
  const ig = (0, ignore_1.default)();
11
11
  ig.add(host.read('.gitignore', 'utf-8'));
12
12
  if (!ig.ignores('apps/example/.next')) {
13
- content = `${content}\n\n# Next.js\n.next\n`;
13
+ content = `${content}\n\n# Next.js\n.next\nout\n`;
14
14
  }
15
15
  host.write('.gitignore', content);
16
16
  }
@@ -12,7 +12,15 @@ function configureForSwc(tree, projectRoot) {
12
12
  const hasSwcCliDependency = rootPackageJson.dependencies?.['@swc/cli'] ||
13
13
  rootPackageJson.devDependencies?.['@swc/cli'];
14
14
  if (!tree.exists(swcConfigPath)) {
15
- (0, add_swc_config_1.addSwcConfig)(tree, swcConfigPath);
15
+ (0, add_swc_config_1.addSwcConfig)(tree, projectRoot);
16
+ }
17
+ if (tree.exists(swcConfigPath)) {
18
+ (0, devkit_1.updateJson)(tree, swcConfigPath, (json) => {
19
+ return {
20
+ ...json,
21
+ exclude: [...json.exclude, '.*.d.ts$'],
22
+ };
23
+ });
16
24
  }
17
25
  if (!hasSwcDepedency || !hasSwcCliDependency) {
18
26
  addSwcDependencies(tree);
@@ -9,4 +9,4 @@ export declare const tsLibVersion = "^2.3.0";
9
9
  export declare const swcCliVersion = "~0.1.62";
10
10
  export declare const swcCoreVersion = "~1.3.85";
11
11
  export declare const swcHelpersVersion = "~0.5.2";
12
- export declare const swcNodeVersion = "~1.6.7";
12
+ export declare const swcNodeVersion = "~1.8.0";
@@ -12,4 +12,4 @@ exports.tsLibVersion = '^2.3.0';
12
12
  exports.swcCliVersion = '~0.1.62';
13
13
  exports.swcCoreVersion = '~1.3.85';
14
14
  exports.swcHelpersVersion = '~0.5.2';
15
- exports.swcNodeVersion = '~1.6.7';
15
+ exports.swcNodeVersion = '~1.8.0';