feat(nextjs): update Next.js to 13.4.1 and default to App Router for new apps (#16948)

This commit is contained in:
Jack Hsu 2023-05-12 16:09:20 -04:00 committed by GitHub
parent 0aa3e45e2e
commit 95421c6945
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 248 additions and 144 deletions

View File

@ -113,7 +113,7 @@ Workspace name (e.g. org name)
Type: `boolean`
Add Experimental app/ layout for next.js
Enable the App Router for Next.js
### nxCloud

View File

@ -118,9 +118,9 @@
},
"appDir": {
"type": "boolean",
"default": false,
"description": "Enable experimental app directory for the project",
"x-prompt": "Do you want to use experimental app/ in this project?"
"default": true,
"description": "Enable the App Router for this project.",
"x-prompt": "Would you like to use the App Router (recommended)?"
},
"rootProject": {
"description": "Create an application at the root of the workspace.",

View File

@ -113,7 +113,7 @@ Workspace name (e.g. org name)
Type: `boolean`
Add Experimental app/ layout for next.js
Enable the App Router for Next.js
### nxCloud

View File

@ -70,9 +70,9 @@
"enum": ["express", "koa", "fastify", "nest", "none"]
},
"nextAppDir": {
"description": "Enable experimental app directory for the project",
"description": "Enable the App Router for this project.",
"type": "boolean",
"default": false
"default": true
},
"e2eTestRunner": {
"description": "The tool to use for running e2e tests.",

View File

@ -82,9 +82,9 @@
"default": false
},
"nextAppDir": {
"description": "Enable experimental app/ for the project",
"description": "Enable the App Router for this project.",
"type": "boolean",
"default": false
"default": true
},
"e2eTestRunner": {
"description": "The tool to use for running e2e tests.",

View File

@ -0,0 +1,56 @@
import {
cleanupProject,
isNotWindows,
killPorts,
newProject,
runCLI,
runCommandUntil,
tmpProjPath,
uniq,
updateFile,
} from '@nx/e2e/utils';
import { getData } from 'ajv/dist/compile/validate';
import { detectPackageManager } from 'nx/src/utils/package-manager';
import { checkApp } from './utils';
import { p } from 'vitest/dist/types-b7007192';
describe('Next.js App Router', () => {
let proj: string;
beforeEach(() => {
proj = newProject();
});
afterEach(() => {
cleanupProject();
});
it('should be able to generate and build app with default App Router', async () => {
const appName = uniq('app');
const jsLib = uniq('tslib');
runCLI(`generate @nx/next:app ${appName}`);
runCLI(`generate @nx/js:lib ${jsLib} --no-interactive`);
updateFile(
`apps/${appName}/app/page.tsx`,
`
import React from 'react';
import { ${jsLib} } from '@${proj}/${jsLib}';
export default async function Page() {
return (
<p>{${jsLib}()}</p>
);
};
`
);
await checkApp(appName, {
checkUnitTest: false,
checkLint: true,
checkE2E: false,
checkExport: false,
});
}, 300_000);
});

View File

@ -65,7 +65,7 @@ describe('NextJs Component Testing', () => {
});
function createAppWithCt(appName: string) {
runCLI(`generate @nx/next:app ${appName} --no-interactive`);
runCLI(`generate @nx/next:app ${appName} --no-interactive --appDir=false`);
runCLI(
`generate @nx/next:component button --project=${appName} --directory=components --flat --no-interactive`
);

View File

@ -21,7 +21,9 @@ describe('Next.js apps', () => {
it('should support different --style options', async () => {
const lessApp = uniq('app');
runCLI(`generate @nx/next:app ${lessApp} --no-interactive --style=less`);
runCLI(
`generate @nx/next:app ${lessApp} --no-interactive --style=less --appDir=false`
);
await checkApp(lessApp, {
checkUnitTest: false,
@ -32,7 +34,9 @@ describe('Next.js apps', () => {
const stylusApp = uniq('app');
runCLI(`generate @nx/next:app ${stylusApp} --no-interactive --style=styl`);
runCLI(
`generate @nx/next:app ${stylusApp} --no-interactive --style=styl --appDir=false`
);
await checkApp(stylusApp, {
checkUnitTest: false,
@ -44,7 +48,7 @@ describe('Next.js apps', () => {
const scApp = uniq('app');
runCLI(
`generate @nx/next:app ${scApp} --no-interactive --style=styled-components`
`generate @nx/next:app ${scApp} --no-interactive --style=styled-components --appDir=false`
);
await checkApp(scApp, {
@ -57,7 +61,7 @@ describe('Next.js apps', () => {
const emotionApp = uniq('app');
runCLI(
`generate @nx/next:app ${emotionApp} --no-interactive --style=@emotion/styled`
`generate @nx/next:app ${emotionApp} --no-interactive --style=@emotion/styled --appDir=false`
);
await checkApp(emotionApp, {

View File

@ -52,7 +52,9 @@ describe('Next.js Applications', () => {
const jsLib = uniq('tslib');
const buildableLib = uniq('buildablelib');
runCLI(`generate @nx/next:app ${appName} --no-interactive --style=css`);
runCLI(
`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`);
runCLI(
@ -231,7 +233,7 @@ describe('Next.js Applications', () => {
const port = 4200;
runCLI(`generate @nx/next:app ${appName}`);
runCLI(`generate @nx/next:app ${appName} --appDir=false`);
runCLI(`generate @nx/js:lib ${jsLib} --no-interactive`);
const proxyConf = {
@ -297,7 +299,9 @@ describe('Next.js Applications', () => {
it('should support custom next.config.js and output it in dist', async () => {
const appName = uniq('app');
runCLI(`generate @nx/next:app ${appName} --no-interactive --style=css`);
runCLI(
`generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false`
);
updateFile(
`apps/${appName}/next.config.js`,
@ -354,7 +358,9 @@ describe('Next.js Applications', () => {
it('should support --js flag', async () => {
const appName = uniq('app');
runCLI(`generate @nx/next:app ${appName} --no-interactive --js`);
runCLI(
`generate @nx/next:app ${appName} --no-interactive --js --appDir=false`
);
checkFilesExist(`apps/${appName}/pages/index.js`);

View File

@ -18,14 +18,6 @@ export async function checkApp(
}
) {
const appsDir = opts.appsDir ?? 'apps';
const buildResult = runCLI(`build ${appName}`);
expect(buildResult).toContain(`Compiled successfully`);
checkFilesExist(`dist/${appsDir}/${appName}/.next/build-manifest.json`);
const packageJson = readJson(`dist/${appsDir}/${appName}/package.json`);
expect(packageJson.dependencies.react).toBeDefined();
expect(packageJson.dependencies['react-dom']).toBeDefined();
expect(packageJson.dependencies.next).toBeDefined();
if (opts.checkLint) {
const lintResults = runCLI(`lint ${appName}`);
@ -39,8 +31,19 @@ export async function checkApp(
);
}
const buildResult = runCLI(`build ${appName}`);
expect(buildResult).toContain(`Successfully ran target build`);
checkFilesExist(`dist/${appsDir}/${appName}/.next/build-manifest.json`);
const packageJson = readJson(`dist/${appsDir}/${appName}/package.json`);
expect(packageJson.dependencies.react).toBeDefined();
expect(packageJson.dependencies['react-dom']).toBeDefined();
expect(packageJson.dependencies.next).toBeDefined();
if (opts.checkE2E && runCypressTests()) {
const e2eResults = runCLI(`e2e ${appName}-e2e --no-watch`);
const e2eResults = runCLI(
`e2e ${appName}-e2e --no-watch --configuration=production`
);
expect(e2eResults).toContain('All specs passed!');
expect(await killPorts()).toBeTruthy();
}

View File

@ -107,7 +107,7 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
type: 'boolean',
})
.option('nextAppDir', {
describe: chalk.dim`Add Experimental app/ layout for next.js`,
describe: chalk.dim`Enable the App Router for Next.js`,
type: 'boolean',
}),
withNxCloud,
@ -638,8 +638,8 @@ async function isNextAppDir(parsedArgs: yargs.Arguments<Arguments>) {
.prompt<{ appDir: 'Yes' | 'No' }>([
{
name: 'appDir',
message: 'Do you want to use experimental app/ in this project?',
type: 'autocomplete',
message: 'Would you like to use the App Router (recommended)?',
type: 'autocomplete' as const,
choices: [
{
name: 'No',
@ -648,7 +648,7 @@ async function isNextAppDir(parsedArgs: yargs.Arguments<Arguments>) {
name: 'Yes',
},
],
initial: 'No' as any,
initial: 'Yes' as any,
},
])
.then((choice) => choice.appDir === 'Yes');

View File

@ -316,6 +316,22 @@
"alwaysAddToPackageJson": false
}
}
},
"16.2.0": {
"version": "16.2.0-beta.0",
"requires": {
"next": ">=13.0.0"
},
"packages": {
"next": {
"version": "13.4.1",
"alwaysAddToPackageJson": false
},
"eslint-config-next": {
"version": "13.4.1",
"alwaysAddToPackageJson": false
}
}
}
}
}

View File

@ -6,14 +6,6 @@ import { WithNxOptions } from './with-nx';
const addLessToRegExp = (rx) =>
new RegExp(rx.source.replace('|sass', '|sass|less'), rx.flags);
function patchNextCSSWithLess(
nextCSSModule: any = require('next/dist/build/webpack/config/blocks/css')
) {
nextCSSModule.regexLikeCss = addLessToRegExp(nextCSSModule.regexLikeCss);
}
patchNextCSSWithLess();
export function withLess(
configOrFn: NextConfigFn | WithNxOptions
): NextConfigFn {
@ -108,4 +100,3 @@ export function withLess(
module.exports = withLess;
module.exports.withLess = withLess;
module.exports.patchNext = patchNextCSSWithLess;

View File

@ -6,14 +6,6 @@ import { WithNxOptions } from './with-nx';
const addStylusToRegExp = (rx) =>
new RegExp(rx.source.replace('|sass', '|sass|styl'), rx.flags);
function patchNextCSSWithStylus(
nextCSSModule = require('next/dist/build/webpack/config/blocks/css') as any
) {
nextCSSModule.regexLikeCss = addStylusToRegExp(nextCSSModule.regexLikeCss);
}
patchNextCSSWithStylus();
export function withStylus(
configOrFn: WithNxOptions | NextConfigFn
): NextConfigFn {
@ -107,4 +99,3 @@ export function withStylus(
module.exports = withStylus;
module.exports.withStylus = withStylus;
module.exports.patchNext = patchNextCSSWithStylus;

View File

@ -1,7 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`app --style styled-jsx should use <style jsx> in index page 1`] = `
"export function Index() {
"'use client';
export default async function Index() {
/*
* Replace the elements below with your own.
*
@ -420,7 +422,5 @@ exports[`app --style styled-jsx should use <style jsx> in index page 1`] = `
</div>
);
}
export default Index;
"
`;

View File

@ -50,12 +50,23 @@ describe('app', () => {
});
});
it('should generate files', async () => {
it('should generate files for app router layout', async () => {
await applicationGenerator(tree, {
name: 'myApp',
style: 'css',
});
expect(tree.exists('apps/my-app/tsconfig.json')).toBeTruthy();
expect(tree.exists('apps/my-app/app/page.tsx')).toBeTruthy();
expect(tree.exists('apps/my-app/app/page.module.css')).toBeTruthy();
});
it('should generate files for pages layout', async () => {
await applicationGenerator(tree, {
name: 'myApp',
style: 'css',
appDir: false,
});
expect(tree.exists('apps/my-app/tsconfig.json')).toBeTruthy();
expect(tree.exists('apps/my-app/pages/index.tsx')).toBeTruthy();
expect(tree.exists('apps/my-app/specs/index.spec.tsx')).toBeTruthy();
expect(tree.exists('apps/my-app/pages/index.module.css')).toBeTruthy();
@ -91,13 +102,11 @@ describe('app', () => {
style: 'scss',
});
expect(tree.exists('apps/my-app/pages/index.module.scss')).toBeTruthy();
expect(tree.exists('apps/my-app/pages/styles.css')).toBeTruthy();
expect(tree.exists('apps/my-app/app/page.module.scss')).toBeTruthy();
expect(tree.exists('apps/my-app/app/global.css')).toBeTruthy();
const indexContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8');
expect(indexContent).toContain(
`import styles from './index.module.scss'`
);
const indexContent = tree.read('apps/my-app/app/page.tsx', 'utf-8');
expect(indexContent).toContain(`import styles from './page.module.scss'`);
});
});
@ -108,13 +117,11 @@ describe('app', () => {
style: 'less',
});
expect(tree.exists('apps/my-app/pages/index.module.less')).toBeTruthy();
expect(tree.exists('apps/my-app/pages/styles.less')).toBeTruthy();
expect(tree.exists('apps/my-app/app/page.module.less')).toBeTruthy();
expect(tree.exists('apps/my-app/app/global.less')).toBeTruthy();
const indexContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8');
expect(indexContent).toContain(
`import styles from './index.module.less'`
);
const indexContent = tree.read('apps/my-app/app/page.tsx', 'utf-8');
expect(indexContent).toContain(`import styles from './page.module.less'`);
});
});
@ -125,13 +132,11 @@ describe('app', () => {
style: 'styl',
});
expect(tree.exists('apps/my-app/pages/index.module.styl')).toBeTruthy();
expect(tree.exists('apps/my-app/pages/styles.styl')).toBeTruthy();
expect(tree.exists('apps/my-app/app/page.module.styl')).toBeTruthy();
expect(tree.exists('apps/my-app/app/global.styl')).toBeTruthy();
const indexContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8');
expect(indexContent).toContain(
`import styles from './index.module.styl'`
);
const indexContent = tree.read('apps/my-app/app/page.tsx', 'utf-8');
expect(indexContent).toContain(`import styles from './page.module.styl'`);
});
});
@ -143,12 +148,12 @@ describe('app', () => {
});
expect(
tree.exists('apps/my-app/pages/index.module.styled-components')
tree.exists('apps/my-app/app/page.module.styled-components')
).toBeFalsy();
expect(tree.exists('apps/my-app/pages/styles.css')).toBeTruthy();
expect(tree.exists('apps/my-app/app/global.css')).toBeTruthy();
const indexContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8');
expect(indexContent).not.toContain(`import styles from './index.module`);
const indexContent = tree.read('apps/my-app/app/page.tsx', 'utf-8');
expect(indexContent).not.toContain(`import styles from './page.module`);
expect(indexContent).toContain(`import styled from 'styled-components'`);
});
});
@ -161,12 +166,12 @@ describe('app', () => {
});
expect(
tree.exists('apps/my-app/pages/index.module.styled-components')
tree.exists('apps/my-app/app/page.module.styled-components')
).toBeFalsy();
expect(tree.exists('apps/my-app/pages/styles.css')).toBeTruthy();
expect(tree.exists('apps/my-app/app/global.css')).toBeTruthy();
const indexContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8');
expect(indexContent).not.toContain(`import styles from './index.module`);
const indexContent = tree.read('apps/my-app/app/page.tsx', 'utf-8');
expect(indexContent).not.toContain(`import styles from './page.module`);
expect(indexContent).toContain(`import styled from '@emotion/styled'`);
});
@ -191,15 +196,13 @@ describe('app', () => {
style: 'styled-jsx',
});
const indexContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8');
const indexContent = tree.read('apps/my-app/app/page.tsx', 'utf-8');
expect(indexContent).toMatchSnapshot();
expect(
tree.exists('apps/my-app/pages/index.module.styled-jsx')
).toBeFalsy();
expect(tree.exists('apps/my-app/pages/styles.css')).toBeTruthy();
expect(tree.exists('apps/my-app/app/page.module.styled-jsx')).toBeFalsy();
expect(tree.exists('apps/my-app/app/global.css')).toBeTruthy();
expect(indexContent).not.toContain(`import styles from './index.module`);
expect(indexContent).not.toContain(`import styles from './page.module`);
expect(indexContent).not.toContain(
`import styled from 'styled-components'`
);
@ -311,7 +314,7 @@ describe('app', () => {
style: 'css',
});
const appContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8');
const appContent = tree.read('apps/my-app/app/page.tsx', 'utf-8');
expect(appContent).not.toMatch(/extends Component/);
});
@ -419,7 +422,7 @@ describe('app', () => {
js: true,
});
expect(tree.exists('apps/my-app/pages/index.js')).toBeTruthy();
expect(tree.exists('apps/my-app/app/page.js')).toBeTruthy();
expect(tree.exists('apps/my-app/specs/index.spec.js')).toBeTruthy();
expect(tree.exists('apps/my-app/index.d.js')).toBeFalsy();
expect(tree.exists('apps/my-app/index.d.ts')).toBeFalsy();
@ -450,8 +453,17 @@ describe('app', () => {
appDir: true,
});
expect(tree.exists('apps/testApp/pages/styles.css')).toBeFalsy();
const tsConfig = readJson(tree, 'apps/test-app/tsconfig.json');
expect(tsConfig.include).toEqual([
'**/*.ts',
'**/*.tsx',
'**/*.js',
'**/*.jsx',
'../../apps/test-app/.next/types/**/*.ts',
'../../dist/apps/test-app/.next/types/**/*.ts',
'next-env.d.ts',
]);
expect(tree.exists('apps/test-app/pages/styles.css')).toBeFalsy();
expect(tree.exists('apps/test-app/app/global.css')).toBeTruthy();
expect(tree.exists('apps/test-app/app/page.tsx')).toBeTruthy();
expect(tree.exists('apps/test-app/app/layout.tsx')).toBeTruthy();
@ -459,5 +471,25 @@ describe('app', () => {
expect(tree.exists('apps/test-app/app/page.module.css')).toBeTruthy();
expect(tree.exists('apps/test-app/public/favicon.ico')).toBeTruthy();
});
it('should add layout types correctly for standalone apps', async () => {
await applicationGenerator(tree, {
name: 'testApp',
style: 'css',
appDir: true,
rootProject: true,
});
const tsConfig = readJson(tree, 'tsconfig.json');
expect(tsConfig.include).toEqual([
'**/*.ts',
'**/*.tsx',
'**/*.js',
'**/*.jsx',
'.next/types/**/*.ts',
'dist/test-app/.next/types/**/*.ts',
'next-env.d.ts',
]);
});
});
});

View File

@ -1,8 +1,7 @@
import Head from 'next/head';
import './global.<%= stylesExt %>';
export const metadata = {
title: 'Nx Next App',
title: 'Welcome to <%= name %>',
description: 'Generated by create-nx-workspace',
}
@ -13,9 +12,6 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<Head>
<title>Welcome to <%= name %>!</title>
</Head>
<body>{children}</body>
</html>
)

View File

@ -17,11 +17,6 @@ const nextConfig = {
// See: https://github.com/gregberge/svgr
svgr: false,
},
<% if(appDir) { %>
experimental: {
appDir: true
},
<% } %>
};
const plugins = [
@ -43,11 +38,6 @@ const nextConfig = {
// See: https://github.com/gregberge/svgr
svgr: false,
},
<% if(appDir) { %>
experimental: {
appDir: true
},
<% } %>
};
const plugins = [
@ -72,11 +62,6 @@ const nextConfig = {
// See: https://github.com/gregberge/svgr
svgr: false,
},
<% if(appDir) { %>
experimental: {
appDir: true
},
<% } %>
};
const plugins = [
@ -96,11 +81,6 @@ const nextConfig = {
// See: https://github.com/gregberge/svgr
svgr: false,
},
<% if(appDir) { %>
experimental: {
appDir: true
},
<% } %>
};
const plugins = [

View File

@ -14,6 +14,16 @@
"incremental": true,
"plugins": [{ "name": "next" }]
},
"include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "next-env.d.ts"],
"include": [
"**/*.ts",
"**/*.tsx",
"**/*.js",
"**/*.jsx",
<% if (appDir) { %>
"<%= layoutTypeSrcPath %>",
"<%= layoutTypeDistPath %>",
<% } %>
"next-env.d.ts"
],
"exclude": ["node_modules", "jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}

View File

@ -1,7 +1,6 @@
import { NormalizedSchema } from './normalize-options';
import {
addProjectConfiguration,
joinPathFragments,
ProjectConfiguration,
Tree,
} from '@nx/devkit';
@ -9,18 +8,13 @@ import {
export function addProject(host: Tree, options: NormalizedSchema) {
const targets: Record<string, any> = {};
const outputPath = joinPathFragments(
'dist',
options.appProjectRoot,
...(options.rootProject ? [options.name] : [])
);
targets.build = {
executor: '@nx/next:build',
outputs: ['{options.outputPath}'],
defaultConfiguration: 'production',
options: {
root: options.appProjectRoot,
outputPath: outputPath,
outputPath: options.outputPath,
},
configurations: {
development: {

View File

@ -3,6 +3,7 @@ import {
generateFiles,
joinPathFragments,
names,
offsetFromRoot as _offsetFromRoot,
readJson,
toJS,
Tree,
@ -17,11 +18,25 @@ import {
} from './create-application-files.helpers';
export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
const offsetFromRoot = _offsetFromRoot(options.appProjectRoot);
const layoutTypeSrcPath = joinPathFragments(
offsetFromRoot,
options.appProjectRoot,
'.next/types/**/*.ts'
);
const layoutTypeDistPath = joinPathFragments(
offsetFromRoot,
options.outputPath,
'.next/types/**/*.ts'
);
const templateVariables = {
...names(options.name),
...options,
dot: '.',
tmpl: '',
offsetFromRoot,
layoutTypeSrcPath,
layoutTypeDistPath,
rootTsConfigPath: getRelativePathToRootTsConfig(
host,
options.appProjectRoot
@ -29,6 +44,7 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
appContent: createAppJsx(options.name),
styleContent: createStyleRules(),
pageStyleContent: `.page {}`,
stylesExt:
options.style === 'less' || options.style === 'styl'
? options.style

View File

@ -13,6 +13,7 @@ import { Schema } from '../schema';
export interface NormalizedSchema extends Schema {
projectName: string;
appProjectRoot: string;
outputPath: string;
e2eProjectName: string;
e2eProjectRoot: string;
parsedTags: string[];
@ -28,6 +29,7 @@ export function normalizeOptions(
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
options.directory
);
const name = names(options.name).fileName;
const appDirectory = projectDirectory
? `${names(projectDirectory).fileName}/${names(options.name).fileName}`
@ -46,13 +48,19 @@ export function normalizeOptions(
? '.'
: joinPathFragments(appsDir, `${appDirectory}-e2e`);
const outputPath = joinPathFragments(
'dist',
appProjectRoot,
...(options.rootProject ? [name] : [])
);
const parsedTags = options.tags
? options.tags.split(',').map((s) => s.trim())
: [];
const fileName = 'index';
const appDir = options.appDir ?? false;
const appDir = options.appDir ?? true;
const styledModule = /^(css|scss|less|styl)$/.test(options.style)
? null
@ -63,17 +71,18 @@ export function normalizeOptions(
return {
...options,
appDir,
name: names(options.name).fileName,
projectName: appProjectName,
linter: options.linter || Linter.EsLint,
unitTestRunner: options.unitTestRunner || 'jest',
e2eTestRunner: options.e2eTestRunner || 'cypress',
style: options.style || 'css',
appProjectRoot,
e2eProjectRoot,
e2eProjectName,
parsedTags,
e2eProjectRoot,
e2eTestRunner: options.e2eTestRunner || 'cypress',
fileName,
linter: options.linter || Linter.EsLint,
name,
outputPath,
parsedTags,
projectName: appProjectName,
style: options.style || 'css',
styledModule,
unitTestRunner: options.unitTestRunner || 'jest',
};
}

View File

@ -4,7 +4,7 @@ import { NormalizedSchema } from './normalize-options';
export function showPossibleWarnings(tree: Tree, options: NormalizedSchema) {
if (options.style === '@emotion/styled' && options.appDir) {
logger.warn(
`Emotion may not work with the experimental appDir layout. See: https://beta.nextjs.org/docs/styling/css-in-js`
`Emotion may not work with the App Router. See: https://beta.nextjs.org/docs/styling/css-in-js`
);
}
}

View File

@ -121,9 +121,9 @@
},
"appDir": {
"type": "boolean",
"default": false,
"description": "Enable experimental app directory for the project",
"x-prompt": "Do you want to use experimental app/ in this project?"
"default": true,
"description": "Enable the App Router for this project.",
"x-prompt": "Would you like to use the App Router (recommended)?"
},
"rootProject": {
"description": "Create an application at the root of the workspace.",

View File

@ -1,10 +1,10 @@
export const nxVersion = require('../../package.json').version;
export const nextVersion = '13.3.0';
export const eslintConfigNextVersion = '13.3.0';
export const sassVersion = '1.61.0';
export const nextVersion = '13.4.1';
export const eslintConfigNextVersion = '13.4.1';
export const sassVersion = '1.62.1';
export const lessLoader = '11.1.0';
export const stylusLoader = '7.1.0';
export const emotionServerVersion = '11.10.0';
export const emotionServerVersion = '11.11.0';
export const babelPluginStyledComponentsVersion = '1.10.7';
export const tsLibVersion = '^2.3.0';

View File

@ -73,9 +73,9 @@
"enum": ["express", "koa", "fastify", "nest", "none"]
},
"nextAppDir": {
"description": "Enable experimental app directory for the project",
"description": "Enable the App Router for this project.",
"type": "boolean",
"default": false
"default": true
},
"e2eTestRunner": {
"description": "The tool to use for running e2e tests.",

View File

@ -48,7 +48,7 @@ describe('preset', () => {
style: 'css',
linter: 'eslint',
});
expect(tree.exists('/apps/proj/pages/index.tsx')).toBe(true);
expect(tree.exists('/apps/proj/app/page.tsx')).toBe(true);
});
it(`should create files (preset = ${Preset.Express})`, async () => {

View File

@ -85,9 +85,9 @@
"default": false
},
"nextAppDir": {
"description": "Enable experimental app/ for the project",
"description": "Enable the App Router for this project.",
"type": "boolean",
"default": false
"default": true
},
"e2eTestRunner": {
"description": "The tool to use for running e2e tests.",