feat(react): add tailwind as style prompt option for app gen (#21784)
This commit is contained in:
parent
343c0f6690
commit
3b384c78ac
@ -59,6 +59,10 @@
|
|||||||
"value": "less",
|
"value": "less",
|
||||||
"label": "LESS [ https://lesscss.org ]"
|
"label": "LESS [ https://lesscss.org ]"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "tailwind",
|
||||||
|
"label": "tailwind [ https://tailwindcss.com/ ]"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "styled-components",
|
"value": "styled-components",
|
||||||
"label": "styled-components [ https://styled-components.com ]"
|
"label": "styled-components [ https://styled-components.com ]"
|
||||||
|
|||||||
@ -46,6 +46,10 @@
|
|||||||
"value": "less",
|
"value": "less",
|
||||||
"label": "LESS [ https://lesscss.org ]"
|
"label": "LESS [ https://lesscss.org ]"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "tailwind",
|
||||||
|
"label": "tailwind [ https://tailwindcss.com/ ]"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "styled-components",
|
"value": "styled-components",
|
||||||
"label": "styled-components [ https://styled-components.com ]"
|
"label": "styled-components [ https://styled-components.com ]"
|
||||||
|
|||||||
@ -52,6 +52,10 @@
|
|||||||
"value": "less",
|
"value": "less",
|
||||||
"label": "LESS [ https://lesscss.org ]"
|
"label": "LESS [ https://lesscss.org ]"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "tailwind",
|
||||||
|
"label": "tailwind [ https://tailwindcss.com/ ]"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "styled-components",
|
"value": "styled-components",
|
||||||
"label": "styled-components [ https://styled-components.com ]"
|
"label": "styled-components [ https://styled-components.com ]"
|
||||||
|
|||||||
@ -124,7 +124,6 @@ describe('React Applications', () => {
|
|||||||
});
|
});
|
||||||
}, 500000);
|
}, 500000);
|
||||||
|
|
||||||
// TODO(crystal, @jaysoo): Investigate why this is failing.
|
|
||||||
it('should be able to use Vite to build and test apps', async () => {
|
it('should be able to use Vite to build and test apps', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
const libName = uniq('lib');
|
const libName = uniq('lib');
|
||||||
@ -307,6 +306,48 @@ describe('React Applications', () => {
|
|||||||
expect(e2eResults).toContain('All specs passed!');
|
expect(e2eResults).toContain('All specs passed!');
|
||||||
}
|
}
|
||||||
}, 250_000);
|
}, 250_000);
|
||||||
|
|
||||||
|
it('should support tailwind', async () => {
|
||||||
|
const appName = uniq('app');
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/react:app ${appName} --style=tailwind --bundler=vite --no-interactive --skipFormat`
|
||||||
|
);
|
||||||
|
|
||||||
|
// update app to use styled-jsx
|
||||||
|
updateFile(
|
||||||
|
`apps/${appName}/src/app/app.tsx`,
|
||||||
|
`
|
||||||
|
import NxWelcome from './nx-welcome';
|
||||||
|
|
||||||
|
export function App() {
|
||||||
|
return (
|
||||||
|
<div className="w-20 h-20">
|
||||||
|
<NxWelcome title="${appName}" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(`build ${appName}`);
|
||||||
|
const outputAssetFiles = listFiles(`dist/apps/${appName}/assets`);
|
||||||
|
const styleFile = outputAssetFiles.find((filename) =>
|
||||||
|
filename.endsWith('.css')
|
||||||
|
);
|
||||||
|
if (!styleFile) {
|
||||||
|
throw new Error('Could not find bundled css file');
|
||||||
|
}
|
||||||
|
const styleFileContents = readFile(
|
||||||
|
`dist/apps/${appName}/assets/${styleFile}`
|
||||||
|
);
|
||||||
|
const isStyleFileUsingTWClasses =
|
||||||
|
styleFileContents.includes('w-20') &&
|
||||||
|
styleFileContents.includes('h-20');
|
||||||
|
expect(isStyleFileUsingTWClasses).toBeTruthy();
|
||||||
|
}, 250_000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('--format', () => {
|
describe('--format', () => {
|
||||||
|
|||||||
@ -592,6 +592,10 @@ async function determineReactOptions(
|
|||||||
name: 'less',
|
name: 'less',
|
||||||
message: 'LESS [ https://lesscss.org ]',
|
message: 'LESS [ https://lesscss.org ]',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'tailwind',
|
||||||
|
message: 'tailwind [ https://tailwindcss.com ]',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'styled-components',
|
name: 'styled-components',
|
||||||
message:
|
message:
|
||||||
|
|||||||
@ -341,6 +341,21 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('--style tailwind', () => {
|
||||||
|
it('should generate tailwind setup', async () => {
|
||||||
|
await applicationGenerator(appTree, { ...schema, style: 'tailwind' });
|
||||||
|
expect(appTree.exists('my-app/tailwind.config.js')).toEqual(true);
|
||||||
|
expect(appTree.read('my-app/src/styles.css', 'utf-8'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
"@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should setup jest with tsx support', async () => {
|
it('should setup jest with tsx support', async () => {
|
||||||
await applicationGenerator(appTree, { ...schema, name: 'my-app' });
|
await applicationGenerator(appTree, { ...schema, name: 'my-app' });
|
||||||
|
|
||||||
|
|||||||
@ -40,6 +40,7 @@ import {
|
|||||||
} from '@nx/eslint/src/generators/utils/eslint-file';
|
} from '@nx/eslint/src/generators/utils/eslint-file';
|
||||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
|
import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind';
|
||||||
|
|
||||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
@ -133,6 +134,13 @@ export async function applicationGeneratorInternal(
|
|||||||
createApplicationFiles(host, options);
|
createApplicationFiles(host, options);
|
||||||
addProject(host, options);
|
addProject(host, options);
|
||||||
|
|
||||||
|
if (options.style === 'tailwind') {
|
||||||
|
const twTask = await setupTailwindGenerator(host, {
|
||||||
|
project: options.projectName,
|
||||||
|
});
|
||||||
|
tasks.push(twTask);
|
||||||
|
}
|
||||||
|
|
||||||
if (options.bundler === 'vite') {
|
if (options.bundler === 'vite') {
|
||||||
const { createOrEditViteConfig, viteConfigurationGenerator } =
|
const { createOrEditViteConfig, viteConfigurationGenerator } =
|
||||||
ensurePackage<typeof import('@nx/vite')>('@nx/vite', nxVersion);
|
ensurePackage<typeof import('@nx/vite')>('@nx/vite', nxVersion);
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<% if (!styledModule && style !== 'none') { %><link rel="stylesheet" href="/src/styles.<%= style %>" /><% } %>
|
<% if (!styledModule && style !== 'none') { %><link rel="stylesheet" href="/src/styles.<%= style === 'tailwind' ? 'css' : style %>" /><% } %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
<% if (classComponent) { %>
|
||||||
|
import { Component } from 'react';
|
||||||
|
<% } if (!minimal) { %>
|
||||||
|
import NxWelcome from "./nx-welcome";
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (classComponent) { %>
|
||||||
|
export class App extends Component {
|
||||||
|
render() {
|
||||||
|
<% } else { %>
|
||||||
|
export function App() {
|
||||||
|
<% } %>
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<% if (!minimal) { %>
|
||||||
|
<NxWelcome title="<%= projectName %>"/>
|
||||||
|
<% } else { %>
|
||||||
|
<h1>
|
||||||
|
<span> Hello there, </span>
|
||||||
|
Welcome <%= projectName %> 👋
|
||||||
|
</h1>
|
||||||
|
<% } %>
|
||||||
|
</div>);
|
||||||
|
<% if (classComponent) { %>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<% } else { %>
|
||||||
|
}
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
|
||||||
|
<% if (inSourceTests === true) { %> <%- inSourceVitestTests %> <% } %>
|
||||||
@ -0,0 +1 @@
|
|||||||
|
/* You can add global styles to this file, and also import other style files */
|
||||||
@ -24,6 +24,8 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
styleSolutionSpecificAppFiles = '../files/style-styled-module';
|
styleSolutionSpecificAppFiles = '../files/style-styled-module';
|
||||||
} else if (options.style === 'styled-jsx') {
|
} else if (options.style === 'styled-jsx') {
|
||||||
styleSolutionSpecificAppFiles = '../files/style-styled-jsx';
|
styleSolutionSpecificAppFiles = '../files/style-styled-jsx';
|
||||||
|
} else if (options.style === 'tailwind') {
|
||||||
|
styleSolutionSpecificAppFiles = '../files/style-tailwind';
|
||||||
} else if (options.style === 'none') {
|
} else if (options.style === 'none') {
|
||||||
styleSolutionSpecificAppFiles = '../files/style-none';
|
styleSolutionSpecificAppFiles = '../files/style-none';
|
||||||
} else if (options.globalCss) {
|
} else if (options.globalCss) {
|
||||||
@ -185,6 +187,10 @@ function createNxWebpackPluginOptions(
|
|||||||
styles:
|
styles:
|
||||||
options.styledModule || !options.hasStyles
|
options.styledModule || !options.hasStyles
|
||||||
? []
|
? []
|
||||||
: [`./src/styles.${options.style}`],
|
: [
|
||||||
|
`./src/styles.${
|
||||||
|
options.style !== 'tailwind' ? options.style : 'css'
|
||||||
|
}`,
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,7 +46,7 @@ export async function normalizeOptions<T extends Schema = Schema>(
|
|||||||
|
|
||||||
const fileName = options.pascalCaseFiles ? 'App' : 'app';
|
const fileName = options.pascalCaseFiles ? 'App' : 'app';
|
||||||
|
|
||||||
const styledModule = /^(css|scss|less|none)$/.test(options.style)
|
const styledModule = /^(css|scss|less|tailwind|none)$/.test(options.style)
|
||||||
? null
|
? null
|
||||||
: options.style;
|
: options.style;
|
||||||
|
|
||||||
|
|||||||
@ -62,6 +62,10 @@
|
|||||||
"value": "less",
|
"value": "less",
|
||||||
"label": "LESS [ https://lesscss.org ]"
|
"label": "LESS [ https://lesscss.org ]"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "tailwind",
|
||||||
|
"label": "tailwind [ https://tailwindcss.com/ ]"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "styled-components",
|
"value": "styled-components",
|
||||||
"label": "styled-components [ https://styled-components.com ]"
|
"label": "styled-components [ https://styled-components.com ]"
|
||||||
|
|||||||
@ -49,6 +49,10 @@
|
|||||||
"value": "less",
|
"value": "less",
|
||||||
"label": "LESS [ https://lesscss.org ]"
|
"label": "LESS [ https://lesscss.org ]"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "tailwind",
|
||||||
|
"label": "tailwind [ https://tailwindcss.com/ ]"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "styled-components",
|
"value": "styled-components",
|
||||||
"label": "styled-components [ https://styled-components.com ]"
|
"label": "styled-components [ https://styled-components.com ]"
|
||||||
|
|||||||
@ -55,6 +55,10 @@
|
|||||||
"value": "less",
|
"value": "less",
|
||||||
"label": "LESS [ https://lesscss.org ]"
|
"label": "LESS [ https://lesscss.org ]"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "tailwind",
|
||||||
|
"label": "tailwind [ https://tailwindcss.com/ ]"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "styled-components",
|
"value": "styled-components",
|
||||||
"label": "styled-components [ https://styled-components.com ]"
|
"label": "styled-components [ https://styled-components.com ]"
|
||||||
|
|||||||
@ -2,6 +2,7 @@ const VALID_STYLES = [
|
|||||||
'css',
|
'css',
|
||||||
'scss',
|
'scss',
|
||||||
'less',
|
'less',
|
||||||
|
'tailwind',
|
||||||
'styled-components',
|
'styled-components',
|
||||||
'@emotion/styled',
|
'@emotion/styled',
|
||||||
'styled-jsx',
|
'styled-jsx',
|
||||||
|
|||||||
1
packages/react/typings/style.d.ts
vendored
1
packages/react/typings/style.d.ts
vendored
@ -2,6 +2,7 @@ export type SupportedStyles =
|
|||||||
| 'css'
|
| 'css'
|
||||||
| 'scss'
|
| 'scss'
|
||||||
| 'less'
|
| 'less'
|
||||||
|
| 'tailwind'
|
||||||
| 'styled-components'
|
| 'styled-components'
|
||||||
| '@emotion/styled'
|
| '@emotion/styled'
|
||||||
| 'styled-jsx'
|
| 'styled-jsx'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user