diff --git a/docs/generated/packages/react/generators/application.json b/docs/generated/packages/react/generators/application.json
index b1fcfb1f119ee..c463a55f583f3 100644
--- a/docs/generated/packages/react/generators/application.json
+++ b/docs/generated/packages/react/generators/application.json
@@ -59,6 +59,10 @@
"value": "less",
"label": "LESS [ https://lesscss.org ]"
},
+ {
+ "value": "tailwind",
+ "label": "tailwind [ https://tailwindcss.com/ ]"
+ },
{
"value": "styled-components",
"label": "styled-components [ https://styled-components.com ]"
diff --git a/docs/generated/packages/react/generators/host.json b/docs/generated/packages/react/generators/host.json
index 8d72ba1722b0f..25b635247c422 100644
--- a/docs/generated/packages/react/generators/host.json
+++ b/docs/generated/packages/react/generators/host.json
@@ -46,6 +46,10 @@
"value": "less",
"label": "LESS [ https://lesscss.org ]"
},
+ {
+ "value": "tailwind",
+ "label": "tailwind [ https://tailwindcss.com/ ]"
+ },
{
"value": "styled-components",
"label": "styled-components [ https://styled-components.com ]"
diff --git a/docs/generated/packages/react/generators/remote.json b/docs/generated/packages/react/generators/remote.json
index b6d4cded8e663..eeba3d1dafc95 100644
--- a/docs/generated/packages/react/generators/remote.json
+++ b/docs/generated/packages/react/generators/remote.json
@@ -52,6 +52,10 @@
"value": "less",
"label": "LESS [ https://lesscss.org ]"
},
+ {
+ "value": "tailwind",
+ "label": "tailwind [ https://tailwindcss.com/ ]"
+ },
{
"value": "styled-components",
"label": "styled-components [ https://styled-components.com ]"
diff --git a/e2e/react-core/src/react.test.ts b/e2e/react-core/src/react.test.ts
index 5e463af4b72c1..a8f5ca926711a 100644
--- a/e2e/react-core/src/react.test.ts
+++ b/e2e/react-core/src/react.test.ts
@@ -124,7 +124,6 @@ describe('React Applications', () => {
});
}, 500000);
- // TODO(crystal, @jaysoo): Investigate why this is failing.
it('should be able to use Vite to build and test apps', async () => {
const appName = uniq('app');
const libName = uniq('lib');
@@ -307,6 +306,48 @@ describe('React Applications', () => {
expect(e2eResults).toContain('All specs passed!');
}
}, 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 (
+
+
+
+ );
+ }
+
+ 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', () => {
diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts
index 1906444a6624b..63ea240fb2a47 100644
--- a/packages/create-nx-workspace/bin/create-nx-workspace.ts
+++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts
@@ -592,6 +592,10 @@ async function determineReactOptions(
name: 'less',
message: 'LESS [ https://lesscss.org ]',
},
+ {
+ name: 'tailwind',
+ message: 'tailwind [ https://tailwindcss.com ]',
+ },
{
name: 'styled-components',
message:
diff --git a/packages/react/src/generators/application/application.spec.ts b/packages/react/src/generators/application/application.spec.ts
index 92f598e1a70b6..98c06f2b9205a 100644
--- a/packages/react/src/generators/application/application.spec.ts
+++ b/packages/react/src/generators/application/application.spec.ts
@@ -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 () => {
await applicationGenerator(appTree, { ...schema, name: 'my-app' });
diff --git a/packages/react/src/generators/application/application.ts b/packages/react/src/generators/application/application.ts
index 4b8892870ef3e..c7d8e6e13ec6e 100644
--- a/packages/react/src/generators/application/application.ts
+++ b/packages/react/src/generators/application/application.ts
@@ -40,6 +40,7 @@ import {
} from '@nx/eslint/src/generators/utils/eslint-file';
import { initGenerator as jsInitGenerator } from '@nx/js';
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) {
const tasks: GeneratorCallback[] = [];
@@ -133,6 +134,13 @@ export async function applicationGeneratorInternal(
createApplicationFiles(host, options);
addProject(host, options);
+ if (options.style === 'tailwind') {
+ const twTask = await setupTailwindGenerator(host, {
+ project: options.projectName,
+ });
+ tasks.push(twTask);
+ }
+
if (options.bundler === 'vite') {
const { createOrEditViteConfig, viteConfigurationGenerator } =
ensurePackage('@nx/vite', nxVersion);
diff --git a/packages/react/src/generators/application/files/base-vite/index.html__tmpl__ b/packages/react/src/generators/application/files/base-vite/index.html__tmpl__
index 0905c1c939b02..6af82e6a0079c 100644
--- a/packages/react/src/generators/application/files/base-vite/index.html__tmpl__
+++ b/packages/react/src/generators/application/files/base-vite/index.html__tmpl__
@@ -7,7 +7,7 @@
- <% if (!styledModule && style !== 'none') { %><% } %>
+ <% if (!styledModule && style !== 'none') { %><% } %>
diff --git a/packages/react/src/generators/application/files/style-tailwind/src/app/__fileName__.tsx__tmpl__ b/packages/react/src/generators/application/files/style-tailwind/src/app/__fileName__.tsx__tmpl__
new file mode 100644
index 0000000000000..671b49bfca17e
--- /dev/null
+++ b/packages/react/src/generators/application/files/style-tailwind/src/app/__fileName__.tsx__tmpl__
@@ -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 (
+
+ <% if (!minimal) { %>
+
+ <% } else { %>
+
+ Hello there,
+ Welcome <%= projectName %> 👋
+
+ <% } %>
+ );
+<% if (classComponent) { %>
+ }
+}
+<% } else { %>
+}
+<% } %>
+
+export default App;
+
+<% if (inSourceTests === true) { %> <%- inSourceVitestTests %> <% } %>
diff --git a/packages/react/src/generators/application/files/style-tailwind/src/styles.css b/packages/react/src/generators/application/files/style-tailwind/src/styles.css
new file mode 100644
index 0000000000000..90d4ee0072ce3
--- /dev/null
+++ b/packages/react/src/generators/application/files/style-tailwind/src/styles.css
@@ -0,0 +1 @@
+/* You can add global styles to this file, and also import other style files */
diff --git a/packages/react/src/generators/application/lib/create-application-files.ts b/packages/react/src/generators/application/lib/create-application-files.ts
index 91ddf811212f9..972bb3fe7e4d1 100644
--- a/packages/react/src/generators/application/lib/create-application-files.ts
+++ b/packages/react/src/generators/application/lib/create-application-files.ts
@@ -24,6 +24,8 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
styleSolutionSpecificAppFiles = '../files/style-styled-module';
} else if (options.style === 'styled-jsx') {
styleSolutionSpecificAppFiles = '../files/style-styled-jsx';
+ } else if (options.style === 'tailwind') {
+ styleSolutionSpecificAppFiles = '../files/style-tailwind';
} else if (options.style === 'none') {
styleSolutionSpecificAppFiles = '../files/style-none';
} else if (options.globalCss) {
@@ -185,6 +187,10 @@ function createNxWebpackPluginOptions(
styles:
options.styledModule || !options.hasStyles
? []
- : [`./src/styles.${options.style}`],
+ : [
+ `./src/styles.${
+ options.style !== 'tailwind' ? options.style : 'css'
+ }`,
+ ],
};
}
diff --git a/packages/react/src/generators/application/lib/normalize-options.ts b/packages/react/src/generators/application/lib/normalize-options.ts
index a159d909b4c27..6596a57d931d7 100644
--- a/packages/react/src/generators/application/lib/normalize-options.ts
+++ b/packages/react/src/generators/application/lib/normalize-options.ts
@@ -46,7 +46,7 @@ export async function normalizeOptions(
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
: options.style;
diff --git a/packages/react/src/generators/application/schema.json b/packages/react/src/generators/application/schema.json
index 29c9dde97d74c..7152a9197ab58 100644
--- a/packages/react/src/generators/application/schema.json
+++ b/packages/react/src/generators/application/schema.json
@@ -62,6 +62,10 @@
"value": "less",
"label": "LESS [ https://lesscss.org ]"
},
+ {
+ "value": "tailwind",
+ "label": "tailwind [ https://tailwindcss.com/ ]"
+ },
{
"value": "styled-components",
"label": "styled-components [ https://styled-components.com ]"
diff --git a/packages/react/src/generators/host/schema.json b/packages/react/src/generators/host/schema.json
index 4f5e84a1db9d8..07765493c77a3 100644
--- a/packages/react/src/generators/host/schema.json
+++ b/packages/react/src/generators/host/schema.json
@@ -49,6 +49,10 @@
"value": "less",
"label": "LESS [ https://lesscss.org ]"
},
+ {
+ "value": "tailwind",
+ "label": "tailwind [ https://tailwindcss.com/ ]"
+ },
{
"value": "styled-components",
"label": "styled-components [ https://styled-components.com ]"
diff --git a/packages/react/src/generators/remote/schema.json b/packages/react/src/generators/remote/schema.json
index 5e56b6bb2feb4..0252f9ed355c2 100644
--- a/packages/react/src/generators/remote/schema.json
+++ b/packages/react/src/generators/remote/schema.json
@@ -55,6 +55,10 @@
"value": "less",
"label": "LESS [ https://lesscss.org ]"
},
+ {
+ "value": "tailwind",
+ "label": "tailwind [ https://tailwindcss.com/ ]"
+ },
{
"value": "styled-components",
"label": "styled-components [ https://styled-components.com ]"
diff --git a/packages/react/src/utils/assertion.ts b/packages/react/src/utils/assertion.ts
index fdeb9b0f9ce5b..584c23d83ffb5 100644
--- a/packages/react/src/utils/assertion.ts
+++ b/packages/react/src/utils/assertion.ts
@@ -2,6 +2,7 @@ const VALID_STYLES = [
'css',
'scss',
'less',
+ 'tailwind',
'styled-components',
'@emotion/styled',
'styled-jsx',
diff --git a/packages/react/typings/style.d.ts b/packages/react/typings/style.d.ts
index 2197a57542755..2ee2659578aa5 100644
--- a/packages/react/typings/style.d.ts
+++ b/packages/react/typings/style.d.ts
@@ -2,6 +2,7 @@ export type SupportedStyles =
| 'css'
| 'scss'
| 'less'
+ | 'tailwind'
| 'styled-components'
| '@emotion/styled'
| 'styled-jsx'