diff --git a/docs/generated/packages/next/generators/application.json b/docs/generated/packages/next/generators/application.json
index da58d772463b2..5ad1db11b4e52 100644
--- a/docs/generated/packages/next/generators/application.json
+++ b/docs/generated/packages/next/generators/application.json
@@ -124,6 +124,12 @@
"default": false,
"description": "Do not add dependencies to `package.json`.",
"x-priority": "internal"
+ },
+ "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?"
}
},
"required": [],
diff --git a/packages/next/src/generators/application/application.spec.ts b/packages/next/src/generators/application/application.spec.ts
index 12a2885d1b46f..dad0f6e8cd13e 100644
--- a/packages/next/src/generators/application/application.spec.ts
+++ b/packages/next/src/generators/application/application.spec.ts
@@ -1,7 +1,6 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import {
getProjects,
- NxJsonConfiguration,
readJson,
readProjectConfiguration,
Tree,
@@ -418,4 +417,23 @@ describe('app', () => {
expect(tree.exists('apps/my-app/public/.gitkeep')).toBe(true);
});
+
+ describe('--appDir', () => {
+ it('should generate app directory instead of pages', async () => {
+ await applicationGenerator(tree, {
+ name: 'testApp',
+ style: 'css',
+ appDir: true,
+ });
+
+ expect(tree.exists('apps/testApp/pages/styles.css')).toBeFalsy();
+
+ expect(tree.exists('apps/testApp/app/global.css'));
+ expect(tree.exists('apps/testApp/app/page.tsx'));
+ expect(tree.exists('apps/testApp/app/layout.tsx'));
+ expect(tree.exists('apps/testApp/app/api/hello/route.ts'));
+ expect(tree.exists('apps/testApp/app/page.module.css'));
+ expect(tree.exists('apps/testApp/app/favicon.ico'));
+ });
+ });
});
diff --git a/packages/next/src/generators/application/files/app/api/hello/route.ts__tmpl__ b/packages/next/src/generators/application/files/app/api/hello/route.ts__tmpl__
new file mode 100644
index 0000000000000..e5655e266b078
--- /dev/null
+++ b/packages/next/src/generators/application/files/app/api/hello/route.ts__tmpl__
@@ -0,0 +1,4 @@
+export async function GET(request: Request) {
+ return new Response('Hello, from API!')
+ }
+
\ No newline at end of file
diff --git a/packages/next/src/generators/application/files/app/favicon.ico b/packages/next/src/generators/application/files/app/favicon.ico
new file mode 100644
index 0000000000000..317ebcb2336e0
Binary files /dev/null and b/packages/next/src/generators/application/files/app/favicon.ico differ
diff --git a/packages/next/src/generators/application/files/app/global.__stylesExt____tmpl__ b/packages/next/src/generators/application/files/app/global.__stylesExt____tmpl__
new file mode 100644
index 0000000000000..c3f24863cb434
--- /dev/null
+++ b/packages/next/src/generators/application/files/app/global.__stylesExt____tmpl__
@@ -0,0 +1 @@
+<%- styleContent %>
diff --git a/packages/next/src/generators/application/files/app/layout.tsx__tmpl__ b/packages/next/src/generators/application/files/app/layout.tsx__tmpl__
new file mode 100644
index 0000000000000..498a427d892ab
--- /dev/null
+++ b/packages/next/src/generators/application/files/app/layout.tsx__tmpl__
@@ -0,0 +1,22 @@
+import Head from 'next/head';
+import './global.<%= stylesExt %>';
+
+export const metadata = {
+ title: 'Nx Next App',
+ description: 'Generated by create-nx-workspace',
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+
+ Welcome to <%= name %>!
+
+ {children}
+
+ )
+}
diff --git a/packages/next/src/generators/application/files/app/page.module.__style__ b/packages/next/src/generators/application/files/app/page.module.__style__
new file mode 100644
index 0000000000000..40d88f3d797b7
--- /dev/null
+++ b/packages/next/src/generators/application/files/app/page.module.__style__
@@ -0,0 +1 @@
+<%- pageStyleContent %>
diff --git a/packages/next/src/generators/application/files/app/page.tsx__tmpl__ b/packages/next/src/generators/application/files/app/page.tsx__tmpl__
new file mode 100644
index 0000000000000..4d4e80e033070
--- /dev/null
+++ b/packages/next/src/generators/application/files/app/page.tsx__tmpl__
@@ -0,0 +1,28 @@
+<% if (styledModule && styledModule !== 'styled-jsx') {
+ var wrapper = 'StyledPage';
+%>import styled from '<%= styledModule %>';<% } else {
+ var wrapper = 'div';
+%>
+ <%- style !== 'styled-jsx' ? `import styles from './page.module.${style}';` : '' %>
+<% }
+%>
+
+<% if (styledModule && styledModule !== 'styled-jsx') { %>
+const StyledPage = styled.div`<%- pageStyleContent %>`;
+<% }%>
+
+export async function Index() {
+ /*
+ * Replace the elements below with your own.
+ *
+ * Note: The corresponding styles are in the ./<%= fileName %>.<%= style %> file.
+ */
+ return (
+ <<%= wrapper %><% if (!styledModule) {%> className={styles.page}<% } %>>
+ <%- styledModule === 'styled-jsx' ? `` : `` %>
+ <%- appContent %>
+ <%= wrapper %>>
+ );
+};
+
+export default Index;
\ No newline at end of file
diff --git a/packages/next/src/generators/application/files/.babelrc__tmpl__ b/packages/next/src/generators/application/files/common/.babelrc__tmpl__
similarity index 100%
rename from packages/next/src/generators/application/files/.babelrc__tmpl__
rename to packages/next/src/generators/application/files/common/.babelrc__tmpl__
diff --git a/packages/next/src/generators/application/files/index.d.ts__tmpl__ b/packages/next/src/generators/application/files/common/index.d.ts__tmpl__
similarity index 100%
rename from packages/next/src/generators/application/files/index.d.ts__tmpl__
rename to packages/next/src/generators/application/files/common/index.d.ts__tmpl__
diff --git a/packages/next/src/generators/application/files/next-env.d.ts__tmpl__ b/packages/next/src/generators/application/files/common/next-env.d.ts__tmpl__
similarity index 100%
rename from packages/next/src/generators/application/files/next-env.d.ts__tmpl__
rename to packages/next/src/generators/application/files/common/next-env.d.ts__tmpl__
diff --git a/packages/next/src/generators/application/files/next.config.js__tmpl__ b/packages/next/src/generators/application/files/common/next.config.js__tmpl__
similarity index 85%
rename from packages/next/src/generators/application/files/next.config.js__tmpl__
rename to packages/next/src/generators/application/files/common/next.config.js__tmpl__
index 8cef6587befb4..69c955d9d1223 100644
--- a/packages/next/src/generators/application/files/next.config.js__tmpl__
+++ b/packages/next/src/generators/application/files/common/next.config.js__tmpl__
@@ -17,6 +17,11 @@ const nextConfig = {
// See: https://github.com/gregberge/svgr
svgr: false,
},
+ <% if(appDir) { %>
+ experimental: {
+ appDir: true
+ },
+ <% } %>
};
module.exports = withLess(withNx(nextConfig));
@@ -32,6 +37,11 @@ const nextConfig = {
// See: https://github.com/gregberge/svgr
svgr: false,
},
+ <% if(appDir) { %>
+ experimental: {
+ appDir: true
+ },
+ <% } %>
};
module.exports = withStylus(withNx(nextConfig));
@@ -50,6 +60,11 @@ const nextConfig = {
// See: https://github.com/gregberge/svgr
svgr: false,
},
+ <% if(appDir) { %>
+ experimental: {
+ appDir: true
+ },
+ <% } %>
};
module.exports = withNx(nextConfig);
@@ -64,6 +79,11 @@ const nextConfig = {
// See: https://github.com/gregberge/svgr
svgr: false,
},
+ <% if(appDir) { %>
+ experimental: {
+ appDir: true
+ },
+ <% } %>
};
module.exports = withNx(nextConfig);
diff --git a/packages/next/src/generators/application/files/public/.gitkeep b/packages/next/src/generators/application/files/common/public/.gitkeep
similarity index 100%
rename from packages/next/src/generators/application/files/public/.gitkeep
rename to packages/next/src/generators/application/files/common/public/.gitkeep
diff --git a/packages/next/src/generators/application/files/specs/__fileName__.spec.tsx__tmpl__ b/packages/next/src/generators/application/files/common/specs/__fileName__.spec.tsx__tmpl__
similarity index 100%
rename from packages/next/src/generators/application/files/specs/__fileName__.spec.tsx__tmpl__
rename to packages/next/src/generators/application/files/common/specs/__fileName__.spec.tsx__tmpl__
diff --git a/packages/next/src/generators/application/files/tsconfig.json__tmpl__ b/packages/next/src/generators/application/files/common/tsconfig.json__tmpl__
similarity index 100%
rename from packages/next/src/generators/application/files/tsconfig.json__tmpl__
rename to packages/next/src/generators/application/files/common/tsconfig.json__tmpl__
diff --git a/packages/next/src/generators/application/files/pages/favicon.ico b/packages/next/src/generators/application/files/pages/favicon.ico
new file mode 100644
index 0000000000000..317ebcb2336e0
Binary files /dev/null and b/packages/next/src/generators/application/files/pages/favicon.ico differ
diff --git a/packages/next/src/generators/application/lib/create-application-files.ts b/packages/next/src/generators/application/lib/create-application-files.ts
index c4319c306da45..e1c9323ca7804 100644
--- a/packages/next/src/generators/application/lib/create-application-files.ts
+++ b/packages/next/src/generators/application/lib/create-application-files.ts
@@ -28,11 +28,27 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
generateFiles(
host,
- join(__dirname, '../files'),
+ join(__dirname, '../files/common'),
options.appProjectRoot,
templateVariables
);
+ if (options.appDir) {
+ generateFiles(
+ host,
+ join(__dirname, '../files/app'),
+ join(options.appProjectRoot, 'app'),
+ templateVariables
+ );
+ } else {
+ generateFiles(
+ host,
+ join(__dirname, '../files/pages'),
+ join(options.appProjectRoot, 'pages'),
+ templateVariables
+ );
+ }
+
if (options.unitTestRunner === 'none') {
host.delete(`${options.appProjectRoot}/specs/${options.fileName}.spec.tsx`);
}
diff --git a/packages/next/src/generators/application/lib/normalize-options.ts b/packages/next/src/generators/application/lib/normalize-options.ts
index fab1c9653bfe9..4df023ad29efe 100644
--- a/packages/next/src/generators/application/lib/normalize-options.ts
+++ b/packages/next/src/generators/application/lib/normalize-options.ts
@@ -47,6 +47,8 @@ export function normalizeOptions(
const fileName = 'index';
+ const appDir = options.appDir ?? false;
+
const styledModule = /^(css|scss|less|styl)$/.test(options.style)
? null
: options.style;
@@ -55,6 +57,7 @@ export function normalizeOptions(
return {
...options,
+ appDir,
name: names(options.name).fileName,
projectName: appProjectName,
linter: options.linter || Linter.EsLint,
diff --git a/packages/next/src/generators/application/schema.d.ts b/packages/next/src/generators/application/schema.d.ts
index dc6de0d244ea4..180a02846f7d3 100644
--- a/packages/next/src/generators/application/schema.d.ts
+++ b/packages/next/src/generators/application/schema.d.ts
@@ -17,4 +17,5 @@ export interface Schema {
swc?: boolean;
customServer?: boolean;
skipPackageJson?: boolean;
+ appDir?: boolean;
}
diff --git a/packages/next/src/generators/application/schema.json b/packages/next/src/generators/application/schema.json
index 79db0c6d1bc6c..93ac82b521bb7 100644
--- a/packages/next/src/generators/application/schema.json
+++ b/packages/next/src/generators/application/schema.json
@@ -124,6 +124,12 @@
"default": false,
"description": "Do not add dependencies to `package.json`.",
"x-priority": "internal"
+ },
+ "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?"
}
},
"required": [],