From 404faef0f7db52627aab71089e2b20b727bb61f3 Mon Sep 17 00:00:00 2001 From: SAMARTHA H V Date: Fri, 29 May 2026 12:57:04 +0530 Subject: [PATCH 1/6] feat: add --tailwind flag with Tailwind v4 support for Vite and CRA --- bin/cli.js | 4 +++ src/cleaners/cra.js | 35 +++++++++++++-------- src/creators/vite.js | 63 ++++++++++++++++++++++++++++++++------ src/generators/tailwind.js | 36 ++++++++++++++++++++++ src/index.js | 14 +++++++-- 5 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 src/generators/tailwind.js diff --git a/bin/cli.js b/bin/cli.js index c3785e8..da3ec26 100644 --- a/bin/cli.js +++ b/bin/cli.js @@ -22,6 +22,10 @@ program "--folders", "Generate recommended folder structure" ) + .option( + "--tailwind", + "Set up Tailwind CSS" + ) .parse(); const projectName = program.args[0]; diff --git a/src/cleaners/cra.js b/src/cleaners/cra.js index eb2a1c5..80f05ab 100644 --- a/src/cleaners/cra.js +++ b/src/cleaners/cra.js @@ -3,31 +3,42 @@ const { writeFile, } = require("../utils/files"); -function cleanCRA(projectPath, typescript) { +function cleanCRA(projectPath, typescript, tailwind) { const ext = typescript ? "tsx" : "js"; - writeFile( - projectPath, - `src/App.${ext}`, -`function App() { + const appContent = tailwind + ? `function App() { return ( -
-

App

+
+

App

); } export default App; ` + : `function App() { + return ( +
+

App

+
); +} + +export default App; +`; + + writeFile(projectPath, `src/App.${ext}`, appContent); + + const indexCSSImport = tailwind ? `import "./index.css";\n` : ""; writeFile( projectPath, `src/index.${ext}`, -typescript -? `import React from "react"; + typescript + ? `import React from "react"; import ReactDOM from "react-dom/client"; -import App from "./App"; +${indexCSSImport}import App from "./App"; const root = ReactDOM.createRoot( document.getElementById("root") as HTMLElement @@ -39,9 +50,9 @@ root.render( ); ` -: `import React from "react"; + : `import React from "react"; import ReactDOM from "react-dom/client"; -import App from "./App"; +${indexCSSImport}import App from "./App"; const root = ReactDOM.createRoot( document.getElementById("root") diff --git a/src/creators/vite.js b/src/creators/vite.js index 6b3c6d1..dfbe3bd 100644 --- a/src/creators/vite.js +++ b/src/creators/vite.js @@ -36,6 +36,15 @@ export default defineConfig({ }) `; +const VITE_CONFIG_JS_TAILWIND = `import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) +`; + const INDEX_HTML = (projectName) => ` @@ -86,6 +95,30 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( ) `; +const MAIN_JSX_TAILWIND = `import React from 'react' +import ReactDOM from 'react-dom/client' +import './index.css' +import App from './App' + +ReactDOM.createRoot(document.getElementById('root')).render( + + + +) +`; + +const MAIN_TSX_TAILWIND = `import React from 'react' +import ReactDOM from 'react-dom/client' +import './index.css' +import App from './App' + +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + +) +`; + const APP_JSX = `function App() { return (
@@ -97,6 +130,17 @@ const APP_JSX = `function App() { export default App `; +const APP_JSX_TAILWIND = `function App() { + return ( +
+

App

+
+ ) +} + +export default App +`; + const TSCONFIG = JSON.stringify({ compilerOptions: { target: "ES2020", @@ -118,7 +162,7 @@ const TSCONFIG = JSON.stringify({ include: ["src"], }, null, 2); -function createVite(projectName, typescript) { +function createVite(projectName, typescript, tailwind) { const projectPath = path.join(process.cwd(), projectName); const ext = typescript ? "tsx" : "jsx"; @@ -135,7 +179,7 @@ function createVite(projectName, typescript) { // vite.config fs.writeFileSync( path.join(projectPath, `vite.config.${typescript ? "ts" : "js"}`), - VITE_CONFIG_JS + tailwind ? VITE_CONFIG_JS_TAILWIND : VITE_CONFIG_JS ); // index.html @@ -144,16 +188,17 @@ function createVite(projectName, typescript) { typescript ? INDEX_HTML_TS(projectName) : INDEX_HTML(projectName) ); - // src/main - fs.writeFileSync( - path.join(projectPath, `src/main.${ext}`), - typescript ? MAIN_TSX : MAIN_JSX - ); + // src/main — include index.css import when tailwind is active + const mainContent = tailwind + ? (typescript ? MAIN_TSX_TAILWIND : MAIN_JSX_TAILWIND) + : (typescript ? MAIN_TSX : MAIN_JSX); + + fs.writeFileSync(path.join(projectPath, `src/main.${ext}`), mainContent); - // src/App + // src/App — use tailwind-styled template when active fs.writeFileSync( path.join(projectPath, `src/App.${ext}`), - APP_JSX + tailwind ? APP_JSX_TAILWIND : APP_JSX ); // tsconfig if needed diff --git a/src/generators/tailwind.js b/src/generators/tailwind.js new file mode 100644 index 0000000..9130478 --- /dev/null +++ b/src/generators/tailwind.js @@ -0,0 +1,36 @@ +const { execSync } = require("child_process"); +const { writeFile } = require("../utils/files"); + +// Tailwind v4: PostCSS plugin for CRA (webpack-based) +const POSTCSS_CONFIG_CRA = `module.exports = { + plugins: { + '@tailwindcss/postcss': {}, + }, +} +`; + +// Tailwind v4: single CSS import replaces the three @tailwind directives +const INDEX_CSS = `@import "tailwindcss"; +`; + +function generateTailwind(projectPath, typescript, cra) { + if (cra) { + // CRA uses PostCSS — write the postcss config + writeFile(projectPath, "postcss.config.js", POSTCSS_CONFIG_CRA); + } + // Vite uses @tailwindcss/vite plugin (wired into vite.config) — no postcss config needed + + writeFile(projectPath, "src/index.css", INDEX_CSS); + + const deps = cra + ? "tailwindcss @tailwindcss/postcss" + : "tailwindcss @tailwindcss/vite"; + + execSync(`npm install -D ${deps}`, { + cwd: projectPath, + stdio: "inherit", + shell: true, + }); +} + +module.exports = generateTailwind; diff --git a/src/index.js b/src/index.js index 71b696b..94d167f 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,7 @@ const createVite = require("./creators/vite"); const cleanCRA = require("./cleaners/cra"); const generateFolders = require("./generators/folders"); +const generateTailwind = require("./generators/tailwind"); const { success, info, error } = require("./utils/logger"); @@ -35,6 +36,7 @@ async function run(projectName, options) { const useCRA = options.cra; const typescript = options.ts; + const tailwind = options.tailwind; info(`Using ${useCRA ? "Create React App" : "Vite"}`); @@ -45,7 +47,7 @@ async function run(projectName, options) { createCRA(projectName, typescript); } else { spinner.stop(); // npm install output needs to show - createVite(projectName, typescript); + createVite(projectName, typescript, tailwind); } } catch (e) { spinner.stop(); @@ -63,11 +65,19 @@ async function run(projectName, options) { // CRA needs cleanup — Vite is already scaffolded clean if (useCRA) { spinner.start("Cleaning starter files..."); - cleanCRA(projectPath, typescript); + cleanCRA(projectPath, typescript, tailwind); spinner.stop(); success("Starter boilerplate removed"); } + // Tailwind setup + if (tailwind) { + spinner.stop(); + info("Setting up Tailwind CSS..."); + generateTailwind(projectPath, typescript, useCRA); + success("Tailwind CSS configured"); + } + // Generate folders if (options.folders) { generateFolders(projectPath); From ef5f12d7bf07c753c4fd5dbbfe2ba843d56cd756 Mon Sep 17 00:00:00 2001 From: Sri Date: Tue, 2 Jun 2026 20:40:30 +0530 Subject: [PATCH 2/6] refactor: removed redundant typescript parameter Removed TypeScript parameter from generateTailwind function. --- src/generators/tailwind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generators/tailwind.js b/src/generators/tailwind.js index 9130478..04fd120 100644 --- a/src/generators/tailwind.js +++ b/src/generators/tailwind.js @@ -13,7 +13,7 @@ const POSTCSS_CONFIG_CRA = `module.exports = { const INDEX_CSS = `@import "tailwindcss"; `; -function generateTailwind(projectPath, typescript, cra) { +function generateTailwind(projectPath, cra) { if (cra) { // CRA uses PostCSS — write the postcss config writeFile(projectPath, "postcss.config.js", POSTCSS_CONFIG_CRA); From 712ea373adedc942dac18b4fd0679afb1337cc78 Mon Sep 17 00:00:00 2001 From: Sri Date: Tue, 2 Jun 2026 20:49:58 +0530 Subject: [PATCH 3/6] refactor: remove unused parameters from cleanCRA and generateTailwind --- src/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 94d167f..d58783c 100644 --- a/src/index.js +++ b/src/index.js @@ -65,7 +65,7 @@ async function run(projectName, options) { // CRA needs cleanup — Vite is already scaffolded clean if (useCRA) { spinner.start("Cleaning starter files..."); - cleanCRA(projectPath, typescript, tailwind); + cleanCRA(projectPath, typescript); spinner.stop(); success("Starter boilerplate removed"); } @@ -74,7 +74,7 @@ async function run(projectName, options) { if (tailwind) { spinner.stop(); info("Setting up Tailwind CSS..."); - generateTailwind(projectPath, typescript, useCRA); + generateTailwind(projectPath, useCRA); success("Tailwind CSS configured"); } @@ -95,4 +95,4 @@ async function run(projectName, options) { } } -module.exports = run; \ No newline at end of file +module.exports = run; From 4a609f9a64e5a301c282c8513a3c9ea8bf4f507f Mon Sep 17 00:00:00 2001 From: Sri Date: Tue, 2 Jun 2026 21:11:08 +0530 Subject: [PATCH 4/6] Refactor App component to minimal starter version --- src/creators/vite.js | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/creators/vite.js b/src/creators/vite.js index dfbe3bd..a98ad37 100644 --- a/src/creators/vite.js +++ b/src/creators/vite.js @@ -130,16 +130,6 @@ const APP_JSX = `function App() { export default App `; -const APP_JSX_TAILWIND = `function App() { - return ( -
-

App

-
- ) -} - -export default App -`; const TSCONFIG = JSON.stringify({ compilerOptions: { @@ -195,10 +185,10 @@ function createVite(projectName, typescript, tailwind) { fs.writeFileSync(path.join(projectPath, `src/main.${ext}`), mainContent); - // src/App — use tailwind-styled template when active + // src/App — minimal starter component fs.writeFileSync( - path.join(projectPath, `src/App.${ext}`), - tailwind ? APP_JSX_TAILWIND : APP_JSX + path.join(projectPath, `src/App.${ext}`), + APP_JSX ); // tsconfig if needed @@ -217,4 +207,4 @@ function createVite(projectName, typescript, tailwind) { }); } -module.exports = createVite; \ No newline at end of file +module.exports = createVite; From e7d0112c87b365eeb632c7279dcd935734903a3d Mon Sep 17 00:00:00 2001 From: Sri Date: Tue, 2 Jun 2026 21:18:36 +0530 Subject: [PATCH 5/6] Refactor App component for cleaner structure --- src/cleaners/cra.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/cleaners/cra.js b/src/cleaners/cra.js index 80f05ab..86d5c92 100644 --- a/src/cleaners/cra.js +++ b/src/cleaners/cra.js @@ -6,18 +6,7 @@ const { function cleanCRA(projectPath, typescript, tailwind) { const ext = typescript ? "tsx" : "js"; - const appContent = tailwind - ? `function App() { - return ( -
-

App

-
- ); -} - -export default App; -` - : `function App() { + const appContent = `function App() { return (

App

@@ -80,4 +69,4 @@ root.render( }); } -module.exports = cleanCRA; \ No newline at end of file +module.exports = cleanCRA; From 55e49cbf35a5ae21fa4e953a6f25ab91fbafda9a Mon Sep 17 00:00:00 2001 From: Sri Date: Tue, 2 Jun 2026 21:47:44 +0530 Subject: [PATCH 6/6] Refactor: re-add tailwind parameter to cleanCRA function --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index d58783c..d38bf35 100644 --- a/src/index.js +++ b/src/index.js @@ -65,7 +65,7 @@ async function run(projectName, options) { // CRA needs cleanup — Vite is already scaffolded clean if (useCRA) { spinner.start("Cleaning starter files..."); - cleanCRA(projectPath, typescript); + cleanCRA(projectPath, typescript, tailwind); spinner.stop(); success("Starter boilerplate removed"); }