Skip to content

Commit

Permalink
feat(nextjs): Add standalone Nextjs option to react selection when ru…
Browse files Browse the repository at this point in the history
…nning CNW (#16317)
  • Loading branch information
ndcunningham authored Apr 19, 2023
1 parent 16e115f commit 338dc64
Show file tree
Hide file tree
Showing 31 changed files with 278 additions and 28 deletions.
8 changes: 7 additions & 1 deletion docs/generated/cli/create-nx-workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ Type: `string`

Workspace name (e.g. org name)

### nextAppDir

Type: `boolean`

Add Experimental app/ layout for next.js

### nxCloud

Type: `boolean`
Expand All @@ -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

Expand Down
7 changes: 7 additions & 0 deletions docs/generated/packages/next/generators/application.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [],
Expand Down
7 changes: 7 additions & 0 deletions docs/generated/packages/next/generators/init.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [],
Expand Down
8 changes: 7 additions & 1 deletion docs/generated/packages/nx/documents/create-nx-workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ Type: `string`

Workspace name (e.g. org name)

### nextAppDir

Type: `boolean`

Add Experimental app/ layout for next.js

### nxCloud

Type: `boolean`
Expand All @@ -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

Expand Down
5 changes: 5 additions & 0 deletions docs/generated/packages/workspace/generators/new.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@
"description": "The framework which the application is using",
"type": "string",
"enum": ["express", "koa", "fastify", "nest", "none"]
},
"nextAppDir": {
"description": "Enable experimental app directory for the project",
"type": "boolean",
"default": false
}
},
"additionalProperties": true,
Expand Down
5 changes: 5 additions & 0 deletions docs/generated/packages/workspace/generators/preset.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@
"description": "Generate a Dockerfile",
"type": "boolean",
"default": false
},
"nextAppDir": {
"description": "Enable experimental app/ for the project",
"type": "boolean",
"default": false
}
},
"presets": []
Expand Down
22 changes: 21 additions & 1 deletion e2e/next/src/next.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<any> {
Expand Down
93 changes: 83 additions & 10 deletions packages/create-nx-workspace/bin/create-nx-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface Arguments extends CreateWorkspaceOptions {
framework: Framework;
standaloneApi: boolean;
docker: boolean;
nextAppDir: boolean;
routing: boolean;
bundler: Bundler;
}
Expand Down Expand Up @@ -104,6 +105,10 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
.option('docker', {
describe: chalk.dim`Generate a Dockerfile with your node-server`,
type: 'boolean',
})
.option('nextAppDir', {
describe: chalk.dim`Add Experimental app/ layout for next.js`,
type: 'boolean',
}),
withNxCloud,
withCI,
Expand Down Expand Up @@ -180,6 +185,7 @@ async function normalizeArgsMiddleware(
framework,
bundler,
docker,
nextAppDir,
routing,
standaloneApi;

Expand Down Expand Up @@ -209,7 +215,7 @@ async function normalizeArgsMiddleware(
if (monorepoStyle === 'package-based') {
preset = 'npm';
} else if (monorepoStyle === 'react') {
preset = Preset.ReactStandalone;
preset = await determineReactFramework(argv);
} else if (monorepoStyle === 'angular') {
preset = Preset.AngularStandalone;
} else if (monorepoStyle === 'node-standalone') {
Expand All @@ -228,7 +234,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));
Expand All @@ -241,6 +248,10 @@ async function normalizeArgsMiddleware(
}
}

if (preset === Preset.NextJsStandalone) {
nextAppDir = await isNextAppDir(argv);
}

if (preset === Preset.ReactStandalone) {
bundler = await determineBundler(argv);
}
Expand Down Expand Up @@ -291,6 +302,7 @@ async function normalizeArgsMiddleware(
ci,
bundler,
docker,
nextAppDir,
});
} catch (e) {
console.error(e);
Expand Down Expand Up @@ -363,27 +375,27 @@ async function determineMonorepoStyle(): Promise<string> {
{
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.',
},
],
},
Expand Down Expand Up @@ -582,6 +594,64 @@ async function determineDockerfile(
}
}

async function determineReactFramework(parsedArgs: yargs.Arguments<Arguments>) {
if (parsedArgs.framework) {
return parsedArgs.framework === 'next.js'
? Preset.NextJsStandalone
: Preset.ReactStandalone;
}
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'
? Preset.NextJsStandalone
: Preset.ReactStandalone
);
}

async function isNextAppDir(parsedArgs: yargs.Arguments<Arguments>) {
if (parsedArgs.nextAppDir === 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.nextAppDir);
}
}

async function determineStyle(
preset: Preset,
parsedArgs: yargs.Arguments<Arguments>
Expand Down Expand Up @@ -617,9 +687,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(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export function pointToTutorialAndCourse(preset: Preset) {
break;
case Preset.ReactMonorepo:
case Preset.NextJs:
case Preset.NextJsStandalone:
output.addVerticalSeparator();
output.note({
title,
Expand Down
1 change: 1 addition & 0 deletions packages/create-nx-workspace/src/utils/preset/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -23,6 +23,4 @@ export async function Index() {
<%- appContent %>
</<%= wrapper %>>
);
};

export default Index;
};
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

1 comment on commit 338dc64

@vercel
Copy link

@vercel vercel bot commented on 338dc64 Apr 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-five.vercel.app
nx.dev
nx-dev-git-master-nrwl.vercel.app
nx-dev-nrwl.vercel.app

Please sign in to comment.