From 239e489f8a39b630e1e140b66de83508cc904bfd Mon Sep 17 00:00:00 2001 From: Aylon Muramatsu Date: Mon, 15 Sep 2025 22:44:05 -0300 Subject: [PATCH 1/2] feat: add tailwind v4 to TS --- index.js | 12 ++++++- src/locales/en-US.json | 3 +- src/locales/pt-BR.json | 3 +- src/modules.js | 21 +++++++----- src/template/package.tailwind-v4.json | 18 ++++++++++ src/template/tailwind-v4.css | 1 + src/template/webpack.config.tailwind-v4.js | 40 ++++++++++++++++++++++ 7 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 src/template/package.tailwind-v4.json create mode 100644 src/template/tailwind-v4.css create mode 100644 src/template/webpack.config.tailwind-v4.js diff --git a/index.js b/index.js index 93a089e..c17fb4c 100755 --- a/index.js +++ b/index.js @@ -29,12 +29,15 @@ inquirer.prompt([ i18n.template.blankTs, i18n.template.tawild, i18n.template.tawildTs, + i18n.template.tawildv4Ts, ], }, ]) .then((answers) => { let isTS = false; let isTailwind = false; + let tailwindVersion = 'v3' + switch (answers.template) { case i18n.template.blankTs: @@ -48,10 +51,17 @@ inquirer.prompt([ case i18n.template.tawildTs: isTS = true; isTailwind = true; + tailwindVersion = 'v3' + break; + + case i18n.template.tawildv4Ts: + isTS = true; + isTailwind = true; + tailwindVersion = 'v4'; break; } projectName = (projectName || answers.projectName).replace(/ /g, '_').trim(); - Nulla.tryRun(projectName, isTS, isTailwind); + Nulla.tryRun(projectName, isTS, isTailwind, tailwindVersion); }); diff --git a/src/locales/en-US.json b/src/locales/en-US.json index e8f72b6..305f80a 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -5,7 +5,8 @@ "blank": "Blank (JavaScript)", "blankTs": "Blank (TypeScript) - blank app with TypeScript enabled", "tawild": "Tailwind (JavaScript)", - "tawildTs": "Tailwind (TypeScript) - Tailwind app with TypeScript enabled" + "tawildTs": "Tailwind v3 (TypeScript) - Tailwind v3 app with TypeScript enabled", + "tawildv4Ts": "Tailwind v4 (TypeScript) - Tailwind v4 app with TypeScript enabled" }, "error": { "default": "error:", diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json index b53c62a..243fccb 100644 --- a/src/locales/pt-BR.json +++ b/src/locales/pt-BR.json @@ -5,7 +5,8 @@ "blank": "Blank (JavaScript)", "blankTs": "Blank (TypeScript) - App em branco com TypeScript habilitado", "tawild": "Tailwind (JavaScript)", - "tawildTs": "Tailwind (TypeScript) - App Tailwind com TypeScript habilitado" + "tawildTs": "Tailwind v3 (TypeScript) - App Tailwind v3 com TypeScript habilitado", + "tawildv4Ts": "Tailwind v4 (TypeScript) - App Tailwind v4 com TypeScript habilitado" }, "error": { "default": "erro:", diff --git a/src/modules.js b/src/modules.js index a7116d4..0c89756 100644 --- a/src/modules.js +++ b/src/modules.js @@ -3,6 +3,7 @@ const fs = require('fs'); const path = require('path'); const packageFolder = __dirname; +const whitelist = ['package', 'webpack', 'tailwind.config'] let lang = Intl.DateTimeFormat().resolvedOptions().locale; lang = (lang === 'pt-BR' || lang === 'en-US') @@ -72,7 +73,7 @@ const replaceLangs = (content) => { return content; }; -Nulla.run = (names, isTS, isTailwind) => { +Nulla.run = (names, isTS, isTailwind, tailwindVersion = 'v3') => { const { projectSlug, projectName } = names; const projectPath = path.join(process.cwd(), projectSlug); @@ -92,23 +93,27 @@ Nulla.run = (names, isTS, isTailwind) => { // Tailwind check, remove all default files and replace them with Tailwind defaults if (isTailwind) for (const file of Files.files) { - if (file.includes(".tailwind")) { + if (file.includes(".tailwind") && tailwindVersion === 'v3' && !file.includes('-v4')) { tailwindReplace.push(file.replace(".tailwind", "")) } + else if(file.includes('.tailwind') && tailwindVersion === 'v4' && (file.includes('-v4') ||!whitelist.some(x => file.includes(x))) ) + tailwindReplace.push(file.replace(".tailwind-v4", "").replace(".tailwind", "")) } - + for (const file of Files.files) { if (file.match(new RegExp(`.${isTS ? 'js' : 'ts'}x?$`)) && file.indexOf('.config.') === -1) continue; if (!isTS && /tsconfig.json/.test(file)) continue; // Tailwind replacer if (isTailwind) { - + if(tailwindVersion === 'v3' && file.includes('-v4')) continue; + if(tailwindVersion === 'v4' && whitelist.some(x => file.includes(x) && !file.includes('-v4')) ) continue; // Check if the file is going to be replaced by tailwind file if (tailwindReplace.includes(file)) continue; // Do not include css files unless they're supposed to be included - if (file.endsWith(".css") && !file.includes("tailwind.")) continue; + if (file.endsWith(".css") && !file.includes("tailwind.") && tailwindVersion === 'v3') continue; + if(file.endsWith(".css") && tailwindVersion === 'v4' && !file.includes('-v4')) continue } else if (file.includes("tailwind")) continue; // If it is not tailwind, do not add tailwind files to the bundle @@ -118,7 +123,7 @@ Nulla.run = (names, isTS, isTailwind) => { ); content = Nulla.contentReplacer(content, 'NAME', projectName); content = Nulla.contentReplacer(content, 'SLUG', projectSlug); - const target = path.join(projectPath, file.replace('_', '.').replace('.tailwind', '')); + const target = path.join(projectPath, file.replace('_', '.').replace('.tailwind-v4', '').replace('.tailwind', '').replace("-v4", "")); content = Nulla.contentReplacer(content, 'SRC', srcFolder); content = Nulla.contentReplacer(content, 'LANG', lang); content = replaceLangs(content); @@ -181,10 +186,10 @@ Nulla.errorHandler = (e) => { } }; -Nulla.tryRun = (name, isTS, isTailwind) => { +Nulla.tryRun = (name, isTS, isTailwind, tailwindVersion) => { try { const names = Nulla.storeNames(name); - Nulla.run(names, isTS, isTailwind); + Nulla.run(names, isTS, isTailwind, tailwindVersion); } catch (e) { Nulla.errorHandler(e); } diff --git a/src/template/package.tailwind-v4.json b/src/template/package.tailwind-v4.json new file mode 100644 index 0000000..ee3ad04 --- /dev/null +++ b/src/template/package.tailwind-v4.json @@ -0,0 +1,18 @@ +{ + "name": ":!PROJECT_SLUG!:", + "version": "0.0.1", + "description": "", + "author": "", + "license": "ISC", + "devDependencies": { + "nullstack": "~0.20.0", + "tailwindcss": "^4.1.13", + "postcss-loader": "^8.2.0", + "postcss": "^8.5.6", + "@tailwindcss/postcss": "^4.1.13" + }, + "scripts": { + "start": "npx nullstack start", + "build": "npx nullstack build" + } +} \ No newline at end of file diff --git a/src/template/tailwind-v4.css b/src/template/tailwind-v4.css new file mode 100644 index 0000000..a461c50 --- /dev/null +++ b/src/template/tailwind-v4.css @@ -0,0 +1 @@ +@import "tailwindcss"; \ No newline at end of file diff --git a/src/template/webpack.config.tailwind-v4.js b/src/template/webpack.config.tailwind-v4.js new file mode 100644 index 0000000..c4db73d --- /dev/null +++ b/src/template/webpack.config.tailwind-v4.js @@ -0,0 +1,40 @@ +const [server, client] = require('nullstack/webpack.config') + +function customClient(...args) { + const config = client(...args) + const rule = config.module.rules.find((rule) => rule.test && rule.test.test('.css')) + rule.use.push({ + loader: require.resolve('postcss-loader'), + options: { + postcssOptions: { + plugins: { + '@tailwindcss/postcss': {}, + }, + }, + }, + }) + + // Configurar minimizer CSS mais compatível para build + if (config.optimization && config.optimization.minimizer) { + config.optimization.minimizer = config.optimization.minimizer.map((minimizer) => { + if (minimizer.constructor.name === 'CssMinimizerPlugin') { + const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') + return new CssMinimizerPlugin({ + minimizerOptions: { + preset: [ + 'default', + { + discardComments: { removeAll: true }, + }, + ], + }, + }) + } + return minimizer + }) + } + + return config +} + +module.exports = [server, customClient] From a1ce6d6be2116a845dbcfcb2a4e68f08a39a942d Mon Sep 17 00:00:00 2001 From: Aylon Muramatsu Date: Thu, 2 Oct 2025 13:45:54 -0300 Subject: [PATCH 2/2] feat: adiciona tailwind v4 para javascript --- index.js | 6 ++++++ src/locales/en-US.json | 1 + src/locales/pt-BR.json | 1 + 3 files changed, 8 insertions(+) diff --git a/index.js b/index.js index c17fb4c..e220e02 100755 --- a/index.js +++ b/index.js @@ -28,6 +28,7 @@ inquirer.prompt([ i18n.template.blank, i18n.template.blankTs, i18n.template.tawild, + i18n.template.tawildv4, i18n.template.tawildTs, i18n.template.tawildv4Ts, ], @@ -48,6 +49,11 @@ inquirer.prompt([ isTailwind = true; break; + case i18n.template.tawildv4: + isTailwind = true; + tailwindVersion = "v4"; + break; + case i18n.template.tawildTs: isTS = true; isTailwind = true; diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 305f80a..1b8aadd 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -5,6 +5,7 @@ "blank": "Blank (JavaScript)", "blankTs": "Blank (TypeScript) - blank app with TypeScript enabled", "tawild": "Tailwind (JavaScript)", + "tawildv4": "Tailwind (Javascript) - Tailwind v4 app", "tawildTs": "Tailwind v3 (TypeScript) - Tailwind v3 app with TypeScript enabled", "tawildv4Ts": "Tailwind v4 (TypeScript) - Tailwind v4 app with TypeScript enabled" }, diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json index 243fccb..bf3150e 100644 --- a/src/locales/pt-BR.json +++ b/src/locales/pt-BR.json @@ -5,6 +5,7 @@ "blank": "Blank (JavaScript)", "blankTs": "Blank (TypeScript) - App em branco com TypeScript habilitado", "tawild": "Tailwind (JavaScript)", + "tawildv4": "Tailwind (Javascript) - App Tailwind v4", "tawildTs": "Tailwind v3 (TypeScript) - App Tailwind v3 com TypeScript habilitado", "tawildv4Ts": "Tailwind v4 (TypeScript) - App Tailwind v4 com TypeScript habilitado" },