feat(nextjs): Standalone projects now default to src (#21010)
This commit is contained in:
parent
49cff89908
commit
c43b22dc88
@ -119,6 +119,12 @@ Type: `boolean`
|
||||
|
||||
Enable the App Router for Next.js
|
||||
|
||||
### nextSrcDir
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Generate a 'src/' directory for Next.js
|
||||
|
||||
### nxCloud
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
@ -124,6 +124,12 @@
|
||||
"description": "Enable the App Router for this project.",
|
||||
"x-prompt": "Would you like to use the App Router (recommended)?"
|
||||
},
|
||||
"src": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Generate a `src` directory for the project.",
|
||||
"x-prompt": "Would you like to use `src/` directory?"
|
||||
},
|
||||
"rootProject": {
|
||||
"description": "Create an application at the root of the workspace.",
|
||||
"type": "boolean",
|
||||
|
||||
@ -119,6 +119,12 @@ Type: `boolean`
|
||||
|
||||
Enable the App Router for Next.js
|
||||
|
||||
### nextSrcDir
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Generate a 'src/' directory for Next.js
|
||||
|
||||
### nxCloud
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
@ -65,6 +65,11 @@
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"nextSrcDir": {
|
||||
"description": "Generate a `src` directory for this project.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "The tool to use for running e2e tests.",
|
||||
"type": "string",
|
||||
|
||||
@ -82,6 +82,11 @@
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"nextSrcDir": {
|
||||
"description": "Generate a `src` directory for this project.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "The tool to use for running e2e tests.",
|
||||
"type": "string",
|
||||
|
||||
@ -45,7 +45,7 @@ describe('Next.js Apps Libs', () => {
|
||||
const buildableLib = uniq('buildablelib');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false --src=false`
|
||||
`generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false`
|
||||
);
|
||||
runCLI(`generate @nx/next:lib ${nextLib} --no-interactive`);
|
||||
runCLI(`generate @nx/js:lib ${jsLib} --no-interactive`);
|
||||
@ -100,11 +100,11 @@ describe('Next.js Apps Libs', () => {
|
||||
`
|
||||
);
|
||||
|
||||
const mainPath = `packages/${appName}/pages/index.tsx`;
|
||||
const mainPath = `packages/${appName}/src/pages/index.tsx`;
|
||||
const content = readFile(mainPath);
|
||||
|
||||
updateFile(
|
||||
`packages/${appName}/pages/api/hello.ts`,
|
||||
`packages/${appName}/src/pages/api/hello.ts`,
|
||||
`
|
||||
import { jsLibAsync } from '@${proj}/${jsLib}';
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ describe('Next.js Applications', () => {
|
||||
|
||||
// check files are generated without the layout directory ("apps/") and
|
||||
// using the project name as the directory when no directory is provided
|
||||
checkFilesExist(`${appName}/app/page.tsx`);
|
||||
checkFilesExist(`${appName}/src/app/page.tsx`);
|
||||
// check build works
|
||||
expect(runCLI(`build ${appName}`)).toContain(
|
||||
`Successfully ran target build for project ${appName}`
|
||||
@ -179,7 +179,7 @@ describe('Next.js Applications', () => {
|
||||
`generate @nx/next:app ${appName} --no-interactive --js --appDir=false`
|
||||
);
|
||||
|
||||
checkFilesExist(`apps/${appName}/pages/index.js`);
|
||||
checkFilesExist(`apps/${appName}/src/pages/index.js`);
|
||||
|
||||
await checkApp(appName, {
|
||||
checkUnitTest: true,
|
||||
@ -195,7 +195,7 @@ describe('Next.js Applications', () => {
|
||||
`generate @nx/next:lib ${libName} --no-interactive --style=none --js`
|
||||
);
|
||||
|
||||
const mainPath = `apps/${appName}/pages/index.js`;
|
||||
const mainPath = `apps/${appName}/src/pages/index.js`;
|
||||
updateFile(
|
||||
mainPath,
|
||||
`import '@${proj}/${libName}';\n` + readFile(mainPath)
|
||||
|
||||
@ -108,7 +108,9 @@ function addBabelSupport(path: string) {
|
||||
}
|
||||
|
||||
function createAppWithCt(appName: string) {
|
||||
runCLI(`generate @nx/next:app ${appName} --no-interactive --appDir=false`);
|
||||
runCLI(
|
||||
`generate @nx/next:app ${appName} --no-interactive --appDir=false --src=false`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/next:component button --project=${appName} --directory=components --flat --no-interactive`
|
||||
);
|
||||
|
||||
@ -22,7 +22,7 @@ describe('Next.js Styles', () => {
|
||||
const lessApp = uniq('app');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/next:app ${lessApp} --no-interactive --style=less --appDir=false`
|
||||
`generate @nx/next:app ${lessApp} --no-interactive --style=less --appDir=false --src=false`
|
||||
);
|
||||
|
||||
await checkApp(lessApp, {
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
getPackageManagerCommand,
|
||||
getSelectedPackageManager,
|
||||
runCommand,
|
||||
runE2ETests,
|
||||
} from '@nx/e2e/utils';
|
||||
import { join } from 'path';
|
||||
|
||||
@ -41,7 +42,9 @@ describe('@nx/workspace:convert-to-monorepo', () => {
|
||||
expect(() => runCLI(`test ${reactApp}`)).not.toThrow();
|
||||
expect(() => runCLI(`lint ${reactApp}`)).not.toThrow();
|
||||
expect(() => runCLI(`lint e2e`)).not.toThrow();
|
||||
if (runE2ETests()) {
|
||||
expect(() => runCLI(`e2e e2e`)).not.toThrow();
|
||||
}
|
||||
});
|
||||
|
||||
it('should be convert a standalone vite and playwright react project to a monorepo', async () => {
|
||||
@ -61,7 +64,9 @@ describe('@nx/workspace:convert-to-monorepo', () => {
|
||||
expect(() => runCLI(`test ${reactApp}`)).not.toThrow();
|
||||
expect(() => runCLI(`lint ${reactApp}`)).not.toThrow();
|
||||
expect(() => runCLI(`lint e2e`)).not.toThrow();
|
||||
if (runE2ETests()) {
|
||||
expect(() => runCLI(`e2e e2e`)).not.toThrow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -229,6 +229,7 @@ export function runCreateWorkspace(
|
||||
standaloneApi,
|
||||
docker,
|
||||
nextAppDir,
|
||||
nextSrcDir,
|
||||
e2eTestRunner,
|
||||
ssr,
|
||||
framework,
|
||||
@ -247,6 +248,7 @@ export function runCreateWorkspace(
|
||||
routing?: boolean;
|
||||
docker?: boolean;
|
||||
nextAppDir?: boolean;
|
||||
nextSrcDir?: boolean;
|
||||
e2eTestRunner?: 'cypress' | 'playwright' | 'jest' | 'detox' | 'none';
|
||||
ssr?: boolean;
|
||||
framework?: string;
|
||||
@ -275,6 +277,10 @@ export function runCreateWorkspace(
|
||||
command += ` --nextAppDir=${nextAppDir}`;
|
||||
}
|
||||
|
||||
if (nextSrcDir !== undefined) {
|
||||
command += ` --nextSrcDir=${nextSrcDir}`;
|
||||
}
|
||||
|
||||
if (docker !== undefined) {
|
||||
command += ` --docker=${docker}`;
|
||||
}
|
||||
|
||||
@ -223,11 +223,12 @@ describe('create-nx-workspace', () => {
|
||||
style: 'css',
|
||||
appName,
|
||||
nextAppDir: false,
|
||||
nextSrcDir: true,
|
||||
packageManager,
|
||||
e2eTestRunner: 'none',
|
||||
});
|
||||
|
||||
checkFilesExist(`apps/${appName}/pages/index.tsx`);
|
||||
checkFilesExist(`apps/${appName}/src/pages/index.tsx`);
|
||||
|
||||
expectNoAngularDevkit();
|
||||
expectCodeIsFormatted();
|
||||
@ -240,12 +241,13 @@ describe('create-nx-workspace', () => {
|
||||
preset: 'nextjs-standalone',
|
||||
style: 'css',
|
||||
nextAppDir: true,
|
||||
nextSrcDir: true,
|
||||
appName,
|
||||
packageManager,
|
||||
e2eTestRunner: 'none',
|
||||
});
|
||||
|
||||
checkFilesExist('app/page.tsx');
|
||||
checkFilesExist('src/app/page.tsx');
|
||||
|
||||
expectNoAngularDevkit();
|
||||
expectCodeIsFormatted();
|
||||
@ -258,12 +260,13 @@ describe('create-nx-workspace', () => {
|
||||
preset: 'nextjs-standalone',
|
||||
style: 'css',
|
||||
nextAppDir: false,
|
||||
nextSrcDir: true,
|
||||
appName,
|
||||
packageManager,
|
||||
e2eTestRunner: 'none',
|
||||
});
|
||||
|
||||
checkFilesExist('pages/index.tsx');
|
||||
checkFilesExist('src/pages/index.tsx');
|
||||
|
||||
expectNoAngularDevkit();
|
||||
expectCodeIsFormatted();
|
||||
|
||||
@ -49,6 +49,7 @@ interface ReactArguments extends BaseArguments {
|
||||
style: string;
|
||||
bundler: 'webpack' | 'vite' | 'rspack';
|
||||
nextAppDir: boolean;
|
||||
nextSrcDir: boolean;
|
||||
e2eTestRunner: 'none' | 'cypress' | 'playwright';
|
||||
}
|
||||
|
||||
@ -164,6 +165,10 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
|
||||
describe: chalk.dim`Enable the App Router for Next.js`,
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('nextSrcDir', {
|
||||
describe: chalk.dim`Generate a 'src/' directory for Next.js`,
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('e2eTestRunner', {
|
||||
describe: chalk.dim`Test runner to use for end to end (E2E) tests.`,
|
||||
choices: ['cypress', 'playwright', 'none'],
|
||||
@ -512,6 +517,7 @@ async function determineReactOptions(
|
||||
let bundler: undefined | 'webpack' | 'vite' | 'rspack' = undefined;
|
||||
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;
|
||||
let nextAppDir = false;
|
||||
let nextSrcDir = false;
|
||||
|
||||
if (parsedArgs.preset && parsedArgs.preset !== Preset.React) {
|
||||
preset = parsedArgs.preset;
|
||||
@ -563,6 +569,7 @@ async function determineReactOptions(
|
||||
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
|
||||
} else if (preset === Preset.NextJs || preset === Preset.NextJsStandalone) {
|
||||
nextAppDir = await determineNextAppDir(parsedArgs);
|
||||
nextSrcDir = await determineNextSrcDir(parsedArgs);
|
||||
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
|
||||
}
|
||||
|
||||
@ -614,7 +621,15 @@ async function determineReactOptions(
|
||||
style = reply.style;
|
||||
}
|
||||
|
||||
return { preset, style, appName, bundler, nextAppDir, e2eTestRunner };
|
||||
return {
|
||||
preset,
|
||||
style,
|
||||
appName,
|
||||
bundler,
|
||||
nextAppDir,
|
||||
nextSrcDir,
|
||||
e2eTestRunner,
|
||||
};
|
||||
}
|
||||
|
||||
async function determineVueOptions(
|
||||
@ -1066,6 +1081,29 @@ async function determineNextAppDir(
|
||||
return reply.nextAppDir === 'Yes';
|
||||
}
|
||||
|
||||
async function determineNextSrcDir(
|
||||
parsedArgs: yargs.Arguments<ReactArguments>
|
||||
): Promise<boolean> {
|
||||
if (parsedArgs.nextSrcDir !== undefined) return parsedArgs.nextSrcDir;
|
||||
const reply = await enquirer.prompt<{ nextSrcDir: 'Yes' | 'No' }>([
|
||||
{
|
||||
name: 'nextSrcDir',
|
||||
message: 'Would you like to use the src/ directory?',
|
||||
type: 'autocomplete',
|
||||
choices: [
|
||||
{
|
||||
name: 'Yes',
|
||||
},
|
||||
{
|
||||
name: 'No',
|
||||
},
|
||||
],
|
||||
initial: 'Yes' as any,
|
||||
},
|
||||
]);
|
||||
return reply.nextSrcDir === 'Yes';
|
||||
}
|
||||
|
||||
async function determineVueFramework(
|
||||
parsedArgs: yargs.Arguments<VueArguments>
|
||||
): Promise<'none' | 'nuxt'> {
|
||||
|
||||
@ -82,12 +82,12 @@ describe('app', () => {
|
||||
`../dist/${name}/.next/types/**/*.ts`,
|
||||
'next-env.d.ts',
|
||||
]);
|
||||
expect(tree.exists(`${name}/pages/styles.css`)).toBeFalsy();
|
||||
expect(tree.exists(`${name}/app/global.css`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/app/page.tsx`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/app/layout.tsx`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/app/api/hello/route.ts`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/app/page.module.css`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/pages/styles.css`)).toBeFalsy();
|
||||
expect(tree.exists(`${name}/src/app/global.css`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/page.tsx`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/layout.tsx`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/api/hello/route.ts`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/page.module.css`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/public/favicon.ico`)).toBeTruthy();
|
||||
});
|
||||
|
||||
@ -123,7 +123,7 @@ describe('app', () => {
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
const content = tree.read('app/page.tsx').toString();
|
||||
const content = tree.read('src/app/page.tsx').toString();
|
||||
|
||||
expect(content).not.toContain('import styles from');
|
||||
expect(content).not.toContain('const StyledPage');
|
||||
@ -138,6 +138,7 @@ describe('app', () => {
|
||||
name,
|
||||
style: 'css',
|
||||
appDir: false,
|
||||
src: false,
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
expect(tree.exists(`${name}/tsconfig.json`)).toBeTruthy();
|
||||
@ -166,6 +167,7 @@ describe('app', () => {
|
||||
name,
|
||||
style: 'none',
|
||||
appDir: false,
|
||||
src: false,
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
@ -186,12 +188,12 @@ describe('app', () => {
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
expect(tree.exists(`${name}/app/page.module.scss`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/app/global.css`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/page.module.scss`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/global.css`)).toBeTruthy();
|
||||
|
||||
const indexContent = tree.read(`${name}/app/page.tsx`, 'utf-8');
|
||||
const indexContent = tree.read(`${name}/src/app/page.tsx`, 'utf-8');
|
||||
expect(indexContent).toContain(`import styles from './page.module.scss'`);
|
||||
expect(tree.read(`${name}/app/layout.tsx`, 'utf-8'))
|
||||
expect(tree.read(`${name}/src/app/layout.tsx`, 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"import './global.css';
|
||||
|
||||
@ -225,12 +227,12 @@ describe('app', () => {
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
expect(tree.exists(`${name}/app/page.module.less`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/app/global.less`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/page.module.less`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/global.less`)).toBeTruthy();
|
||||
|
||||
const indexContent = tree.read(`${name}/app/page.tsx`, 'utf-8');
|
||||
const indexContent = tree.read(`${name}/src/app/page.tsx`, 'utf-8');
|
||||
expect(indexContent).toContain(`import styles from './page.module.less'`);
|
||||
expect(tree.read(`${name}/app/layout.tsx`, 'utf-8'))
|
||||
expect(tree.read(`${name}/src/app/layout.tsx`, 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"import './global.less';
|
||||
|
||||
@ -265,14 +267,14 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
expect(
|
||||
tree.exists(`${name}/app/page.module.styled-components`)
|
||||
tree.exists(`${name}/src/app/page.module.styled-components`)
|
||||
).toBeFalsy();
|
||||
expect(tree.exists(`${name}/app/global.css`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/global.css`)).toBeTruthy();
|
||||
|
||||
const indexContent = tree.read(`${name}/app/page.tsx`, 'utf-8');
|
||||
const indexContent = tree.read(`${name}/src/app/page.tsx`, 'utf-8');
|
||||
expect(indexContent).not.toContain(`import styles from './page.module`);
|
||||
expect(indexContent).toContain(`import styled from 'styled-components'`);
|
||||
expect(tree.read(`${name}/app/layout.tsx`, 'utf-8'))
|
||||
expect(tree.read(`${name}/src/app/layout.tsx`, 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"import './global.css';
|
||||
import { StyledComponentsRegistry } from './registry';
|
||||
@ -297,7 +299,7 @@ describe('app', () => {
|
||||
}
|
||||
"
|
||||
`);
|
||||
expect(tree.read(`${name}/app/registry.tsx`, 'utf-8'))
|
||||
expect(tree.read(`${name}/src/app/registry.tsx`, 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"'use client';
|
||||
|
||||
@ -348,14 +350,14 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
expect(
|
||||
tree.exists(`${name}/app/page.module.styled-components`)
|
||||
tree.exists(`${name}/src/app/page.module.styled-components`)
|
||||
).toBeFalsy();
|
||||
expect(tree.exists(`${name}/app/global.css`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/global.css`)).toBeTruthy();
|
||||
|
||||
const indexContent = tree.read(`${name}/app/page.tsx`, 'utf-8');
|
||||
const indexContent = tree.read(`${name}/src/app/page.tsx`, 'utf-8');
|
||||
expect(indexContent).not.toContain(`import styles from './page.module`);
|
||||
expect(indexContent).toContain(`import styled from '@emotion/styled'`);
|
||||
expect(tree.read(`${name}/app/layout.tsx`, 'utf-8'))
|
||||
expect(tree.read(`${name}/src/app/layout.tsx`, 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"import './global.css';
|
||||
|
||||
@ -406,17 +408,17 @@ describe('app', () => {
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
const indexContent = tree.read(`${name}/app/page.tsx`, 'utf-8');
|
||||
const indexContent = tree.read(`${name}/src/app/page.tsx`, 'utf-8');
|
||||
|
||||
expect(indexContent).toMatchSnapshot();
|
||||
expect(tree.exists(`${name}/app/page.module.styled-jsx`)).toBeFalsy();
|
||||
expect(tree.exists(`${name}/app/global.css`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/page.module.styled-jsx`)).toBeFalsy();
|
||||
expect(tree.exists(`${name}/src/app/global.css`)).toBeTruthy();
|
||||
|
||||
expect(indexContent).not.toContain(`import styles from './page.module`);
|
||||
expect(indexContent).not.toContain(
|
||||
`import styled from 'styled-components'`
|
||||
);
|
||||
expect(tree.read(`${name}/app/layout.tsx`, 'utf-8'))
|
||||
expect(tree.read(`${name}/src/app/layout.tsx`, 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"import './global.css';
|
||||
import { StyledJsxRegistry } from './registry';
|
||||
@ -436,7 +438,7 @@ describe('app', () => {
|
||||
}
|
||||
"
|
||||
`);
|
||||
expect(tree.read(`${name}/app/registry.tsx`, 'utf-8'))
|
||||
expect(tree.read(`${name}/src/app/registry.tsx`, 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"'use client';
|
||||
|
||||
@ -588,7 +590,7 @@ describe('app', () => {
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
const appContent = tree.read(`${name}/app/page.tsx`, 'utf-8');
|
||||
const appContent = tree.read(`${name}/src/app/page.tsx`, 'utf-8');
|
||||
|
||||
expect(appContent).not.toMatch(/extends Component/);
|
||||
});
|
||||
@ -709,7 +711,7 @@ describe('app', () => {
|
||||
js: true,
|
||||
});
|
||||
|
||||
expect(tree.exists(`${name}/app/page.js`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/src/app/page.js`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/specs/index.spec.js`)).toBeTruthy();
|
||||
expect(tree.exists(`${name}/index.d.js`)).toBeFalsy();
|
||||
expect(tree.exists(`${name}/index.d.ts`)).toBeFalsy();
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
<% if (src) { %>
|
||||
import Index from '../src/pages/index';
|
||||
<% } else { %>
|
||||
import Index from '../pages/index';
|
||||
|
||||
<% } %>
|
||||
describe('Index', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<Index />);
|
||||
|
||||
@ -48,6 +48,10 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||
stylesExt: options.style === 'less' ? options.style : 'css',
|
||||
};
|
||||
|
||||
const generatedAppFilePath = options.src
|
||||
? join(options.appProjectRoot, 'src')
|
||||
: options.appProjectRoot;
|
||||
|
||||
generateFiles(
|
||||
host,
|
||||
join(__dirname, '../files/common'),
|
||||
@ -59,7 +63,7 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||
generateFiles(
|
||||
host,
|
||||
join(__dirname, '../files/app'),
|
||||
join(options.appProjectRoot, 'app'),
|
||||
join(generatedAppFilePath, 'app'),
|
||||
templateVariables
|
||||
);
|
||||
|
||||
@ -76,21 +80,21 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||
generateFiles(
|
||||
host,
|
||||
join(__dirname, '../files/app-styled-components'),
|
||||
join(options.appProjectRoot, 'app'),
|
||||
join(generatedAppFilePath, 'app'),
|
||||
templateVariables
|
||||
);
|
||||
} else if (options.style === 'styled-jsx') {
|
||||
generateFiles(
|
||||
host,
|
||||
join(__dirname, '../files/app-styled-jsx'),
|
||||
join(options.appProjectRoot, 'app'),
|
||||
join(generatedAppFilePath, 'app'),
|
||||
templateVariables
|
||||
);
|
||||
} else {
|
||||
generateFiles(
|
||||
host,
|
||||
join(__dirname, '../files/app-default-layout'),
|
||||
join(options.appProjectRoot, 'app'),
|
||||
join(generatedAppFilePath, 'app'),
|
||||
templateVariables
|
||||
);
|
||||
}
|
||||
@ -98,7 +102,7 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||
generateFiles(
|
||||
host,
|
||||
join(__dirname, '../files/pages'),
|
||||
join(options.appProjectRoot, 'pages'),
|
||||
join(generatedAppFilePath, 'pages'),
|
||||
templateVariables
|
||||
);
|
||||
}
|
||||
@ -151,16 +155,16 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||
|
||||
if (options.styledModule) {
|
||||
if (options.appDir) {
|
||||
host.delete(`${options.appProjectRoot}/app/page.module.${options.style}`);
|
||||
host.delete(`${generatedAppFilePath}/app/page.module.${options.style}`);
|
||||
} else {
|
||||
host.delete(
|
||||
`${options.appProjectRoot}/pages/${options.fileName}.module.${options.style}`
|
||||
`${generatedAppFilePath}/pages/${options.fileName}.module.${options.style}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.style !== 'styled-components') {
|
||||
host.delete(`${options.appProjectRoot}/pages/_document.tsx`);
|
||||
host.delete(`${generatedAppFilePath}/pages/_document.tsx`);
|
||||
}
|
||||
|
||||
if (options.js) {
|
||||
|
||||
@ -53,6 +53,7 @@ export async function normalizeOptions(
|
||||
const fileName = 'index';
|
||||
|
||||
const appDir = options.appDir ?? true;
|
||||
const src = options.src ?? true;
|
||||
|
||||
const styledModule = /^(css|scss|less)$/.test(options.style)
|
||||
? null
|
||||
@ -63,6 +64,7 @@ export async function normalizeOptions(
|
||||
return {
|
||||
...options,
|
||||
appDir,
|
||||
src,
|
||||
appProjectRoot,
|
||||
e2eProjectName,
|
||||
e2eProjectRoot,
|
||||
|
||||
@ -18,5 +18,6 @@ export interface Schema {
|
||||
customServer?: boolean;
|
||||
skipPackageJson?: boolean;
|
||||
appDir?: boolean;
|
||||
src?: boolean;
|
||||
rootProject?: boolean;
|
||||
}
|
||||
|
||||
@ -127,6 +127,12 @@
|
||||
"description": "Enable the App Router for this project.",
|
||||
"x-prompt": "Would you like to use the App Router (recommended)?"
|
||||
},
|
||||
"src": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Generate a `src` directory for the project.",
|
||||
"x-prompt": "Would you like to use `src/` directory?"
|
||||
},
|
||||
"rootProject": {
|
||||
"description": "Create an application at the root of the workspace.",
|
||||
"type": "boolean",
|
||||
|
||||
@ -111,6 +111,7 @@ describe('monorepo generator', () => {
|
||||
unitTestRunner: 'jest',
|
||||
e2eTestRunner: 'none',
|
||||
appDir: true,
|
||||
src: true,
|
||||
linter: 'eslint',
|
||||
rootProject: true,
|
||||
});
|
||||
@ -121,7 +122,7 @@ describe('monorepo generator', () => {
|
||||
expect(readProjectConfiguration(tree, 'demo')).toMatchObject({
|
||||
sourceRoot: 'apps/demo',
|
||||
});
|
||||
expect(tree.read('apps/demo/app/page.tsx', 'utf-8')).toContain('demo');
|
||||
expect(tree.read('apps/demo/src/app/page.tsx', 'utf-8')).toContain('demo');
|
||||
expect(readProjectConfiguration(tree, 'util')).toMatchObject({
|
||||
sourceRoot: 'libs/util/src',
|
||||
});
|
||||
|
||||
@ -70,6 +70,7 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) {
|
||||
opts.docker ? `--docker=${opts.docker}` : null,
|
||||
opts.js ? `--js` : null,
|
||||
opts.nextAppDir ? '--nextAppDir=true' : '--nextAppDir=false',
|
||||
opts.nextSrcDir ? '--nextSrcDir=true' : '--nextSrcDir=false',
|
||||
opts.packageManager ? `--packageManager=${opts.packageManager}` : null,
|
||||
opts.standaloneApi !== undefined
|
||||
? `--standaloneApi=${opts.standaloneApi}`
|
||||
|
||||
@ -26,6 +26,7 @@ interface Schema {
|
||||
docker?: boolean;
|
||||
js?: boolean;
|
||||
nextAppDir?: boolean;
|
||||
nextSrcDir?: boolean;
|
||||
linter?: Linter;
|
||||
bundler?: 'vite' | 'webpack';
|
||||
standaloneApi?: boolean;
|
||||
|
||||
@ -68,6 +68,11 @@
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"nextSrcDir": {
|
||||
"description": "Generate a `src` directory for this project.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "The tool to use for running e2e tests.",
|
||||
"type": "string",
|
||||
|
||||
@ -70,7 +70,7 @@ describe('preset', () => {
|
||||
style: 'css',
|
||||
linter: 'eslint',
|
||||
});
|
||||
expect(tree.exists('/apps/proj/app/page.tsx')).toBe(true);
|
||||
expect(tree.exists('/apps/proj/src/app/page.tsx')).toBe(true);
|
||||
});
|
||||
|
||||
it(`should create files (preset = ${Preset.Express})`, async () => {
|
||||
|
||||
@ -143,6 +143,7 @@ async function createPreset(tree: Tree, options: Schema) {
|
||||
style: options.style,
|
||||
linter: options.linter,
|
||||
appDir: options.nextAppDir,
|
||||
src: options.nextSrcDir,
|
||||
e2eTestRunner: options.e2eTestRunner ?? 'cypress',
|
||||
});
|
||||
} else if (options.preset === Preset.NextJsStandalone) {
|
||||
@ -155,6 +156,7 @@ async function createPreset(tree: Tree, options: Schema) {
|
||||
style: options.style,
|
||||
linter: options.linter,
|
||||
appDir: options.nextAppDir,
|
||||
src: options.nextSrcDir,
|
||||
e2eTestRunner: options.e2eTestRunner ?? 'cypress',
|
||||
rootProject: true,
|
||||
});
|
||||
|
||||
@ -12,6 +12,7 @@ export interface Schema {
|
||||
bundler?: 'vite' | 'webpack' | 'rspack' | 'esbuild';
|
||||
docker?: boolean;
|
||||
nextAppDir?: boolean;
|
||||
nextSrcDir?: boolean;
|
||||
routing?: boolean;
|
||||
standaloneApi?: boolean;
|
||||
e2eTestRunner?: 'cypress' | 'playwright' | 'jest' | 'detox' | 'none';
|
||||
|
||||
@ -85,6 +85,11 @@
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"nextSrcDir": {
|
||||
"description": "Generate a `src` directory for this project.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "The tool to use for running e2e tests.",
|
||||
"type": "string",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user