feat(nextjs): Add standalone Nextjs option to react selection when running CNW (#16317)
This commit is contained in:
parent
16e115fd7b
commit
338dc64d91
@ -109,6 +109,12 @@ Type: `string`
|
|||||||
|
|
||||||
Workspace name (e.g. org name)
|
Workspace name (e.g. org name)
|
||||||
|
|
||||||
|
### nextAppDir
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Add Experimental app/ layout for next.js
|
||||||
|
|
||||||
### nxCloud
|
### nxCloud
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
@ -129,7 +135,7 @@ Package manager to use
|
|||||||
|
|
||||||
Type: `string`
|
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
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -121,6 +121,13 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Enable experimental app directory for the project",
|
"description": "Enable experimental app directory for the project",
|
||||||
"x-prompt": "Do you want to use experimental app/ in this 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": [],
|
"required": [],
|
||||||
|
|||||||
@ -36,6 +36,13 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
|
},
|
||||||
|
"rootProject": {
|
||||||
|
"description": "Create an application at the root of the workspace.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"hidden": true,
|
||||||
|
"x-priority": "internal"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -109,6 +109,12 @@ Type: `string`
|
|||||||
|
|
||||||
Workspace name (e.g. org name)
|
Workspace name (e.g. org name)
|
||||||
|
|
||||||
|
### nextAppDir
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Add Experimental app/ layout for next.js
|
||||||
|
|
||||||
### nxCloud
|
### nxCloud
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
@ -129,7 +135,7 @@ Package manager to use
|
|||||||
|
|
||||||
Type: `string`
|
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
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -68,6 +68,11 @@
|
|||||||
"description": "The framework which the application is using",
|
"description": "The framework which the application is using",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["express", "koa", "fastify", "nest", "none"]
|
"enum": ["express", "koa", "fastify", "nest", "none"]
|
||||||
|
},
|
||||||
|
"nextAppDir": {
|
||||||
|
"description": "Enable experimental app directory for the project",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
|
|||||||
@ -80,6 +80,11 @@
|
|||||||
"description": "Generate a Dockerfile",
|
"description": "Generate a Dockerfile",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"nextAppDir": {
|
||||||
|
"description": "Enable experimental app/ for the project",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"presets": []
|
"presets": []
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import {
|
|||||||
} from '@nrwl/e2e/utils';
|
} from '@nrwl/e2e/utils';
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
import { checkApp } from './utils';
|
import { checkApp } from './utils';
|
||||||
import { removeSync } from 'fs-extra';
|
|
||||||
|
|
||||||
describe('Next.js Applications', () => {
|
describe('Next.js Applications', () => {
|
||||||
let proj: string;
|
let proj: string;
|
||||||
@ -426,6 +425,27 @@ describe('Next.js Applications', () => {
|
|||||||
checkExport: false,
|
checkExport: false,
|
||||||
});
|
});
|
||||||
}, 300_000);
|
}, 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> {
|
function getData(port, path = ''): Promise<any> {
|
||||||
|
|||||||
@ -39,6 +39,7 @@ interface Arguments extends CreateWorkspaceOptions {
|
|||||||
framework: Framework;
|
framework: Framework;
|
||||||
standaloneApi: boolean;
|
standaloneApi: boolean;
|
||||||
docker: boolean;
|
docker: boolean;
|
||||||
|
nextAppDir: boolean;
|
||||||
routing: boolean;
|
routing: boolean;
|
||||||
bundler: Bundler;
|
bundler: Bundler;
|
||||||
}
|
}
|
||||||
@ -104,6 +105,10 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
|
|||||||
.option('docker', {
|
.option('docker', {
|
||||||
describe: chalk.dim`Generate a Dockerfile with your node-server`,
|
describe: chalk.dim`Generate a Dockerfile with your node-server`,
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
|
})
|
||||||
|
.option('nextAppDir', {
|
||||||
|
describe: chalk.dim`Add Experimental app/ layout for next.js`,
|
||||||
|
type: 'boolean',
|
||||||
}),
|
}),
|
||||||
withNxCloud,
|
withNxCloud,
|
||||||
withCI,
|
withCI,
|
||||||
@ -180,6 +185,7 @@ async function normalizeArgsMiddleware(
|
|||||||
framework,
|
framework,
|
||||||
bundler,
|
bundler,
|
||||||
docker,
|
docker,
|
||||||
|
nextAppDir,
|
||||||
routing,
|
routing,
|
||||||
standaloneApi;
|
standaloneApi;
|
||||||
|
|
||||||
@ -209,7 +215,7 @@ async function normalizeArgsMiddleware(
|
|||||||
if (monorepoStyle === 'package-based') {
|
if (monorepoStyle === 'package-based') {
|
||||||
preset = 'npm';
|
preset = 'npm';
|
||||||
} else if (monorepoStyle === 'react') {
|
} else if (monorepoStyle === 'react') {
|
||||||
preset = Preset.ReactStandalone;
|
preset = await determineReactFramework(argv);
|
||||||
} else if (monorepoStyle === 'angular') {
|
} else if (monorepoStyle === 'angular') {
|
||||||
preset = Preset.AngularStandalone;
|
preset = Preset.AngularStandalone;
|
||||||
} else if (monorepoStyle === 'node-standalone') {
|
} else if (monorepoStyle === 'node-standalone') {
|
||||||
@ -228,7 +234,8 @@ async function normalizeArgsMiddleware(
|
|||||||
if (
|
if (
|
||||||
preset === Preset.ReactStandalone ||
|
preset === Preset.ReactStandalone ||
|
||||||
preset === Preset.AngularStandalone ||
|
preset === Preset.AngularStandalone ||
|
||||||
preset === Preset.NodeStandalone
|
preset === Preset.NodeStandalone ||
|
||||||
|
preset === Preset.NextJsStandalone
|
||||||
) {
|
) {
|
||||||
appName =
|
appName =
|
||||||
argv.appName ?? argv.name ?? (await determineAppName(preset, argv));
|
argv.appName ?? argv.name ?? (await determineAppName(preset, argv));
|
||||||
@ -241,6 +248,10 @@ async function normalizeArgsMiddleware(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preset === Preset.NextJsStandalone) {
|
||||||
|
nextAppDir = await isNextAppDir(argv);
|
||||||
|
}
|
||||||
|
|
||||||
if (preset === Preset.ReactStandalone) {
|
if (preset === Preset.ReactStandalone) {
|
||||||
bundler = await determineBundler(argv);
|
bundler = await determineBundler(argv);
|
||||||
}
|
}
|
||||||
@ -291,6 +302,7 @@ async function normalizeArgsMiddleware(
|
|||||||
ci,
|
ci,
|
||||||
bundler,
|
bundler,
|
||||||
docker,
|
docker,
|
||||||
|
nextAppDir,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@ -373,7 +385,7 @@ async function determineMonorepoStyle(): Promise<string> {
|
|||||||
{
|
{
|
||||||
name: 'react',
|
name: 'react',
|
||||||
message:
|
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',
|
name: 'angular',
|
||||||
@ -383,7 +395,7 @@ async function determineMonorepoStyle(): Promise<string> {
|
|||||||
{
|
{
|
||||||
name: 'node-standalone',
|
name: 'node-standalone',
|
||||||
message:
|
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.',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -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(
|
async function determineStyle(
|
||||||
preset: Preset,
|
preset: Preset,
|
||||||
parsedArgs: yargs.Arguments<Arguments>
|
parsedArgs: yargs.Arguments<Arguments>
|
||||||
@ -617,9 +687,12 @@ async function determineStyle(
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
[Preset.ReactMonorepo, Preset.ReactStandalone, Preset.NextJs].includes(
|
[
|
||||||
preset
|
Preset.ReactMonorepo,
|
||||||
)
|
Preset.ReactStandalone,
|
||||||
|
Preset.NextJs,
|
||||||
|
Preset.NextJsStandalone,
|
||||||
|
].includes(preset)
|
||||||
) {
|
) {
|
||||||
choices.push(
|
choices.push(
|
||||||
{
|
{
|
||||||
|
|||||||
@ -31,6 +31,7 @@ export function pointToTutorialAndCourse(preset: Preset) {
|
|||||||
break;
|
break;
|
||||||
case Preset.ReactMonorepo:
|
case Preset.ReactMonorepo:
|
||||||
case Preset.NextJs:
|
case Preset.NextJs:
|
||||||
|
case Preset.NextJsStandalone:
|
||||||
output.addVerticalSeparator();
|
output.addVerticalSeparator();
|
||||||
output.note({
|
output.note({
|
||||||
title,
|
title,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export enum Preset {
|
|||||||
AngularStandalone = 'angular-standalone',
|
AngularStandalone = 'angular-standalone',
|
||||||
ReactMonorepo = 'react-monorepo',
|
ReactMonorepo = 'react-monorepo',
|
||||||
ReactStandalone = 'react-standalone',
|
ReactStandalone = 'react-standalone',
|
||||||
|
NextJsStandalone = 'nextjs-standalone',
|
||||||
ReactNative = 'react-native',
|
ReactNative = 'react-native',
|
||||||
Expo = 'expo',
|
Expo = 'expo',
|
||||||
NextJs = 'next',
|
NextJs = 'next',
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
const StyledPage = styled.div`<%- pageStyleContent %>`;
|
const StyledPage = styled.div`<%- pageStyleContent %>`;
|
||||||
<% }%>
|
<% }%>
|
||||||
|
|
||||||
export async function Index() {
|
export default async function Index() {
|
||||||
/*
|
/*
|
||||||
* Replace the elements below with your own.
|
* Replace the elements below with your own.
|
||||||
*
|
*
|
||||||
@ -24,5 +24,3 @@ export async function Index() {
|
|||||||
</<%= wrapper %>>
|
</<%= wrapper %>>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Index;
|
|
||||||
@ -11,7 +11,8 @@
|
|||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"incremental": true
|
"incremental": true,
|
||||||
|
"plugins": [{ "name": "next" }]
|
||||||
},
|
},
|
||||||
"include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "next-env.d.ts"],
|
"include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "next-env.d.ts"],
|
||||||
"exclude": ["node_modules", "jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
|
"exclude": ["node_modules", "jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
|
||||||
|
|||||||
@ -15,7 +15,7 @@ export async function addCypress(host: Tree, options: NormalizedSchema) {
|
|||||||
return cypressProjectGenerator(host, {
|
return cypressProjectGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
name: `${options.name}-e2e`,
|
name: options.e2eProjectName,
|
||||||
directory: options.directory,
|
directory: options.directory,
|
||||||
project: options.projectName,
|
project: options.projectName,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { generateFiles, names, toJS, Tree } from '@nx/devkit';
|
import {
|
||||||
|
generateFiles,
|
||||||
|
names,
|
||||||
|
readJson,
|
||||||
|
toJS,
|
||||||
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
import { getRelativePathToRootTsConfig } from '@nx/js';
|
import { getRelativePathToRootTsConfig } from '@nx/js';
|
||||||
|
|
||||||
import { NormalizedSchema } from './normalize-options';
|
import { NormalizedSchema } from './normalize-options';
|
||||||
@ -12,6 +19,7 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
const templateVariables = {
|
const templateVariables = {
|
||||||
...names(options.name),
|
...names(options.name),
|
||||||
...options,
|
...options,
|
||||||
|
dot: '.',
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
rootTsConfigPath: getRelativePathToRootTsConfig(
|
rootTsConfigPath: getRelativePathToRootTsConfig(
|
||||||
host,
|
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') {
|
if (options.unitTestRunner === 'none') {
|
||||||
host.delete(`${options.appProjectRoot}/specs/${options.fileName}.spec.tsx`);
|
host.delete(`${options.appProjectRoot}/specs/${options.fileName}.spec.tsx`);
|
||||||
}
|
}
|
||||||
@ -60,10 +100,14 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.styledModule) {
|
if (options.styledModule) {
|
||||||
|
if (options.appDir) {
|
||||||
|
host.delete(`${options.appProjectRoot}/app/page.module.${options.style}`);
|
||||||
|
} else {
|
||||||
host.delete(
|
host.delete(
|
||||||
`${options.appProjectRoot}/pages/${options.fileName}.module.${options.style}`
|
`${options.appProjectRoot}/pages/${options.fileName}.module.${options.style}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (options.style !== 'styled-components') {
|
if (options.style !== 'styled-components') {
|
||||||
host.delete(`${options.appProjectRoot}/pages/_document.tsx`);
|
host.delete(`${options.appProjectRoot}/pages/_document.tsx`);
|
||||||
|
|||||||
@ -36,10 +36,15 @@ export function normalizeOptions(
|
|||||||
const appsDir = layoutDirectory ?? getWorkspaceLayout(host).appsDir;
|
const appsDir = layoutDirectory ?? getWorkspaceLayout(host).appsDir;
|
||||||
|
|
||||||
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
||||||
const e2eProjectName = `${appProjectName}-e2e`;
|
const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||||
|
|
||||||
const appProjectRoot = joinPathFragments(appsDir, appDirectory);
|
const appProjectRoot = options.rootProject
|
||||||
const e2eProjectRoot = joinPathFragments(appsDir, `${appDirectory}-e2e`);
|
? '.'
|
||||||
|
: joinPathFragments(appsDir, appDirectory);
|
||||||
|
|
||||||
|
const e2eProjectRoot = options.rootProject
|
||||||
|
? '.'
|
||||||
|
: joinPathFragments(appsDir, `${appDirectory}-e2e`);
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
|
|||||||
@ -16,4 +16,5 @@ export interface Schema {
|
|||||||
customServer?: boolean;
|
customServer?: boolean;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
appDir?: boolean;
|
appDir?: boolean;
|
||||||
|
rootProject?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,6 +124,13 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Enable experimental app directory for the project",
|
"description": "Enable experimental app directory for the project",
|
||||||
"x-prompt": "Do you want to use experimental app/ in this 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": [],
|
"required": [],
|
||||||
|
|||||||
@ -65,6 +65,7 @@ export async function nextInitGenerator(host: Tree, schema: InitSchema) {
|
|||||||
const reactTask = await reactInitGenerator(host, {
|
const reactTask = await reactInitGenerator(host, {
|
||||||
...schema,
|
...schema,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
|
skipBabelConfig: true,
|
||||||
});
|
});
|
||||||
tasks.push(reactTask);
|
tasks.push(reactTask);
|
||||||
|
|
||||||
|
|||||||
@ -4,4 +4,5 @@ export interface InitSchema {
|
|||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
js?: boolean;
|
js?: boolean;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
|
rootProject?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,13 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
|
},
|
||||||
|
"rootProject": {
|
||||||
|
"description": "Create an application at the root of the workspace.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"hidden": true,
|
||||||
|
"x-priority": "internal"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|||||||
@ -230,6 +230,31 @@ Visit the [Nx Documentation](https://nx.dev) to learn more.
|
|||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`@nx/workspace:generateWorkspaceFiles README.md should be created for NextJsStandalone preset 1`] = `
|
||||||
|
"# Proj
|
||||||
|
|
||||||
|
<a alt="Nx logo" href="https://nx.dev" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png" width="45"></a>
|
||||||
|
|
||||||
|
✨ **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[`@nx/workspace:generateWorkspaceFiles README.md should be created for NodeStandalone preset 1`] = `
|
exports[`@nx/workspace:generateWorkspaceFiles README.md should be created for NodeStandalone preset 1`] = `
|
||||||
"# Proj
|
"# Proj
|
||||||
|
|
||||||
|
|||||||
@ -77,6 +77,7 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) {
|
|||||||
opts.bundler ? `--bundler=${opts.bundler}` : null,
|
opts.bundler ? `--bundler=${opts.bundler}` : null,
|
||||||
opts.framework ? `--framework=${opts.framework}` : null,
|
opts.framework ? `--framework=${opts.framework}` : null,
|
||||||
opts.docker ? `--docker=${opts.docker}` : null,
|
opts.docker ? `--docker=${opts.docker}` : null,
|
||||||
|
opts.nextAppDir ? `--nextAppDir=${opts.nextAppDir}` : null,
|
||||||
opts.packageManager ? `--packageManager=${opts.packageManager}` : null,
|
opts.packageManager ? `--packageManager=${opts.packageManager}` : null,
|
||||||
opts.standaloneApi !== undefined
|
opts.standaloneApi !== undefined
|
||||||
? `--standaloneApi=${opts.standaloneApi}`
|
? `--standaloneApi=${opts.standaloneApi}`
|
||||||
@ -116,6 +117,7 @@ function getPresetDependencies({
|
|||||||
};
|
};
|
||||||
|
|
||||||
case Preset.NextJs:
|
case Preset.NextJs:
|
||||||
|
case Preset.NextJsStandalone:
|
||||||
return { dependencies: { '@nx/next': nxVersion }, dev: {} };
|
return { dependencies: { '@nx/next': nxVersion }, dev: {} };
|
||||||
|
|
||||||
case Preset.ReactMonorepo:
|
case Preset.ReactMonorepo:
|
||||||
|
|||||||
@ -41,6 +41,7 @@ describe('@nx/workspace:generateWorkspaceFiles', () => {
|
|||||||
Preset.WebComponents,
|
Preset.WebComponents,
|
||||||
Preset.Express,
|
Preset.Express,
|
||||||
Preset.NodeStandalone,
|
Preset.NodeStandalone,
|
||||||
|
Preset.NextJsStandalone,
|
||||||
].includes(Preset[preset])
|
].includes(Preset[preset])
|
||||||
) {
|
) {
|
||||||
appName = 'app1';
|
appName = 'app1';
|
||||||
|
|||||||
@ -67,6 +67,7 @@ function createAppsAndLibsFolders(tree: Tree, options: NormalizedSchema) {
|
|||||||
options.preset === Preset.AngularStandalone ||
|
options.preset === Preset.AngularStandalone ||
|
||||||
options.preset === Preset.ReactStandalone ||
|
options.preset === Preset.ReactStandalone ||
|
||||||
options.preset === Preset.NodeStandalone ||
|
options.preset === Preset.NodeStandalone ||
|
||||||
|
options.preset === Preset.NextJsStandalone ||
|
||||||
options.isCustomPreset
|
options.isCustomPreset
|
||||||
) {
|
) {
|
||||||
// don't generate any folders
|
// don't generate any folders
|
||||||
@ -126,7 +127,8 @@ function createFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
const filesDirName =
|
const filesDirName =
|
||||||
options.preset === Preset.AngularStandalone ||
|
options.preset === Preset.AngularStandalone ||
|
||||||
options.preset === Preset.ReactStandalone ||
|
options.preset === Preset.ReactStandalone ||
|
||||||
options.preset === Preset.NodeStandalone
|
options.preset === Preset.NodeStandalone ||
|
||||||
|
options.preset === Preset.NextJsStandalone
|
||||||
? './files-root-app'
|
? './files-root-app'
|
||||||
: options.preset === Preset.NPM || options.preset === Preset.Core
|
: options.preset === Preset.NPM || options.preset === Preset.Core
|
||||||
? './files-package-based-repo'
|
? './files-package-based-repo'
|
||||||
@ -177,7 +179,8 @@ function addNpmScripts(tree: Tree, options: NormalizedSchema) {
|
|||||||
if (
|
if (
|
||||||
options.preset === Preset.AngularStandalone ||
|
options.preset === Preset.AngularStandalone ||
|
||||||
options.preset === Preset.ReactStandalone ||
|
options.preset === Preset.ReactStandalone ||
|
||||||
options.preset === Preset.NodeStandalone
|
options.preset === Preset.NodeStandalone ||
|
||||||
|
options.preset === Preset.NextJsStandalone
|
||||||
) {
|
) {
|
||||||
updateJson(tree, join(options.directory, 'package.json'), (json) => {
|
updateJson(tree, join(options.directory, 'package.json'), (json) => {
|
||||||
Object.assign(json.scripts, {
|
Object.assign(json.scripts, {
|
||||||
|
|||||||
@ -24,6 +24,7 @@ interface Schema {
|
|||||||
defaultBase: string;
|
defaultBase: string;
|
||||||
framework?: string;
|
framework?: string;
|
||||||
docker?: boolean;
|
docker?: boolean;
|
||||||
|
nextAppDir?: boolean;
|
||||||
linter?: Linter;
|
linter?: Linter;
|
||||||
bundler?: 'vite' | 'webpack';
|
bundler?: 'vite' | 'webpack';
|
||||||
standaloneApi?: boolean;
|
standaloneApi?: boolean;
|
||||||
|
|||||||
@ -71,6 +71,11 @@
|
|||||||
"description": "The framework which the application is using",
|
"description": "The framework which the application is using",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["express", "koa", "fastify", "nest", "none"]
|
"enum": ["express", "koa", "fastify", "nest", "none"]
|
||||||
|
},
|
||||||
|
"nextAppDir": {
|
||||||
|
"description": "Enable experimental app directory for the project",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": true
|
"additionalProperties": true
|
||||||
|
|||||||
@ -79,6 +79,16 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
style: options.style,
|
style: options.style,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
});
|
});
|
||||||
|
} else if (options.preset === Preset.NextJsStandalone) {
|
||||||
|
const { applicationGenerator: nextApplicationGenerator } = require('@nx' +
|
||||||
|
'/next');
|
||||||
|
return nextApplicationGenerator(tree, {
|
||||||
|
name: options.name,
|
||||||
|
style: options.style,
|
||||||
|
linter: options.linter,
|
||||||
|
appDir: options.nextAppDir,
|
||||||
|
rootProject: true,
|
||||||
|
});
|
||||||
} else if (options.preset === Preset.WebComponents) {
|
} else if (options.preset === Preset.WebComponents) {
|
||||||
const { applicationGenerator: webApplicationGenerator } = require('@nx' +
|
const { applicationGenerator: webApplicationGenerator } = require('@nx' +
|
||||||
'/web');
|
'/web');
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export interface Schema {
|
|||||||
packageManager?: PackageManager;
|
packageManager?: PackageManager;
|
||||||
bundler?: 'vite' | 'webpack' | 'rspack';
|
bundler?: 'vite' | 'webpack' | 'rspack';
|
||||||
docker?: boolean;
|
docker?: boolean;
|
||||||
|
nextAppDir?: boolean;
|
||||||
routing?: boolean;
|
routing?: boolean;
|
||||||
standaloneApi?: boolean;
|
standaloneApi?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,6 +83,11 @@
|
|||||||
"description": "Generate a Dockerfile",
|
"description": "Generate a Dockerfile",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"nextAppDir": {
|
||||||
|
"description": "Enable experimental app/ for the project",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export enum Preset {
|
|||||||
AngularStandalone = 'angular-standalone',
|
AngularStandalone = 'angular-standalone',
|
||||||
ReactMonorepo = 'react-monorepo',
|
ReactMonorepo = 'react-monorepo',
|
||||||
ReactStandalone = 'react-standalone',
|
ReactStandalone = 'react-standalone',
|
||||||
|
NextJsStandalone = 'nextjs-standalone',
|
||||||
ReactNative = 'react-native',
|
ReactNative = 'react-native',
|
||||||
Expo = 'expo',
|
Expo = 'expo',
|
||||||
NextJs = 'next',
|
NextJs = 'next',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user