feat(nextjs): add support for experimental appDir (#16132)
This commit is contained in:
parent
a8b8ea91f2
commit
18e965d2ef
@ -124,6 +124,12 @@
|
|||||||
"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"
|
||||||
|
},
|
||||||
|
"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": [],
|
"required": [],
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
import {
|
import {
|
||||||
getProjects,
|
getProjects,
|
||||||
NxJsonConfiguration,
|
|
||||||
readJson,
|
readJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
@ -418,4 +417,23 @@ describe('app', () => {
|
|||||||
|
|
||||||
expect(tree.exists('apps/my-app/public/.gitkeep')).toBe(true);
|
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'));
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
export async function GET(request: Request) {
|
||||||
|
return new Response('Hello, from API!')
|
||||||
|
}
|
||||||
|
|
||||||
BIN
packages/next/src/generators/application/files/app/favicon.ico
Normal file
BIN
packages/next/src/generators/application/files/app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1 @@
|
|||||||
|
<%- styleContent %>
|
||||||
@ -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 (
|
||||||
|
<html lang="en">
|
||||||
|
<Head>
|
||||||
|
<title>Welcome to <%= name %>!</title>
|
||||||
|
</Head>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<%- pageStyleContent %>
|
||||||
@ -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' ? `<style jsx>{\`${pageStyleContent}\`}</style>` : `` %>
|
||||||
|
<%- appContent %>
|
||||||
|
</<%= wrapper %>>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Index;
|
||||||
@ -17,6 +17,11 @@ const nextConfig = {
|
|||||||
// See: https://github.com/gregberge/svgr
|
// See: https://github.com/gregberge/svgr
|
||||||
svgr: false,
|
svgr: false,
|
||||||
},
|
},
|
||||||
|
<% if(appDir) { %>
|
||||||
|
experimental: {
|
||||||
|
appDir: true
|
||||||
|
},
|
||||||
|
<% } %>
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withLess(withNx(nextConfig));
|
module.exports = withLess(withNx(nextConfig));
|
||||||
@ -32,6 +37,11 @@ const nextConfig = {
|
|||||||
// See: https://github.com/gregberge/svgr
|
// See: https://github.com/gregberge/svgr
|
||||||
svgr: false,
|
svgr: false,
|
||||||
},
|
},
|
||||||
|
<% if(appDir) { %>
|
||||||
|
experimental: {
|
||||||
|
appDir: true
|
||||||
|
},
|
||||||
|
<% } %>
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withStylus(withNx(nextConfig));
|
module.exports = withStylus(withNx(nextConfig));
|
||||||
@ -50,6 +60,11 @@ const nextConfig = {
|
|||||||
// See: https://github.com/gregberge/svgr
|
// See: https://github.com/gregberge/svgr
|
||||||
svgr: false,
|
svgr: false,
|
||||||
},
|
},
|
||||||
|
<% if(appDir) { %>
|
||||||
|
experimental: {
|
||||||
|
appDir: true
|
||||||
|
},
|
||||||
|
<% } %>
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withNx(nextConfig);
|
module.exports = withNx(nextConfig);
|
||||||
@ -64,6 +79,11 @@ const nextConfig = {
|
|||||||
// See: https://github.com/gregberge/svgr
|
// See: https://github.com/gregberge/svgr
|
||||||
svgr: false,
|
svgr: false,
|
||||||
},
|
},
|
||||||
|
<% if(appDir) { %>
|
||||||
|
experimental: {
|
||||||
|
appDir: true
|
||||||
|
},
|
||||||
|
<% } %>
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withNx(nextConfig);
|
module.exports = withNx(nextConfig);
|
||||||
BIN
packages/next/src/generators/application/files/pages/favicon.ico
Normal file
BIN
packages/next/src/generators/application/files/pages/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@ -28,11 +28,27 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
|
|
||||||
generateFiles(
|
generateFiles(
|
||||||
host,
|
host,
|
||||||
join(__dirname, '../files'),
|
join(__dirname, '../files/common'),
|
||||||
options.appProjectRoot,
|
options.appProjectRoot,
|
||||||
templateVariables
|
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') {
|
if (options.unitTestRunner === 'none') {
|
||||||
host.delete(`${options.appProjectRoot}/specs/${options.fileName}.spec.tsx`);
|
host.delete(`${options.appProjectRoot}/specs/${options.fileName}.spec.tsx`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,8 @@ export function normalizeOptions(
|
|||||||
|
|
||||||
const fileName = 'index';
|
const fileName = 'index';
|
||||||
|
|
||||||
|
const appDir = options.appDir ?? false;
|
||||||
|
|
||||||
const styledModule = /^(css|scss|less|styl)$/.test(options.style)
|
const styledModule = /^(css|scss|less|styl)$/.test(options.style)
|
||||||
? null
|
? null
|
||||||
: options.style;
|
: options.style;
|
||||||
@ -55,6 +57,7 @@ export function normalizeOptions(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
|
appDir,
|
||||||
name: names(options.name).fileName,
|
name: names(options.name).fileName,
|
||||||
projectName: appProjectName,
|
projectName: appProjectName,
|
||||||
linter: options.linter || Linter.EsLint,
|
linter: options.linter || Linter.EsLint,
|
||||||
|
|||||||
@ -17,4 +17,5 @@ export interface Schema {
|
|||||||
swc?: boolean;
|
swc?: boolean;
|
||||||
customServer?: boolean;
|
customServer?: boolean;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
|
appDir?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,6 +124,12 @@
|
|||||||
"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"
|
||||||
|
},
|
||||||
|
"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": [],
|
"required": [],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user