arustack 1.0.0
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 +45 -0
- package/bin/index.js +277 -0
- package/package.json +29 -0
- package/publish_output.txt +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# arustack š
|
|
2
|
+
|
|
3
|
+
Scaffold a professional full-stack React + Express app instantly with a premium tech stack.
|
|
4
|
+
|
|
5
|
+
## š¦ What's inside?
|
|
6
|
+
|
|
7
|
+
- **Frontend**: React + Vite + Tailwind CSS v4 + DaisyUI v5 + Axios + React Toastify + React Router.
|
|
8
|
+
- **Backend**: Express + CORS + dotenv + nodemon.
|
|
9
|
+
- **Tools**: `concurrently` (to run both together).
|
|
10
|
+
|
|
11
|
+
## š Quick Start
|
|
12
|
+
|
|
13
|
+
You don't need to install anything globally. Just run:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx arustack my-app
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### š Running your app
|
|
20
|
+
|
|
21
|
+
1. Navigate to your project:
|
|
22
|
+
```bash
|
|
23
|
+
cd my-app
|
|
24
|
+
```
|
|
25
|
+
2. Start both client and server:
|
|
26
|
+
```bash
|
|
27
|
+
npm run dev
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## š Project Structure
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
my-app/
|
|
34
|
+
āāā client/ # React + Vite + Tailwind + DaisyUI
|
|
35
|
+
āāā server/ # Express + CORS
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## šØ Styling
|
|
39
|
+
|
|
40
|
+
- **Tailwind CSS v4**: Built-in support for the latest Tailwind version.
|
|
41
|
+
- **DaisyUI v5**: Access high-quality components and themes easily.
|
|
42
|
+
- **Themes**: Switch themes instantly using `data-theme` on your `<html>` tag.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
Built with ā¤ļø for rapid development.
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const chalk = require("chalk");
|
|
4
|
+
const ora = require("ora");
|
|
5
|
+
const fs = require("fs-extra");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const { execSync } = require("child_process");
|
|
8
|
+
|
|
9
|
+
const projectName = process.argv[2] || "my-fullstack-app";
|
|
10
|
+
const projectPath = path.join(process.cwd(), projectName);
|
|
11
|
+
const clientPath = path.join(projectPath, "client");
|
|
12
|
+
const serverPath = path.join(projectPath, "server");
|
|
13
|
+
|
|
14
|
+
console.log(chalk.bold.cyan("\nš create-fullstack-app\n"));
|
|
15
|
+
console.log(chalk.gray(`Creating project: ${chalk.white.bold(projectName)}\n`));
|
|
16
|
+
|
|
17
|
+
function run(cmd, cwd) {
|
|
18
|
+
execSync(cmd, { cwd, stdio: "ignore" });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function main() {
|
|
22
|
+
|
|
23
|
+
// āāā 1. Create folders āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
24
|
+
let spinner = ora("Creating project folders...").start();
|
|
25
|
+
await fs.ensureDir(clientPath);
|
|
26
|
+
await fs.ensureDir(serverPath);
|
|
27
|
+
spinner.succeed(chalk.green("Project folders created"));
|
|
28
|
+
|
|
29
|
+
// āāā 2. SERVER āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
30
|
+
spinner = ora("Setting up Express server...").start();
|
|
31
|
+
|
|
32
|
+
const serverPkg = {
|
|
33
|
+
name: `${projectName}-server`,
|
|
34
|
+
version: "1.0.0",
|
|
35
|
+
main: "index.js",
|
|
36
|
+
scripts: {
|
|
37
|
+
start: "node index.js",
|
|
38
|
+
dev: "nodemon index.js",
|
|
39
|
+
},
|
|
40
|
+
dependencies: {},
|
|
41
|
+
};
|
|
42
|
+
await fs.writeJSON(path.join(serverPath, "package.json"), serverPkg, { spaces: 2 });
|
|
43
|
+
run("npm install express cors dotenv", serverPath);
|
|
44
|
+
run("npm install --save-dev nodemon", serverPath);
|
|
45
|
+
|
|
46
|
+
await fs.writeFile(
|
|
47
|
+
path.join(serverPath, "index.js"),
|
|
48
|
+
`const express = require('express');
|
|
49
|
+
const cors = require('cors');
|
|
50
|
+
require('dotenv').config();
|
|
51
|
+
|
|
52
|
+
const app = express();
|
|
53
|
+
const PORT = process.env.PORT || 5000;
|
|
54
|
+
|
|
55
|
+
app.use(cors());
|
|
56
|
+
app.use(express.json());
|
|
57
|
+
|
|
58
|
+
// āā Routes āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
59
|
+
app.get('/', (req, res) => {
|
|
60
|
+
res.json({ message: 'š Server is running!' });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
app.get('/api/hello', (req, res) => {
|
|
64
|
+
res.json({ message: 'Hello from Express! š' });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
68
|
+
app.listen(PORT, () => {
|
|
69
|
+
console.log(\`ā
Server running on http://localhost:\${PORT}\`);
|
|
70
|
+
});
|
|
71
|
+
`
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
await fs.writeFile(path.join(serverPath, ".env"), `PORT=5000\n# Add your environment variables here\n`);
|
|
75
|
+
await fs.writeFile(path.join(serverPath, ".gitignore"), `node_modules\n.env\n`);
|
|
76
|
+
|
|
77
|
+
spinner.succeed(chalk.green("Express server ready (express, cors, dotenv, nodemon)"));
|
|
78
|
+
|
|
79
|
+
// āāā 3. CLIENT ā Vite + React āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
80
|
+
spinner = ora("Creating React app with Vite...").start();
|
|
81
|
+
run(`npm create vite@latest client -- --template react`, projectPath);
|
|
82
|
+
run("npm install", clientPath);
|
|
83
|
+
spinner.succeed(chalk.green("React + Vite project created"));
|
|
84
|
+
|
|
85
|
+
// āāā 4. Tailwind v4 + DaisyUI v5 āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
86
|
+
spinner = ora("Installing Tailwind CSS v4 + DaisyUI v5...").start();
|
|
87
|
+
run("npm install tailwindcss @tailwindcss/vite daisyui", clientPath);
|
|
88
|
+
spinner.succeed(chalk.green("Tailwind v4 + DaisyUI v5 installed"));
|
|
89
|
+
|
|
90
|
+
// āāā 5. vite.config.js āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
91
|
+
spinner = ora("Writing vite.config.js...").start();
|
|
92
|
+
await fs.writeFile(
|
|
93
|
+
path.join(clientPath, "vite.config.js"),
|
|
94
|
+
`import { defineConfig } from 'vite'
|
|
95
|
+
import react from '@vitejs/plugin-react'
|
|
96
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
97
|
+
|
|
98
|
+
export default defineConfig({
|
|
99
|
+
plugins: [
|
|
100
|
+
react(),
|
|
101
|
+
tailwindcss(),
|
|
102
|
+
],
|
|
103
|
+
server: {
|
|
104
|
+
proxy: {
|
|
105
|
+
'/api': 'http://localhost:5000',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
`
|
|
110
|
+
);
|
|
111
|
+
spinner.succeed(chalk.green("vite.config.js written (Tailwind v4 plugin + /api proxy)"));
|
|
112
|
+
|
|
113
|
+
// āāā 6. index.css āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
114
|
+
spinner = ora("Writing global CSS...").start();
|
|
115
|
+
await fs.writeFile(
|
|
116
|
+
path.join(clientPath, "src/index.css"),
|
|
117
|
+
`@import "tailwindcss";
|
|
118
|
+
@plugin "daisyui" {
|
|
119
|
+
themes: light, dark, cupcake, synthwave, corporate;
|
|
120
|
+
}
|
|
121
|
+
`
|
|
122
|
+
);
|
|
123
|
+
spinner.succeed(chalk.green("index.css written (Tailwind v4 + DaisyUI v5 syntax)"));
|
|
124
|
+
|
|
125
|
+
// āāā 7. Axios + Toastify + React Router āāāāāāāāāāāāāāāāāāāāāāāā
|
|
126
|
+
spinner = ora("Installing Axios, Toastify, React Router...").start();
|
|
127
|
+
run("npm install axios react-toastify react-router-dom", clientPath);
|
|
128
|
+
spinner.succeed(chalk.green("Axios, React Toastify, React Router DOM installed"));
|
|
129
|
+
|
|
130
|
+
// āāā 8. App.jsx āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
131
|
+
spinner = ora("Writing demo App.jsx...").start();
|
|
132
|
+
await fs.writeFile(
|
|
133
|
+
path.join(clientPath, "src/App.jsx"),
|
|
134
|
+
`import { useState } from 'react';
|
|
135
|
+
import { BrowserRouter, Routes, Route, useNavigate } from 'react-router-dom';
|
|
136
|
+
import { ToastContainer, toast } from 'react-toastify';
|
|
137
|
+
import 'react-toastify/dist/ReactToastify.css';
|
|
138
|
+
import axios from 'axios';
|
|
139
|
+
|
|
140
|
+
// āā Home Page āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
141
|
+
function Home() {
|
|
142
|
+
const navigate = useNavigate();
|
|
143
|
+
const [data, setData] = useState(null);
|
|
144
|
+
const [loading, setLoading] = useState(false);
|
|
145
|
+
|
|
146
|
+
const fetchData = async () => {
|
|
147
|
+
setLoading(true);
|
|
148
|
+
try {
|
|
149
|
+
const res = await axios.get('/api/hello');
|
|
150
|
+
setData(res.data.message);
|
|
151
|
+
toast.success('Data fetched! ā
');
|
|
152
|
+
} catch (err) {
|
|
153
|
+
toast.error('Start your Express server first!');
|
|
154
|
+
} finally {
|
|
155
|
+
setLoading(false);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<div className="min-h-screen bg-base-200 flex flex-col items-center justify-center gap-6 p-8">
|
|
161
|
+
<div className="card w-full max-w-lg shadow-xl bg-base-100">
|
|
162
|
+
<div className="card-body items-center text-center gap-4">
|
|
163
|
+
<h1 className="card-title text-3xl font-bold">š Fullstack Starter</h1>
|
|
164
|
+
<p className="text-base-content/60">
|
|
165
|
+
React Ā· Vite Ā· Tailwind v4 Ā· DaisyUI v5 Ā· Toastify Ā· Axios Ā· React Router
|
|
166
|
+
</p>
|
|
167
|
+
|
|
168
|
+
<button
|
|
169
|
+
className="btn btn-primary w-full"
|
|
170
|
+
onClick={fetchData}
|
|
171
|
+
disabled={loading}
|
|
172
|
+
>
|
|
173
|
+
{loading ? <span className="loading loading-spinner"></span> : 'Fetch from Express API'}
|
|
174
|
+
</button>
|
|
175
|
+
|
|
176
|
+
<button
|
|
177
|
+
className="btn btn-outline w-full"
|
|
178
|
+
onClick={() => navigate('/about')}
|
|
179
|
+
>
|
|
180
|
+
Go to About Page ā
|
|
181
|
+
</button>
|
|
182
|
+
|
|
183
|
+
{data && (
|
|
184
|
+
<div className="alert alert-success w-full">
|
|
185
|
+
<span>{data}</span>
|
|
186
|
+
</div>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// āā About Page āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
195
|
+
function About() {
|
|
196
|
+
const navigate = useNavigate();
|
|
197
|
+
return (
|
|
198
|
+
<div className="min-h-screen bg-base-200 flex flex-col items-center justify-center gap-6 p-8">
|
|
199
|
+
<div className="card w-full max-w-lg shadow-xl bg-base-100">
|
|
200
|
+
<div className="card-body items-center text-center gap-4">
|
|
201
|
+
<h1 className="card-title text-3xl font-bold">About Page</h1>
|
|
202
|
+
<p className="text-base-content/60">You navigated here using React Router! š</p>
|
|
203
|
+
<button className="btn btn-primary" onClick={() => navigate('/')}>
|
|
204
|
+
ā Back to Home
|
|
205
|
+
</button>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// āā App āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
213
|
+
export default function App() {
|
|
214
|
+
return (
|
|
215
|
+
<BrowserRouter>
|
|
216
|
+
<ToastContainer position="top-right" autoClose={3000} />
|
|
217
|
+
<Routes>
|
|
218
|
+
<Route path="/" element={<Home />} />
|
|
219
|
+
<Route path="/about" element={<About />} />
|
|
220
|
+
</Routes>
|
|
221
|
+
</BrowserRouter>
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
`
|
|
225
|
+
);
|
|
226
|
+
spinner.succeed(chalk.green("Demo App.jsx written"));
|
|
227
|
+
|
|
228
|
+
// āāā 9. Root package.json with concurrently āāāāāāāāāāāāāāāāāāāāā
|
|
229
|
+
spinner = ora("Creating root scripts...").start();
|
|
230
|
+
const rootPkg = {
|
|
231
|
+
name: projectName,
|
|
232
|
+
version: "1.0.0",
|
|
233
|
+
scripts: {
|
|
234
|
+
dev: `concurrently "npm run dev --prefix client" "npm run dev --prefix server"`,
|
|
235
|
+
"dev:client": "npm run dev --prefix client",
|
|
236
|
+
"dev:server": "npm run dev --prefix server",
|
|
237
|
+
build: "npm run build --prefix client",
|
|
238
|
+
},
|
|
239
|
+
dependencies: {},
|
|
240
|
+
};
|
|
241
|
+
await fs.writeJSON(path.join(projectPath, "package.json"), rootPkg, { spaces: 2 });
|
|
242
|
+
run("npm install concurrently", projectPath);
|
|
243
|
+
|
|
244
|
+
await fs.writeFile(
|
|
245
|
+
path.join(projectPath, ".gitignore"),
|
|
246
|
+
`node_modules\nclient/node_modules\nserver/node_modules\nclient/dist\n.env\n`
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
spinner.succeed(chalk.green("Root scripts ready (concurrently)"));
|
|
250
|
+
|
|
251
|
+
// āāā Done! āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
252
|
+
console.log(`
|
|
253
|
+
${chalk.bold.green("ā
Project created successfully!")}
|
|
254
|
+
|
|
255
|
+
${chalk.bold("š Structure:")}
|
|
256
|
+
${chalk.cyan(projectName + "/")}
|
|
257
|
+
āāā ${chalk.yellow("client/")} ā React + Vite + Tailwind v4 + DaisyUI v5 + Toastify + Axios + React Router
|
|
258
|
+
āāā ${chalk.yellow("server/")} ā Express + CORS + dotenv + nodemon
|
|
259
|
+
|
|
260
|
+
${chalk.bold("ā¶ Get started:")}
|
|
261
|
+
${chalk.white(`cd ${projectName}`)}
|
|
262
|
+
${chalk.white("npm run dev")} ${chalk.gray("ā starts both client & server together")}
|
|
263
|
+
|
|
264
|
+
${chalk.bold("š URLs:")}
|
|
265
|
+
Client ā ${chalk.cyan("http://localhost:5173")}
|
|
266
|
+
Server ā ${chalk.cyan("http://localhost:5000")}
|
|
267
|
+
|
|
268
|
+
${chalk.bold("šØ DaisyUI themes:")}
|
|
269
|
+
${chalk.gray('Add data-theme="dark" on your <html> tag to switch themes')}
|
|
270
|
+
${chalk.gray("Available: light, dark, cupcake, synthwave, corporate")}
|
|
271
|
+
`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
main().catch((err) => {
|
|
275
|
+
console.error(chalk.red("\nā Error: " + err.message));
|
|
276
|
+
process.exit(1);
|
|
277
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "arustack",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Scaffold a full-stack React + Express app instantly with Tailwind, DaisyUI, shadcn, Toastify, Axios, CORS",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"arustack": "bin/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/index.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"react",
|
|
14
|
+
"express",
|
|
15
|
+
"tailwind",
|
|
16
|
+
"fullstack",
|
|
17
|
+
"scaffold",
|
|
18
|
+
"cli",
|
|
19
|
+
"daisyui",
|
|
20
|
+
"shadcn"
|
|
21
|
+
],
|
|
22
|
+
"author": "",
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"chalk": "^4.1.2",
|
|
26
|
+
"fs-extra": "^11.3.4",
|
|
27
|
+
"ora": "^5.4.1"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
npm warn publish npm auto-corrected some errors in your package.json when publishing. Please run "npm pkg fix" to address these errors.
|
|
2
|
+
npm warn publish errors corrected:
|
|
3
|
+
npm warn publish "bin[arustack]" script name bin/index.js was invalid and removed
|
|
4
|
+
npm notice
|
|
5
|
+
npm notice š¦ arustack@1.0.0
|
|
6
|
+
npm notice Tarball Contents
|
|
7
|
+
npm notice 1.0kB README.md
|
|
8
|
+
npm notice 10.6kB bin/index.js
|
|
9
|
+
npm notice 565B package.json
|
|
10
|
+
npm notice 0B publish_output.txt
|
|
11
|
+
npm notice Tarball Details
|
|
12
|
+
npm notice name: arustack
|
|
13
|
+
npm notice version: 1.0.0
|
|
14
|
+
npm notice filename: arustack-1.0.0.tgz
|
|
15
|
+
npm notice package size: 3.7 kB
|
|
16
|
+
npm notice unpacked size: 12.2 kB
|
|
17
|
+
npm notice shasum: 688b2601a71193a9e038603eac3b93b2a968395d
|
|
18
|
+
npm notice integrity: sha512-BFBQY6S4fsp8X[...]f6uVO52JbLGeQ==
|
|
19
|
+
npm notice total files: 4
|
|
20
|
+
npm notice
|
|
21
|
+
npm notice Publishing to https://registry.npmjs.org/ with tag latest and default access
|
|
22
|
+
npm error code E403
|
|
23
|
+
npm error 403 403 Forbidden - PUT https://registry.npmjs.org/arustack - Two-factor authentication or granular access token with bypass 2fa enabled is required to publish packages.
|
|
24
|
+
npm error 403 In most cases, you or one of your dependencies are requesting
|
|
25
|
+
npm error 403 a package version that is forbidden by your security policy, or
|
|
26
|
+
npm error 403 on a server you do not have access to.
|
|
27
|
+
npm error A complete log of this run can be found in: C:\Users\Home Office\AppData\Local\npm-cache\_logs\2026-04-02T14_23_26_908Z-debug-0.log
|