@rellcodes16/devkit 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 +128 -0
- package/bin/devkit.js +55 -0
- package/package.json +42 -0
- package/src/commands/createNode.js +219 -0
- package/src/commands/createReact.js +124 -0
- package/src/templates/node/index.js +666 -0
- package/src/templates/react/index.js +172 -0
- package/src/utils.js +40 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
export function reactAppJsx(appname, options) {
|
|
2
|
+
const imports = [];
|
|
3
|
+
const routerImport = options.router
|
|
4
|
+
? `import { BrowserRouter, Routes, Route } from "react-router-dom";`
|
|
5
|
+
: "";
|
|
6
|
+
|
|
7
|
+
if (routerImport) imports.push(routerImport);
|
|
8
|
+
|
|
9
|
+
const homeComponent = `
|
|
10
|
+
function Home() {
|
|
11
|
+
return (
|
|
12
|
+
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
|
13
|
+
<div className="text-center">
|
|
14
|
+
<h1 className="text-4xl font-bold text-gray-900 mb-2">${appname}</h1>
|
|
15
|
+
<p className="text-gray-500">Your app is ready. Start building.</p>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}`;
|
|
20
|
+
|
|
21
|
+
const simpleBody = `
|
|
22
|
+
return (
|
|
23
|
+
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
|
24
|
+
<div className="text-center">
|
|
25
|
+
<h1 className="text-4xl font-bold text-gray-900 mb-2">${appname}</h1>
|
|
26
|
+
<p className="text-gray-500">Your app is ready. Start building.</p>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
);`;
|
|
30
|
+
|
|
31
|
+
const routerBody = `
|
|
32
|
+
return (
|
|
33
|
+
<BrowserRouter>
|
|
34
|
+
<Routes>
|
|
35
|
+
<Route path="/" element={<Home />} />
|
|
36
|
+
</Routes>
|
|
37
|
+
</BrowserRouter>
|
|
38
|
+
);`;
|
|
39
|
+
|
|
40
|
+
const body = options.router ? routerBody : simpleBody;
|
|
41
|
+
const extras = options.router ? homeComponent : "";
|
|
42
|
+
|
|
43
|
+
return `${imports.join("\n")}
|
|
44
|
+
${extras}
|
|
45
|
+
export default function App() {${body}
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function reactIndexCss() {
|
|
51
|
+
return `@import "tailwindcss";
|
|
52
|
+
|
|
53
|
+
/* Custom base styles */
|
|
54
|
+
*, *::before, *::after {
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
body {
|
|
59
|
+
margin: 0;
|
|
60
|
+
font-family: Inter, system-ui, -apple-system, sans-serif;
|
|
61
|
+
-webkit-font-smoothing: antialiased;
|
|
62
|
+
-moz-osx-font-smoothing: grayscale;
|
|
63
|
+
}
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function reactViteConfig() {
|
|
68
|
+
return `import { defineConfig } from "vite";
|
|
69
|
+
import react from "@vitejs/plugin-react";
|
|
70
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
71
|
+
|
|
72
|
+
export default defineConfig({
|
|
73
|
+
plugins: [react(), tailwindcss()],
|
|
74
|
+
});
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function reactGitignore() {
|
|
79
|
+
return `node_modules/
|
|
80
|
+
dist/
|
|
81
|
+
.env
|
|
82
|
+
.env.local
|
|
83
|
+
*.log
|
|
84
|
+
.DS_Store
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function reactEnv() {
|
|
89
|
+
return `VITE_API_URL=http://localhost:3000/api
|
|
90
|
+
`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function reactApiUtil() {
|
|
94
|
+
return `import axios from "axios";
|
|
95
|
+
|
|
96
|
+
const api = axios.create({
|
|
97
|
+
baseURL: import.meta.env.VITE_API_URL,
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Request interceptor — attach auth tokens, etc.
|
|
104
|
+
api.interceptors.request.use(
|
|
105
|
+
(config) => {
|
|
106
|
+
// const token = localStorage.getItem("token");
|
|
107
|
+
// if (token) config.headers.Authorization = \`Bearer \${token}\`;
|
|
108
|
+
return config;
|
|
109
|
+
},
|
|
110
|
+
(error) => Promise.reject(error)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// Response interceptor — handle global errors
|
|
114
|
+
api.interceptors.response.use(
|
|
115
|
+
(response) => response,
|
|
116
|
+
(error) => {
|
|
117
|
+
if (error.response?.status === 401) {
|
|
118
|
+
// Handle unauthorized — e.g. redirect to login
|
|
119
|
+
}
|
|
120
|
+
return Promise.reject(error);
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
export default api;
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function reactReadme(appname, options) {
|
|
129
|
+
const stackLines = [
|
|
130
|
+
"- React + Vite",
|
|
131
|
+
"- Tailwind CSS v4",
|
|
132
|
+
"- Lucide React (icons)",
|
|
133
|
+
"- clsx",
|
|
134
|
+
];
|
|
135
|
+
if (options.router) stackLines.push("- React Router DOM");
|
|
136
|
+
if (options.axios) stackLines.push("- Axios (pre-configured client)");
|
|
137
|
+
|
|
138
|
+
return `# ${appname}
|
|
139
|
+
|
|
140
|
+
Scaffolded with [devkit](https://github.com/rellcodes16/devkit).
|
|
141
|
+
|
|
142
|
+
## Stack
|
|
143
|
+
|
|
144
|
+
${stackLines.join("\n")}
|
|
145
|
+
|
|
146
|
+
## Getting started
|
|
147
|
+
|
|
148
|
+
\`\`\`bash
|
|
149
|
+
cp .env.example .env
|
|
150
|
+
npm run dev
|
|
151
|
+
\`\`\`
|
|
152
|
+
|
|
153
|
+
## Project structure
|
|
154
|
+
|
|
155
|
+
\`\`\`
|
|
156
|
+
src/
|
|
157
|
+
components/ # Reusable UI components
|
|
158
|
+
pages/ # Page-level components
|
|
159
|
+
hooks/ # Custom React hooks
|
|
160
|
+
utils/ # Helper functions${options.axios ? "\n api.js # Pre-configured axios instance" : ""}
|
|
161
|
+
assets/ # Static assets
|
|
162
|
+
App.jsx # Root component
|
|
163
|
+
main.jsx # Entry point
|
|
164
|
+
\`\`\`
|
|
165
|
+
|
|
166
|
+
## Environment variables
|
|
167
|
+
|
|
168
|
+
| Variable | Description |
|
|
169
|
+
|---|---|
|
|
170
|
+
| \`VITE_API_URL\` | Backend API base URL |
|
|
171
|
+
`;
|
|
172
|
+
}
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import kleur from "kleur";
|
|
3
|
+
|
|
4
|
+
export function printStep(message) {
|
|
5
|
+
console.log(` ${kleur.gray(message)}`);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function printSuccess(message) {
|
|
9
|
+
console.log(`\n ${kleur.green("✔")} ${kleur.green(message)}`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function printError(message) {
|
|
13
|
+
console.error(`\n ${kleur.red("✖")} ${kleur.red(message)}\n`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function printDivider() {
|
|
17
|
+
console.log(kleur.gray(" ─────────────────────────────────────────"));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function runCommand(cmd, args, cwd, label) {
|
|
21
|
+
printStep(label);
|
|
22
|
+
try {
|
|
23
|
+
await execa(cmd, args, { cwd, stdio: "pipe" });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
printError(`Failed: ${label}`);
|
|
26
|
+
console.error(err.stderr || err.message);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function printDoneMessage(appname, devCmd, extraLines = []) {
|
|
32
|
+
console.log(`
|
|
33
|
+
${kleur.bold().green("Project ready!")}
|
|
34
|
+
|
|
35
|
+
${kleur.gray("Next steps:")}
|
|
36
|
+
${kleur.cyan(`cd ${appname}`)}
|
|
37
|
+
${kleur.cyan(devCmd)}
|
|
38
|
+
${extraLines.map((l) => ` ${kleur.gray(l)}`).join("\n")}
|
|
39
|
+
`);
|
|
40
|
+
}
|