diff --git a/docs/generated/cli/create-nx-workspace.md b/docs/generated/cli/create-nx-workspace.md index 2e1ee043afefbf..c0927ba7ed8293 100644 --- a/docs/generated/cli/create-nx-workspace.md +++ b/docs/generated/cli/create-nx-workspace.md @@ -25,6 +25,12 @@ Default: `false` Show all prompts +### appDir + +Type: `boolean` + +Add Experimental app/ layout for next.js + ### appName Type: `string` @@ -129,7 +135,7 @@ Package manager to use Type: `string` -Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular", "node-standalone"]. To build your own see https://nx.dev/packages/nx-plugin#preset +Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "nextjs-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular", "node-standalone"]. To build your own see https://nx.dev/packages/nx-plugin#preset ### routing diff --git a/docs/generated/packages/next/generators/application.json b/docs/generated/packages/next/generators/application.json index fa325636748a00..6089512e1b5c70 100644 --- a/docs/generated/packages/next/generators/application.json +++ b/docs/generated/packages/next/generators/application.json @@ -121,6 +121,13 @@ "default": false, "description": "Enable experimental app directory for the project", "x-prompt": "Do you want to use experimental app/ in this project?" + }, + "rootProject": { + "description": "Create an application at the root of the workspace.", + "type": "boolean", + "default": false, + "hidden": true, + "x-priority": "internal" } }, "required": [], diff --git a/docs/generated/packages/next/generators/init.json b/docs/generated/packages/next/generators/init.json index 2859ac27a4df1e..725954439807a3 100644 --- a/docs/generated/packages/next/generators/init.json +++ b/docs/generated/packages/next/generators/init.json @@ -36,6 +36,13 @@ "default": false, "description": "Do not add dependencies to `package.json`.", "x-priority": "internal" + }, + "rootProject": { + "description": "Create an application at the root of the workspace.", + "type": "boolean", + "default": false, + "hidden": true, + "x-priority": "internal" } }, "required": [], diff --git a/docs/generated/packages/nx/documents/create-nx-workspace.md b/docs/generated/packages/nx/documents/create-nx-workspace.md index 2e1ee043afefbf..c0927ba7ed8293 100644 --- a/docs/generated/packages/nx/documents/create-nx-workspace.md +++ b/docs/generated/packages/nx/documents/create-nx-workspace.md @@ -25,6 +25,12 @@ Default: `false` Show all prompts +### appDir + +Type: `boolean` + +Add Experimental app/ layout for next.js + ### appName Type: `string` @@ -129,7 +135,7 @@ Package manager to use Type: `string` -Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular", "node-standalone"]. To build your own see https://nx.dev/packages/nx-plugin#preset +Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "nextjs-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular", "node-standalone"]. To build your own see https://nx.dev/packages/nx-plugin#preset ### routing diff --git a/docs/generated/packages/workspace/generators/new.json b/docs/generated/packages/workspace/generators/new.json index ad4605cca4d343..8aafcd1f6459dc 100644 --- a/docs/generated/packages/workspace/generators/new.json +++ b/docs/generated/packages/workspace/generators/new.json @@ -68,6 +68,11 @@ "description": "The framework which the application is using", "type": "string", "enum": ["express", "koa", "fastify", "nest", "none"] + }, + "appDir": { + "description": "Enable experimental app directory for the project", + "type": "boolean", + "default": false } }, "additionalProperties": true, diff --git a/docs/generated/packages/workspace/generators/preset.json b/docs/generated/packages/workspace/generators/preset.json index c9165e99375c2c..2945f5cd8ab2f1 100644 --- a/docs/generated/packages/workspace/generators/preset.json +++ b/docs/generated/packages/workspace/generators/preset.json @@ -80,6 +80,11 @@ "description": "Generate a Dockerfile", "type": "boolean", "default": false + }, + "appDir": { + "description": "Enable experimental app directory for the project", + "type": "boolean", + "default": false } }, "presets": [] diff --git a/e2e/next/src/next.test.ts b/e2e/next/src/next.test.ts index 5fe0c9f2b8945a..8dbc0ceb442da6 100644 --- a/e2e/next/src/next.test.ts +++ b/e2e/next/src/next.test.ts @@ -21,7 +21,6 @@ import { } from '@nrwl/e2e/utils'; import * as http from 'http'; import { checkApp } from './utils'; -import { removeSync } from 'fs-extra'; describe('Next.js Applications', () => { let proj: string; @@ -426,6 +425,27 @@ describe('Next.js Applications', () => { checkExport: false, }); }, 300_000); + + it('should create a generate a next.js app with app layout enabled', async () => { + const appName = uniq('app'); + + runCLI( + `generate @nrwl/next:app ${appName} --style=css --appDir --no-interactive` + ); + + checkFilesExist(`apps/${appName}/app/api/hello/route.ts`); + checkFilesExist(`apps/${appName}/app/page.tsx`); + checkFilesExist(`apps/${appName}/app/layout.tsx`); + checkFilesExist(`apps/${appName}/app/global.css`); + checkFilesExist(`apps/${appName}/app/page.module.css`); + + await checkApp(appName, { + checkUnitTest: false, + checkLint: false, + checkE2E: false, + checkExport: false, + }); + }, 300_000); }); function getData(port, path = ''): Promise { diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts index 9d735a836e6e63..dcb393979536df 100644 --- a/packages/create-nx-workspace/bin/create-nx-workspace.ts +++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts @@ -36,6 +36,7 @@ interface Arguments extends CreateWorkspaceOptions { framework: Framework; standaloneApi: boolean; docker: boolean; + appDir: boolean; routing: boolean; bundler: Bundler; } @@ -101,6 +102,10 @@ export const commandsObject: yargs.Argv = yargs .option('docker', { describe: chalk.dim`Generate a Dockerfile with your node-server`, type: 'boolean', + }) + .option('appDir', { + describe: chalk.dim`Add Experimental app/ layout for next.js`, + type: 'boolean', }), withNxCloud, withCI, @@ -153,6 +158,7 @@ async function normalizeArgsMiddleware( framework, bundler, docker, + appDir, routing, standaloneApi; @@ -182,7 +188,9 @@ async function normalizeArgsMiddleware( if (monorepoStyle === 'package-based') { preset = 'npm'; } else if (monorepoStyle === 'react') { - preset = Preset.ReactStandalone; + preset = (await isFrameworkNextJs(argv)) + ? Preset.NextJsStandalone + : Preset.ReactStandalone; } else if (monorepoStyle === 'angular') { preset = Preset.AngularStandalone; } else if (monorepoStyle === 'node-standalone') { @@ -201,7 +209,8 @@ async function normalizeArgsMiddleware( if ( preset === Preset.ReactStandalone || preset === Preset.AngularStandalone || - preset === Preset.NodeStandalone + preset === Preset.NodeStandalone || + preset === Preset.NextJsStandalone ) { appName = argv.appName ?? argv.name ?? (await determineAppName(preset, argv)); @@ -214,6 +223,10 @@ async function normalizeArgsMiddleware( } } + if (preset === Preset.NextJsStandalone) { + appDir = await isAppDir(argv); + } + if (preset === Preset.ReactStandalone) { bundler = await determineBundler(argv); } @@ -264,6 +277,7 @@ async function normalizeArgsMiddleware( ci, bundler, docker, + appDir, }); } catch (e) { console.error(e); @@ -336,27 +350,27 @@ async function determineMonorepoStyle(): Promise { { name: 'package-based', message: - 'Package-based monorepo: Nx makes it fast, but lets you run things your way.', + 'Package-based monorepo: Nx makes it fast, but lets you run things your way.', }, { name: 'integrated', message: - 'Integrated monorepo: Nx configures your favorite frameworks and lets you focus on shipping features.', + 'Integrated monorepo: Nx configures your favorite frameworks and lets you focus on shipping features.', }, { name: 'react', message: - 'Standalone React app: Nx configures Vite (or Webpack), ESLint, and Cypress.', + 'Standalone React app: Nx configures a React app with an optional framework (e.g. Next.js).', }, { name: 'angular', message: - 'Standalone Angular app: Nx configures Jest, ESLint and Cypress.', + 'Standalone Angular app: Nx configures Jest, ESLint and Cypress.', }, { name: 'node-standalone', message: - 'Standalone Node app: Nx configures a framework (ex. Express), esbuild, ESlint and Jest.', + 'Standalone Node app: Nx configures a framework (e.g. Express), esbuild, ESlint and Jest.', }, ], }, @@ -555,6 +569,59 @@ async function determineDockerfile( } } +async function isFrameworkNextJs(parsedArgs: yargs.Arguments) { + if (parsedArgs.framework === undefined) { + return enquirer + .prompt<{ framework: 'none' | 'next.js' }>([ + { + name: 'framework', + message: 'What framework would you like to use?', + type: 'autocomplete', + choices: [ + { + name: 'none', + message: 'None', + hint: 'I only want React', + }, + { + name: 'next.js', + message: 'Next.js [https://nextjs.org/]', + }, + ], + initial: 'none' as any, + }, + ]) + .then((choice) => choice.framework === 'next.js'); + } else { + return Promise.resolve(parsedArgs.framework === 'next.js'); + } +} + +async function isAppDir(parsedArgs: yargs.Arguments) { + if (parsedArgs.appDir === undefined) { + return enquirer + .prompt<{ appDir: 'Yes' | 'No' }>([ + { + name: 'appDir', + message: 'Do you want to use experimental app/ in this project?', + type: 'autocomplete', + choices: [ + { + name: 'No', + }, + { + name: 'Yes', + }, + ], + initial: 'No' as any, + }, + ]) + .then((choice) => choice.appDir === 'Yes'); + } else { + return Promise.resolve(parsedArgs.appDir); + } +} + async function determineStyle( preset: Preset, parsedArgs: yargs.Arguments @@ -590,9 +657,12 @@ async function determineStyle( ]; if ( - [Preset.ReactMonorepo, Preset.ReactStandalone, Preset.NextJs].includes( - preset - ) + [ + Preset.ReactMonorepo, + Preset.ReactStandalone, + Preset.NextJs, + Preset.NextJsStandalone, + ].includes(preset) ) { choices.push( { diff --git a/packages/create-nx-workspace/src/utils/preset/point-to-tutorial-and-course.ts b/packages/create-nx-workspace/src/utils/preset/point-to-tutorial-and-course.ts index 3224f10229203e..50c53fbc6a90eb 100644 --- a/packages/create-nx-workspace/src/utils/preset/point-to-tutorial-and-course.ts +++ b/packages/create-nx-workspace/src/utils/preset/point-to-tutorial-and-course.ts @@ -31,6 +31,7 @@ export function pointToTutorialAndCourse(preset: Preset) { break; case Preset.ReactMonorepo: case Preset.NextJs: + case Preset.NextJsStandalone: output.addVerticalSeparator(); output.note({ title, diff --git a/packages/create-nx-workspace/src/utils/preset/preset.ts b/packages/create-nx-workspace/src/utils/preset/preset.ts index 237e9c558594b5..554d3742748361 100644 --- a/packages/create-nx-workspace/src/utils/preset/preset.ts +++ b/packages/create-nx-workspace/src/utils/preset/preset.ts @@ -9,6 +9,7 @@ export enum Preset { AngularStandalone = 'angular-standalone', ReactMonorepo = 'react-monorepo', ReactStandalone = 'react-standalone', + NextJsStandalone = 'nextjs-standalone', ReactNative = 'react-native', Expo = 'expo', NextJs = 'next', diff --git a/packages/next/src/generators/application/files/app/page.tsx__tmpl__ b/packages/next/src/generators/application/files/app/page.tsx__tmpl__ index 4d4e80e0330707..de8950f216d6fa 100644 --- a/packages/next/src/generators/application/files/app/page.tsx__tmpl__ +++ b/packages/next/src/generators/application/files/app/page.tsx__tmpl__ @@ -11,7 +11,7 @@ const StyledPage = styled.div`<%- pageStyleContent %>`; <% }%> -export async function Index() { +export default async function Index() { /* * Replace the elements below with your own. * @@ -23,6 +23,4 @@ export async function Index() { <%- appContent %> > ); -}; - -export default Index; \ No newline at end of file +}; \ No newline at end of file diff --git a/packages/next/src/generators/application/files/common/.babelrc__tmpl__ b/packages/next/src/generators/application/files/common/__dot__babelrc similarity index 100% rename from packages/next/src/generators/application/files/common/.babelrc__tmpl__ rename to packages/next/src/generators/application/files/common/__dot__babelrc diff --git a/packages/next/src/generators/application/files/common/tsconfig.json__tmpl__ b/packages/next/src/generators/application/files/common/tsconfig.json__tmpl__ index fcd3120fc97b7c..35fd206998f618 100644 --- a/packages/next/src/generators/application/files/common/tsconfig.json__tmpl__ +++ b/packages/next/src/generators/application/files/common/tsconfig.json__tmpl__ @@ -11,7 +11,8 @@ "noEmit": true, "resolveJsonModule": true, "isolatedModules": true, - "incremental": true + "incremental": true, + "plugins": [{ "name": "next" }] }, "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "next-env.d.ts"], "exclude": ["node_modules", "jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] diff --git a/packages/next/src/generators/application/lib/add-cypress.ts b/packages/next/src/generators/application/lib/add-cypress.ts index 83017ed43b3850..a9b9cac85f1aae 100644 --- a/packages/next/src/generators/application/lib/add-cypress.ts +++ b/packages/next/src/generators/application/lib/add-cypress.ts @@ -15,7 +15,7 @@ export async function addCypress(host: Tree, options: NormalizedSchema) { return cypressProjectGenerator(host, { ...options, linter: Linter.EsLint, - name: `${options.name}-e2e`, + name: options.e2eProjectName, directory: options.directory, project: options.projectName, skipFormat: true, diff --git a/packages/next/src/generators/application/lib/create-application-files.ts b/packages/next/src/generators/application/lib/create-application-files.ts index e1c9323ca7804e..4f30ab4d5f392c 100644 --- a/packages/next/src/generators/application/lib/create-application-files.ts +++ b/packages/next/src/generators/application/lib/create-application-files.ts @@ -1,5 +1,12 @@ import { join } from 'path'; -import { generateFiles, names, toJS, Tree } from '@nrwl/devkit'; +import { + generateFiles, + names, + readJson, + toJS, + Tree, + updateJson, +} from '@nrwl/devkit'; import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { NormalizedSchema } from './normalize-options'; @@ -12,6 +19,7 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) { const templateVariables = { ...names(options.name), ...options, + dot: '.', tmpl: '', rootTsConfigPath: getRelativePathToRootTsConfig( host, @@ -49,6 +57,38 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) { ); } + if (options.rootProject) { + updateJson(host, 'tsconfig.base.json', (json) => { + const appJSON = readJson(host, 'tsconfig.json'); + + let { extends: _, ...updatedJson } = json; + + updatedJson = { + ...updateJson, + compilerOptions: { + ...updatedJson.compilerOptions, + ...appJSON.compilerOptions, + }, + include: [ + ...new Set([ + ...(updatedJson.include || []), + ...(appJSON.include || []), + ]), + ], + exclude: [ + ...new Set([ + ...(updatedJson.exclude || []), + ...(appJSON.exclude || []), + '**e2e/**/*', + ]), + ], + }; + return updatedJson; + }); + host.delete('tsconfig.json'); + host.rename('tsconfig.base.json', 'tsconfig.json'); + } + if (options.unitTestRunner === 'none') { host.delete(`${options.appProjectRoot}/specs/${options.fileName}.spec.tsx`); } diff --git a/packages/next/src/generators/application/lib/normalize-options.ts b/packages/next/src/generators/application/lib/normalize-options.ts index 4df023ad29efe7..879c8c2c0ac4bf 100644 --- a/packages/next/src/generators/application/lib/normalize-options.ts +++ b/packages/next/src/generators/application/lib/normalize-options.ts @@ -36,10 +36,15 @@ export function normalizeOptions( const appsDir = layoutDirectory ?? getWorkspaceLayout(host).appsDir; const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-'); - const e2eProjectName = `${appProjectName}-e2e`; + const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`; - const appProjectRoot = joinPathFragments(appsDir, appDirectory); - const e2eProjectRoot = joinPathFragments(appsDir, `${appDirectory}-e2e`); + const appProjectRoot = options.rootProject + ? '.' + : joinPathFragments(appsDir, appDirectory); + + const e2eProjectRoot = options.rootProject + ? '.' + : joinPathFragments(appsDir, `${appDirectory}-e2e`); const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) diff --git a/packages/next/src/generators/application/schema.d.ts b/packages/next/src/generators/application/schema.d.ts index c1032a0df41501..da2c3bcf492b9a 100644 --- a/packages/next/src/generators/application/schema.d.ts +++ b/packages/next/src/generators/application/schema.d.ts @@ -16,4 +16,5 @@ export interface Schema { customServer?: boolean; skipPackageJson?: boolean; appDir?: boolean; + rootProject?: boolean; } diff --git a/packages/next/src/generators/application/schema.json b/packages/next/src/generators/application/schema.json index 889443d88aa620..39bf2d17f88484 100644 --- a/packages/next/src/generators/application/schema.json +++ b/packages/next/src/generators/application/schema.json @@ -124,6 +124,13 @@ "default": false, "description": "Enable experimental app directory for the project", "x-prompt": "Do you want to use experimental app/ in this project?" + }, + "rootProject": { + "description": "Create an application at the root of the workspace.", + "type": "boolean", + "default": false, + "hidden": true, + "x-priority": "internal" } }, "required": [], diff --git a/packages/next/src/generators/init/init.ts b/packages/next/src/generators/init/init.ts index 2192a11ea88deb..8d70da09a3e005 100644 --- a/packages/next/src/generators/init/init.ts +++ b/packages/next/src/generators/init/init.ts @@ -65,6 +65,7 @@ export async function nextInitGenerator(host: Tree, schema: InitSchema) { const reactTask = await reactInitGenerator(host, { ...schema, skipFormat: true, + skipBabelConfig: true, }); tasks.push(reactTask); diff --git a/packages/next/src/generators/init/schema.d.ts b/packages/next/src/generators/init/schema.d.ts index 0ef1c5ded9b54c..43169ac817dad0 100644 --- a/packages/next/src/generators/init/schema.d.ts +++ b/packages/next/src/generators/init/schema.d.ts @@ -4,4 +4,5 @@ export interface InitSchema { skipFormat?: boolean; js?: boolean; skipPackageJson?: boolean; + rootProject?: boolean; } diff --git a/packages/next/src/generators/init/schema.json b/packages/next/src/generators/init/schema.json index 9fa41c1956bd8e..8492383e91d023 100644 --- a/packages/next/src/generators/init/schema.json +++ b/packages/next/src/generators/init/schema.json @@ -33,6 +33,13 @@ "default": false, "description": "Do not add dependencies to `package.json`.", "x-priority": "internal" + }, + "rootProject": { + "description": "Create an application at the root of the workspace.", + "type": "boolean", + "default": false, + "hidden": true, + "x-priority": "internal" } }, "required": [] diff --git a/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap b/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap index 13859c65d7c60c..5f08c7db150c8f 100644 --- a/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap +++ b/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap @@ -230,6 +230,31 @@ Visit the [Nx Documentation](https://nx.dev) to learn more. " `; +exports[`@nrwl/workspace:generateWorkspaceFiles README.md should be created for NextJsStandalone preset 1`] = ` +"# Proj + + + +✨ **This workspace has been generated by [Nx, a Smart, fast and extensible build system.](https://nx.dev)** ✨ + +## Development server + +Run \`nx serve app1\` for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files. + +## Understand this workspace + +Run \`nx graph\` to see a diagram of the dependencies of the projects. + +## Remote caching + +Run \`npx nx connect-to-nx-cloud\` to enable [remote caching](https://nx.app) and make CI faster. + +## Further help + +Visit the [Nx Documentation](https://nx.dev) to learn more. +" +`; + exports[`@nrwl/workspace:generateWorkspaceFiles README.md should be created for NodeStandalone preset 1`] = ` "# Proj diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts index 6b8ba4aca7a87c..31d6e4dbda15ea 100644 --- a/packages/workspace/src/generators/new/generate-preset.ts +++ b/packages/workspace/src/generators/new/generate-preset.ts @@ -77,6 +77,7 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) { opts.bundler ? `--bundler=${opts.bundler}` : null, opts.framework ? `--framework=${opts.framework}` : null, opts.docker ? `--docker=${opts.docker}` : null, + opts.appDir ? `--appDir=${opts.appDir}` : null, opts.packageManager ? `--packageManager=${opts.packageManager}` : null, opts.standaloneApi !== undefined ? `--standaloneApi=${opts.standaloneApi}` @@ -116,6 +117,7 @@ function getPresetDependencies({ }; case Preset.NextJs: + case Preset.NextJsStandalone: return { dependencies: { '@nrwl/next': nxVersion }, dev: {} }; case Preset.ReactMonorepo: diff --git a/packages/workspace/src/generators/new/generate-workspace-files.spec.ts b/packages/workspace/src/generators/new/generate-workspace-files.spec.ts index 7faa5cae9c3f09..424e4412de154a 100644 --- a/packages/workspace/src/generators/new/generate-workspace-files.spec.ts +++ b/packages/workspace/src/generators/new/generate-workspace-files.spec.ts @@ -41,6 +41,7 @@ describe('@nrwl/workspace:generateWorkspaceFiles', () => { Preset.WebComponents, Preset.Express, Preset.NodeStandalone, + Preset.NextJsStandalone, ].includes(Preset[preset]) ) { appName = 'app1'; diff --git a/packages/workspace/src/generators/new/generate-workspace-files.ts b/packages/workspace/src/generators/new/generate-workspace-files.ts index 4b651329bb9d47..c8b8f373e5de0e 100644 --- a/packages/workspace/src/generators/new/generate-workspace-files.ts +++ b/packages/workspace/src/generators/new/generate-workspace-files.ts @@ -67,6 +67,7 @@ function createAppsAndLibsFolders(tree: Tree, options: NormalizedSchema) { options.preset === Preset.AngularStandalone || options.preset === Preset.ReactStandalone || options.preset === Preset.NodeStandalone || + options.preset === Preset.NextJsStandalone || options.isCustomPreset ) { // don't generate any folders @@ -126,7 +127,8 @@ function createFiles(tree: Tree, options: NormalizedSchema) { const filesDirName = options.preset === Preset.AngularStandalone || options.preset === Preset.ReactStandalone || - options.preset === Preset.NodeStandalone + options.preset === Preset.NodeStandalone || + options.preset === Preset.NextJsStandalone ? './files-root-app' : options.preset === Preset.NPM || options.preset === Preset.Core ? './files-package-based-repo' @@ -177,7 +179,8 @@ function addNpmScripts(tree: Tree, options: NormalizedSchema) { if ( options.preset === Preset.AngularStandalone || options.preset === Preset.ReactStandalone || - options.preset === Preset.NodeStandalone + options.preset === Preset.NodeStandalone || + options.preset === Preset.NextJsStandalone ) { updateJson(tree, join(options.directory, 'package.json'), (json) => { Object.assign(json.scripts, { diff --git a/packages/workspace/src/generators/new/new.ts b/packages/workspace/src/generators/new/new.ts index 66adbf390374fc..198f91075ff9ab 100644 --- a/packages/workspace/src/generators/new/new.ts +++ b/packages/workspace/src/generators/new/new.ts @@ -24,6 +24,7 @@ interface Schema { defaultBase: string; framework?: string; docker?: boolean; + appDir?: boolean; linter?: Linter; bundler?: 'vite' | 'webpack'; standaloneApi?: boolean; diff --git a/packages/workspace/src/generators/new/schema.json b/packages/workspace/src/generators/new/schema.json index b4e7c4c55acec1..2178817d7b18ef 100644 --- a/packages/workspace/src/generators/new/schema.json +++ b/packages/workspace/src/generators/new/schema.json @@ -71,6 +71,11 @@ "description": "The framework which the application is using", "type": "string", "enum": ["express", "koa", "fastify", "nest", "none"] + }, + "appDir": { + "description": "Enable experimental app directory for the project", + "type": "boolean", + "default": false } }, "additionalProperties": true diff --git a/packages/workspace/src/generators/preset/preset.ts b/packages/workspace/src/generators/preset/preset.ts index 4550e60bea7833..d288189dd9cb17 100644 --- a/packages/workspace/src/generators/preset/preset.ts +++ b/packages/workspace/src/generators/preset/preset.ts @@ -81,6 +81,16 @@ async function createPreset(tree: Tree, options: Schema) { style: options.style, linter: options.linter, }); + } else if (options.preset === Preset.NextJsStandalone) { + const { applicationGenerator: nextApplicationGenerator } = require('@nrwl' + + '/next'); + return nextApplicationGenerator(tree, { + name: options.name, + style: options.style, + linter: options.linter, + appDir: options.appDir, + rootProject: true, + }); } else if (options.preset === Preset.WebComponents) { const { applicationGenerator: webApplicationGenerator } = require('@nrwl' + '/web'); diff --git a/packages/workspace/src/generators/preset/schema.d.ts b/packages/workspace/src/generators/preset/schema.d.ts index 50c5ecedda24f0..11c04bcf80c4d7 100644 --- a/packages/workspace/src/generators/preset/schema.d.ts +++ b/packages/workspace/src/generators/preset/schema.d.ts @@ -12,6 +12,7 @@ export interface Schema { packageManager?: PackageManager; bundler?: 'vite' | 'webpack'; docker?: boolean; + appDir?: boolean; routing?: boolean; standaloneApi?: boolean; } diff --git a/packages/workspace/src/generators/preset/schema.json b/packages/workspace/src/generators/preset/schema.json index 3731fb59819639..010ced123cfda9 100644 --- a/packages/workspace/src/generators/preset/schema.json +++ b/packages/workspace/src/generators/preset/schema.json @@ -83,6 +83,11 @@ "description": "Generate a Dockerfile", "type": "boolean", "default": false + }, + "appDir": { + "description": "Enable experimental app directory for the project", + "type": "boolean", + "default": false } } } diff --git a/packages/workspace/src/generators/utils/presets.ts b/packages/workspace/src/generators/utils/presets.ts index ac4032bab7331f..2874fa5b506a56 100644 --- a/packages/workspace/src/generators/utils/presets.ts +++ b/packages/workspace/src/generators/utils/presets.ts @@ -9,6 +9,7 @@ export enum Preset { AngularStandalone = 'angular-standalone', ReactMonorepo = 'react-monorepo', ReactStandalone = 'react-standalone', + NextJsStandalone = 'nextjs-standalone', ReactNative = 'react-native', Expo = 'expo', NextJs = 'next',