tumemo 1.0.0 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/index.js +69 -89
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
# Tumemo CLI
|
|
1
|
+
# 🚀 Tumemo CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
O jeito mais rápido de iniciar seus projetos React com TypeScript, Axios e as melhores ferramentas de estilo.
|
|
4
4
|
|
|
5
5
|
## 🛠️ O que ele faz?
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
- **
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
- **
|
|
12
|
-
- **Organização Sênior:** Cria pastas `components`, `pages`, `hooks` e `lib`.
|
|
6
|
+
- Gera um projeto **Vite (React + TS)** limpo.
|
|
7
|
+
- Remove arquivos desnecessários (`App.css`, `index.css`, ativos de exemplo).
|
|
8
|
+
- Instala automaticamente: **Axios**, **React Router Dom**, **Tailwind Merge** e **Clsx**.
|
|
9
|
+
- Configura Aliases de caminho (`@/` aponta para `src/`).
|
|
10
|
+
- Já entrega as pastas `src/components`, `src/pages` e `src/shared` criadas.
|
|
11
|
+
- **Inicia o servidor automaticamente** após o setup.
|
|
13
12
|
|
|
14
13
|
## 🚀 Como usar
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
Acesse a pasta onde deseja criar o projeto e rode:
|
|
16
|
+
|
|
17
17
|
```bash
|
|
18
|
-
npx tumemo
|
|
18
|
+
npx tumemo@latest
|
package/index.js
CHANGED
|
@@ -6,132 +6,112 @@ import { execa } from 'execa';
|
|
|
6
6
|
import fs from 'fs-extra';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
|
|
9
|
+
process.env.FORCE_COLOR = "1";
|
|
10
|
+
|
|
9
11
|
const log = {
|
|
10
12
|
info: (msg) => console.log(chalk.blue(`ℹ ${msg}`)),
|
|
11
13
|
success: (msg) => console.log(chalk.green.bold(`\n✅ ${msg}`)),
|
|
12
14
|
error: (msg) => console.log(chalk.red.bold(`\n❌ ${msg}`)),
|
|
13
|
-
step: (msg) => console.log(chalk.cyan(
|
|
15
|
+
step: (msg) => console.log(chalk.cyan.bold(`\n🚀 ${msg}`))
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
async function runCommand(command, args, options = {}) {
|
|
17
19
|
try {
|
|
18
|
-
await execa(command, args, {
|
|
20
|
+
await execa(command, args, {
|
|
21
|
+
stdio: 'inherit',
|
|
22
|
+
shell: true,
|
|
23
|
+
env: { ...process.env, FORCE_COLOR: "1" },
|
|
24
|
+
...options
|
|
25
|
+
});
|
|
19
26
|
} catch (error) {
|
|
20
|
-
log.error(`Erro
|
|
27
|
+
log.error(`Erro: ${error.message}`);
|
|
21
28
|
process.exit(1);
|
|
22
29
|
}
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
program
|
|
26
33
|
.name('Tumemo')
|
|
27
|
-
.description('
|
|
28
|
-
.version('1.
|
|
29
|
-
.option('-t, --tailwind', 'Instalar Tailwind
|
|
30
|
-
.option('-s, --shadcn', 'Instalar
|
|
34
|
+
.description('O setup mais rápido para React + TS')
|
|
35
|
+
.version('1.1.1')
|
|
36
|
+
.option('-t, --tailwind', 'Instalar Tailwind v4')
|
|
37
|
+
.option('-s, --shadcn', 'Instalar Shadcn')
|
|
31
38
|
.action(async (options) => {
|
|
32
39
|
const root = process.cwd();
|
|
40
|
+
const projectName = path.basename(root);
|
|
33
41
|
|
|
34
42
|
try {
|
|
35
43
|
log.step(`Iniciando Setup Tumemo em: ${root}`);
|
|
36
44
|
|
|
37
|
-
|
|
38
|
-
await runCommand('
|
|
45
|
+
log.info('Baixando template React + TS...');
|
|
46
|
+
await runCommand('npx', ['--yes', 'degit', 'vitejs/vite/packages/create-vite/template-react-ts', '.']);
|
|
47
|
+
|
|
48
|
+
const oldGit = path.join(root, '_gitignore');
|
|
49
|
+
if (fs.existsSync(oldGit)) fs.renameSync(oldGit, path.join(root, '.gitignore'));
|
|
50
|
+
|
|
51
|
+
const pkgPath = path.join(root, 'package.json');
|
|
52
|
+
const pkg = await fs.readJson(pkgPath);
|
|
53
|
+
pkg.name = projectName;
|
|
54
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
39
55
|
|
|
40
|
-
|
|
41
|
-
log.info('Baixando dependências...');
|
|
56
|
+
log.info('Instalando dependências base...');
|
|
42
57
|
await runCommand('npm', ['install']);
|
|
43
|
-
await runCommand('npm', ['install', '-D', '@types/node']);
|
|
44
|
-
await runCommand('npm', ['install', 'axios', 'react-router-dom', 'tailwind-merge', 'clsx']);
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
log.info('Limpando boilerplate...');
|
|
60
|
+
['src/assets', 'src/App.css', 'src/index.css', 'public/vite.svg'].forEach(item => {
|
|
61
|
+
const fullPath = path.resolve(root, item);
|
|
62
|
+
if (fs.existsSync(fullPath)) fs.removeSync(fullPath);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const htmlPath = path.join(root, 'index.html');
|
|
66
|
+
let htmlContent = fs.readFileSync(htmlPath, 'utf8');
|
|
67
|
+
htmlContent = htmlContent.replace('</head>', ' <style>body { margin: 0; padding: 0; box-sizing: border-box; }</style>\n </head>');
|
|
68
|
+
fs.writeFileSync(htmlPath, htmlContent);
|
|
69
|
+
|
|
70
|
+
await runCommand('npm', ['install', 'axios', 'react-router-dom', 'tailwind-merge', 'clsx']);
|
|
71
|
+
await runCommand('npm', ['install', '-D', '@types/node']);
|
|
54
72
|
|
|
55
73
|
const useTailwind = options.tailwind || options.shadcn;
|
|
74
|
+
const useShadcn = options.shadcn;
|
|
56
75
|
|
|
57
|
-
// 4. Estilos Customizados
|
|
58
76
|
if (useTailwind) {
|
|
59
|
-
log.info('Configurando
|
|
60
|
-
await runCommand('npm', ['install', '
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const tailwindContent = `@tailwind base;\n@tailwind components;\n@tailwind utilities;`;
|
|
64
|
-
await fs.ensureDir(path.join(root, 'src/shared'));
|
|
65
|
-
await fs.writeFile(path.join(root, 'src/shared/tailwind.css'), tailwindContent);
|
|
77
|
+
log.info('Configurando Tailwind v4...');
|
|
78
|
+
await runCommand('npm', ['install', 'tailwindcss', '@tailwindcss/vite']);
|
|
79
|
+
fs.ensureDirSync(path.join(root, 'src/shared'));
|
|
80
|
+
fs.writeFileSync(path.join(root, 'src/shared/tailwind.css'), `@import "tailwindcss";`);
|
|
66
81
|
}
|
|
67
82
|
|
|
68
|
-
|
|
69
|
-
if (options.shadcn) {
|
|
83
|
+
if (useShadcn) {
|
|
70
84
|
log.info('Configurando Shadcn UI...');
|
|
71
|
-
await runCommand('
|
|
72
|
-
await runCommand('npx', ['shadcn-ui@latest', 'init', '-y']);
|
|
85
|
+
await runCommand('npx', ['--yes', 'shadcn@latest', 'init', '-y']);
|
|
73
86
|
}
|
|
74
87
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
import path from "path"
|
|
78
|
-
import react from "@vitejs/plugin-react"
|
|
79
|
-
import { defineConfig } from "vite"
|
|
80
|
-
|
|
81
|
-
export default defineConfig({
|
|
82
|
-
plugins: [react()],
|
|
83
|
-
resolve: {
|
|
84
|
-
alias: {
|
|
85
|
-
"@": path.resolve(__dirname, "./src"),
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
})`;
|
|
89
|
-
await fs.writeFile(path.join(root, 'vite.config.ts'), viteConfig.trim());
|
|
90
|
-
|
|
91
|
-
const tsConfigPath = path.join(root, 'tsconfig.app.json');
|
|
92
|
-
if (await fs.pathExists(tsConfigPath)) {
|
|
93
|
-
const tsConfig = await fs.readJson(tsConfigPath);
|
|
94
|
-
tsConfig.compilerOptions.baseUrl = ".";
|
|
95
|
-
tsConfig.compilerOptions.paths = { "@/*": ["./src/*"] };
|
|
96
|
-
await fs.writeJson(tsConfigPath, tsConfig, { spaces: 2 });
|
|
97
|
-
}
|
|
88
|
+
const viteConfig = `import path from "path"\nimport react from "@vitejs/plugin-react"\nimport { defineConfig } from "vite"\n${useTailwind ? 'import tailwindcss from "@tailwindcss/vite"' : ''}\n\nexport default defineConfig({\n plugins: [react(), ${useTailwind ? 'tailwindcss()' : ''}],\n resolve: { alias: { "@": path.resolve(__dirname, "./src") } },\n})`;
|
|
89
|
+
fs.writeFileSync(path.join(root, 'vite.config.ts'), viteConfig.trim());
|
|
98
90
|
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
import ReactDOM from 'react-dom/client'
|
|
103
|
-
import App from './App.tsx'
|
|
104
|
-
${useTailwind ? "import '@/shared/tailwind.css'" : ""}
|
|
105
|
-
|
|
106
|
-
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
107
|
-
<React.StrictMode>
|
|
108
|
-
<App />
|
|
109
|
-
</React.StrictMode>,
|
|
110
|
-
)`;
|
|
111
|
-
await fs.writeFile(path.join(root, 'src/main.tsx'), mainContent.trim());
|
|
112
|
-
|
|
113
|
-
// 8. App.tsx
|
|
114
|
-
const appContent = `
|
|
115
|
-
export default function App() {
|
|
116
|
-
return (
|
|
117
|
-
<div style={{ padding: '2rem', fontFamily: 'sans-serif' }}>
|
|
118
|
-
<h1>Setup Tumemo</h1>
|
|
119
|
-
<p>Desenvolvido com sucesso. React + TS + Axios prontos.</p>
|
|
120
|
-
</div>
|
|
121
|
-
)
|
|
122
|
-
}
|
|
123
|
-
`;
|
|
124
|
-
await fs.writeFile(path.join(root, 'src/App.tsx'), appContent.trim());
|
|
91
|
+
const tsAppPath = path.join(root, 'tsconfig.app.json');
|
|
92
|
+
const fallbackTs = { compilerOptions: { target: "ESNext", lib: ["DOM", "DOM.Iterable", "ESNext"], module: "ESNext", skipLibCheck: true, moduleResolution: "Node", resolveJsonModule: true, isolatedModules: true, noEmit: true, jsx: "react-jsx", strict: true, baseUrl: ".", paths: { "@/*": ["./src/*"] } } };
|
|
93
|
+
fs.writeJsonSync(tsAppPath, fallbackTs, { spaces: 2 });
|
|
125
94
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
95
|
+
let techStack = "React + TS";
|
|
96
|
+
if (useShadcn) techStack += " + Shadcn UI";
|
|
97
|
+
else if (useTailwind) techStack += " + Tailwind v4";
|
|
98
|
+
|
|
99
|
+
const appContent = `export default function App() {\n return (\n <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', width: '100%', fontFamily: 'system-ui, sans-serif', backgroundColor: '#0f172a', color: '#f8fafc', margin: 0 }}>\n <h1 style={{ fontSize: '3.5rem', marginBottom: '0.5rem' }}>Tumemo CLI</h1>\n <p style={{ fontSize: '1.25rem', color: '#94a3b8' }}>Projeto: <strong style={{ color: '#38bdf8' }}>${projectName}</strong></p>\n <div style={{ marginTop: '2.5rem', padding: '1.5rem 3rem', borderRadius: '12px', backgroundColor: '#1e293b', border: '1px solid #334155' }}>\n <p>Stack: <strong>${techStack}</strong></p>\n </div>\n </div>\n )\n}`;
|
|
100
|
+
fs.writeFileSync(path.join(root, 'src/App.tsx'), appContent.trim());
|
|
101
|
+
|
|
102
|
+
const mainContent = `import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport App from './App.tsx'\n${useTailwind ? "import '@/shared/tailwind.css'\n" : ""}ReactDOM.createRoot(document.getElementById('root')!).render(<App />)`;
|
|
103
|
+
fs.writeFileSync(path.join(root, 'src/main.tsx'), mainContent);
|
|
104
|
+
|
|
105
|
+
['src/components', 'src/pages'].forEach(dir => fs.ensureDirSync(path.join(root, dir)));
|
|
106
|
+
|
|
107
|
+
log.success(`\nTumemo v1.0.5 finalizado!`);
|
|
108
|
+
log.info('Iniciando servidor de desenvolvimento...\n');
|
|
109
|
+
|
|
110
|
+
// COMANDO PARA RODAR O SERVIDOR AUTOMATICAMENTE
|
|
111
|
+
await runCommand('npm', ['run', 'dev']);
|
|
131
112
|
|
|
132
|
-
log.success('Setup Tumemo finalizado! Tudo pronto para codar.');
|
|
133
113
|
} catch (err) {
|
|
134
|
-
log.error(`
|
|
114
|
+
log.error(`Falha: ${err.message}`);
|
|
135
115
|
}
|
|
136
116
|
});
|
|
137
117
|
|