create-nxpress-app 1.0.2 → 1.0.3
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/dist/index.js +100 -76
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,27 +12,28 @@ const path_1 = __importDefault(require("path"));
|
|
|
12
12
|
const child_process_1 = require("child_process");
|
|
13
13
|
const program = new commander_1.Command();
|
|
14
14
|
program
|
|
15
|
-
.name(
|
|
16
|
-
.description(
|
|
17
|
-
.argument(
|
|
18
|
-
.option(
|
|
19
|
-
.option(
|
|
20
|
-
.option(
|
|
21
|
-
.option(
|
|
22
|
-
.option(
|
|
23
|
-
.option(
|
|
15
|
+
.name("create-nxpress-app")
|
|
16
|
+
.description("Scaffold a new Nxpress project")
|
|
17
|
+
.argument("[project-directory]", "Directory for the project")
|
|
18
|
+
.option("-e, --engine <engine>", "Template engine (handlebars, ejs, html)")
|
|
19
|
+
.option("-p, --port <number>", "Port number")
|
|
20
|
+
.option("--tailwind", "Include Tailwind CSS support", true)
|
|
21
|
+
.option("--app-dir <dir>", "Directory for application routes")
|
|
22
|
+
.option("--components-dir <dir>", "Directory for components")
|
|
23
|
+
.option("--public-dir <dir>", "Directory for static assets")
|
|
24
|
+
.option("--skip-install", "Skip installing dependencies", false)
|
|
24
25
|
.action(async (projectDirArg, options) => {
|
|
25
26
|
console.log();
|
|
26
|
-
(0, prompts_1.intro)(chalk_1.default.bgCyan.black(
|
|
27
|
+
(0, prompts_1.intro)(chalk_1.default.bgCyan.black(" Create Nxpress App "));
|
|
27
28
|
let projectDir = projectDirArg;
|
|
28
29
|
if (!projectDir) {
|
|
29
30
|
const res = await (0, prompts_1.text)({
|
|
30
|
-
message:
|
|
31
|
-
placeholder:
|
|
32
|
-
defaultValue:
|
|
31
|
+
message: "Where would you like to create your project?",
|
|
32
|
+
placeholder: "my-nxpress-app",
|
|
33
|
+
defaultValue: "my-nxpress-app",
|
|
33
34
|
});
|
|
34
35
|
if ((0, prompts_1.isCancel)(res)) {
|
|
35
|
-
(0, prompts_1.cancel)(
|
|
36
|
+
(0, prompts_1.cancel)("Operation cancelled.");
|
|
36
37
|
process.exit(0);
|
|
37
38
|
}
|
|
38
39
|
projectDir = res;
|
|
@@ -44,66 +45,89 @@ program
|
|
|
44
45
|
initialValue: false,
|
|
45
46
|
});
|
|
46
47
|
if ((0, prompts_1.isCancel)(overwrite) || !overwrite) {
|
|
47
|
-
(0, prompts_1.cancel)(
|
|
48
|
+
(0, prompts_1.cancel)("Operation cancelled.");
|
|
48
49
|
process.exit(0);
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
let engine = options.engine;
|
|
52
|
-
if (!engine || ![
|
|
53
|
+
if (!engine || !["handlebars", "ejs", "html"].includes(engine)) {
|
|
53
54
|
const selectedEngine = await (0, prompts_1.select)({
|
|
54
|
-
message:
|
|
55
|
+
message: "Which template engine do you want to use?",
|
|
55
56
|
options: [
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
{
|
|
58
|
+
value: "handlebars",
|
|
59
|
+
label: "Handlebars (Recommended)",
|
|
60
|
+
hint: "Clean syntax & partials",
|
|
61
|
+
},
|
|
62
|
+
{ value: "ejs", label: "EJS", hint: "Embedded JavaScript templates" },
|
|
63
|
+
{ value: "html", label: "HTML", hint: "Plain HTML templates" },
|
|
59
64
|
],
|
|
60
65
|
});
|
|
61
66
|
if ((0, prompts_1.isCancel)(selectedEngine)) {
|
|
62
|
-
(0, prompts_1.cancel)(
|
|
67
|
+
(0, prompts_1.cancel)("Operation cancelled.");
|
|
63
68
|
process.exit(0);
|
|
64
69
|
}
|
|
65
70
|
engine = selectedEngine;
|
|
66
71
|
}
|
|
72
|
+
let port = options.port ? parseInt(options.port, 10) : 3000;
|
|
73
|
+
if (process.stdin.isTTY && !options.port) {
|
|
74
|
+
const portRes = await (0, prompts_1.text)({
|
|
75
|
+
message: "Port number:",
|
|
76
|
+
placeholder: "3000",
|
|
77
|
+
defaultValue: "3000",
|
|
78
|
+
validate: (val) => !!val && (isNaN(Number(val)) || Number(val) <= 0)
|
|
79
|
+
? "Port must be a valid positive number"
|
|
80
|
+
: undefined,
|
|
81
|
+
});
|
|
82
|
+
if ((0, prompts_1.isCancel)(portRes)) {
|
|
83
|
+
(0, prompts_1.cancel)("Operation cancelled.");
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
port = parseInt(portRes, 10);
|
|
87
|
+
}
|
|
67
88
|
let appDirName = options.appDir;
|
|
68
89
|
let componentsDirName = options.componentsDir;
|
|
69
90
|
let publicDirName = options.publicDir;
|
|
70
|
-
if (process.stdin.isTTY &&
|
|
91
|
+
if (process.stdin.isTTY &&
|
|
92
|
+
!options.appDir &&
|
|
93
|
+
!options.componentsDir &&
|
|
94
|
+
!options.publicDir) {
|
|
71
95
|
const customizeDirs = await (0, prompts_1.confirm)({
|
|
72
|
-
message:
|
|
96
|
+
message: "Do you want to customize directory names?",
|
|
73
97
|
initialValue: false,
|
|
74
98
|
});
|
|
75
99
|
if ((0, prompts_1.isCancel)(customizeDirs)) {
|
|
76
|
-
(0, prompts_1.cancel)(
|
|
100
|
+
(0, prompts_1.cancel)("Operation cancelled.");
|
|
77
101
|
process.exit(0);
|
|
78
102
|
}
|
|
79
103
|
if (customizeDirs) {
|
|
80
104
|
const appRes = await (0, prompts_1.text)({
|
|
81
|
-
message:
|
|
82
|
-
placeholder:
|
|
83
|
-
defaultValue:
|
|
105
|
+
message: "Routes directory name:",
|
|
106
|
+
placeholder: "app",
|
|
107
|
+
defaultValue: "app",
|
|
84
108
|
});
|
|
85
109
|
if ((0, prompts_1.isCancel)(appRes)) {
|
|
86
|
-
(0, prompts_1.cancel)(
|
|
110
|
+
(0, prompts_1.cancel)("Operation cancelled.");
|
|
87
111
|
process.exit(0);
|
|
88
112
|
}
|
|
89
113
|
appDirName = appRes;
|
|
90
114
|
const compRes = await (0, prompts_1.text)({
|
|
91
|
-
message:
|
|
92
|
-
placeholder:
|
|
93
|
-
defaultValue:
|
|
115
|
+
message: "Components directory name:",
|
|
116
|
+
placeholder: "components",
|
|
117
|
+
defaultValue: "components",
|
|
94
118
|
});
|
|
95
119
|
if ((0, prompts_1.isCancel)(compRes)) {
|
|
96
|
-
(0, prompts_1.cancel)(
|
|
120
|
+
(0, prompts_1.cancel)("Operation cancelled.");
|
|
97
121
|
process.exit(0);
|
|
98
122
|
}
|
|
99
123
|
componentsDirName = compRes;
|
|
100
124
|
const pubRes = await (0, prompts_1.text)({
|
|
101
|
-
message:
|
|
102
|
-
placeholder:
|
|
103
|
-
defaultValue:
|
|
125
|
+
message: "Public directory name:",
|
|
126
|
+
placeholder: "public",
|
|
127
|
+
defaultValue: "public",
|
|
104
128
|
});
|
|
105
129
|
if ((0, prompts_1.isCancel)(pubRes)) {
|
|
106
|
-
(0, prompts_1.cancel)(
|
|
130
|
+
(0, prompts_1.cancel)("Operation cancelled.");
|
|
107
131
|
process.exit(0);
|
|
108
132
|
}
|
|
109
133
|
publicDirName = pubRes;
|
|
@@ -112,17 +136,17 @@ program
|
|
|
112
136
|
let shouldInstall = !options.skipInstall;
|
|
113
137
|
if (!options.skipInstall && process.stdin.isTTY) {
|
|
114
138
|
const res = await (0, prompts_1.confirm)({
|
|
115
|
-
message:
|
|
139
|
+
message: "Install dependencies using pnpm?",
|
|
116
140
|
initialValue: true,
|
|
117
141
|
});
|
|
118
142
|
if ((0, prompts_1.isCancel)(res)) {
|
|
119
|
-
(0, prompts_1.cancel)(
|
|
143
|
+
(0, prompts_1.cancel)("Operation cancelled.");
|
|
120
144
|
process.exit(0);
|
|
121
145
|
}
|
|
122
146
|
shouldInstall = res;
|
|
123
147
|
}
|
|
124
148
|
const s = (0, prompts_1.spinner)();
|
|
125
|
-
s.start(
|
|
149
|
+
s.start("Scaffolding project...");
|
|
126
150
|
fs_extra_1.default.ensureDirSync(targetPath);
|
|
127
151
|
// Create app structure with chosen directories
|
|
128
152
|
const appDir = path_1.default.join(targetPath, appDirName);
|
|
@@ -131,9 +155,9 @@ program
|
|
|
131
155
|
fs_extra_1.default.ensureDirSync(appDir);
|
|
132
156
|
fs_extra_1.default.ensureDirSync(componentsDir);
|
|
133
157
|
fs_extra_1.default.ensureDirSync(publicDir);
|
|
134
|
-
const ext = engine ===
|
|
158
|
+
const ext = engine === "handlebars" ? "hbs" : engine;
|
|
135
159
|
// Root layout
|
|
136
|
-
const layoutContent = engine ===
|
|
160
|
+
const layoutContent = engine === "handlebars"
|
|
137
161
|
? `<!DOCTYPE html>
|
|
138
162
|
<html lang="en">
|
|
139
163
|
<head>
|
|
@@ -146,7 +170,7 @@ program
|
|
|
146
170
|
{{{body}}}
|
|
147
171
|
</body>
|
|
148
172
|
</html>`
|
|
149
|
-
: engine ===
|
|
173
|
+
: engine === "ejs"
|
|
150
174
|
? `<!DOCTYPE html>
|
|
151
175
|
<html lang="en">
|
|
152
176
|
<head>
|
|
@@ -173,7 +197,7 @@ program
|
|
|
173
197
|
</html>`;
|
|
174
198
|
fs_extra_1.default.writeFileSync(path_1.default.join(appDir, `layout.${ext}`), layoutContent);
|
|
175
199
|
// Index page
|
|
176
|
-
const indexPageContent = engine ===
|
|
200
|
+
const indexPageContent = engine === "handlebars"
|
|
177
201
|
? `<div class="max-w-4xl mx-auto px-4 py-16 text-center">
|
|
178
202
|
<h1 class="text-5xl font-bold mb-4 bg-gradient-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent">
|
|
179
203
|
Welcome to {{title}}
|
|
@@ -183,7 +207,7 @@ program
|
|
|
183
207
|
<p class="text-sm font-mono text-cyan-400">Edit <span class="text-amber-300">${appDirName}/index.${ext}</span> to get started.</p>
|
|
184
208
|
</div>
|
|
185
209
|
</div>`
|
|
186
|
-
: engine ===
|
|
210
|
+
: engine === "ejs"
|
|
187
211
|
? `<div class="max-w-4xl mx-auto px-4 py-16 text-center">
|
|
188
212
|
<h1 class="text-5xl font-bold mb-4 bg-gradient-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent">
|
|
189
213
|
Welcome to <%= title %>
|
|
@@ -210,90 +234,90 @@ export async function props(req: Request, res: Response) {
|
|
|
210
234
|
};
|
|
211
235
|
}
|
|
212
236
|
`;
|
|
213
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(appDir,
|
|
237
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(appDir, "index.ts"), indexTsContent);
|
|
214
238
|
// App CSS for Tailwind v4
|
|
215
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath,
|
|
239
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "app.css"), `@import "tailwindcss";\n`);
|
|
216
240
|
// Server file
|
|
217
241
|
const serverTsContent = `import { nxpress } from '@nxpress/core';
|
|
218
242
|
|
|
219
243
|
const app = nxpress({
|
|
220
|
-
engine: '${engine ===
|
|
244
|
+
engine: '${engine === "handlebars" ? "hbs" : engine}',
|
|
221
245
|
});
|
|
222
246
|
|
|
223
|
-
const PORT = process.env.PORT ||
|
|
247
|
+
const PORT = process.env.PORT || ${port};
|
|
224
248
|
app.listen(PORT, () => {
|
|
225
249
|
console.log(\`Nxpress server running on http://localhost:\${PORT}\`);
|
|
226
250
|
});
|
|
227
251
|
`;
|
|
228
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath,
|
|
229
|
-
const pkgVersion =
|
|
252
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "server.ts"), serverTsContent);
|
|
253
|
+
const pkgVersion = "1.0.1";
|
|
230
254
|
// nxpress.config.json
|
|
231
255
|
const nxConfig = {
|
|
232
256
|
$schema: `https://unpkg.com/@nxpress/core@${pkgVersion}/schema.json`,
|
|
233
|
-
port
|
|
234
|
-
engine: engine ===
|
|
257
|
+
port,
|
|
258
|
+
engine: engine === "handlebars" ? "hbs" : engine,
|
|
235
259
|
appDir: appDirName,
|
|
236
260
|
componentsDir: componentsDirName,
|
|
237
261
|
publicDir: publicDirName,
|
|
238
262
|
};
|
|
239
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath,
|
|
263
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "nxpress.config.json"), JSON.stringify(nxConfig, null, 2));
|
|
240
264
|
// package.json for target project
|
|
241
265
|
const projectPkgJson = {
|
|
242
266
|
name: path_1.default.basename(targetPath),
|
|
243
|
-
version:
|
|
267
|
+
version: "0.1.0",
|
|
244
268
|
private: true,
|
|
245
269
|
scripts: {
|
|
246
|
-
dev:
|
|
247
|
-
build:
|
|
248
|
-
start:
|
|
270
|
+
dev: "nxpress dev",
|
|
271
|
+
build: "tsc",
|
|
272
|
+
start: "nxpress start",
|
|
249
273
|
},
|
|
250
274
|
dependencies: {
|
|
251
|
-
|
|
252
|
-
...(engine ===
|
|
253
|
-
...(engine ===
|
|
275
|
+
"@nxpress/core": `^${pkgVersion}`,
|
|
276
|
+
...(engine === "handlebars" ? { hbs: "^4.2.0" } : {}),
|
|
277
|
+
...(engine === "ejs" ? { ejs: "^3.1.10" } : {}),
|
|
254
278
|
},
|
|
255
279
|
devDependencies: {
|
|
256
|
-
typescript:
|
|
257
|
-
|
|
258
|
-
|
|
280
|
+
typescript: "^5.3.3",
|
|
281
|
+
"@types/node": "^20.11.24",
|
|
282
|
+
"@types/express": "^4.17.21",
|
|
259
283
|
},
|
|
260
284
|
};
|
|
261
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath,
|
|
285
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "package.json"), JSON.stringify(projectPkgJson, null, 2));
|
|
262
286
|
// tsconfig.json for target project
|
|
263
287
|
const projectTsConfig = {
|
|
264
288
|
compilerOptions: {
|
|
265
|
-
target:
|
|
266
|
-
module:
|
|
267
|
-
moduleResolution:
|
|
289
|
+
target: "ES2022",
|
|
290
|
+
module: "CommonJS",
|
|
291
|
+
moduleResolution: "node",
|
|
268
292
|
strict: true,
|
|
269
293
|
esModuleInterop: true,
|
|
270
294
|
skipLibCheck: true,
|
|
271
295
|
},
|
|
272
|
-
include: [
|
|
296
|
+
include: ["**/*"],
|
|
273
297
|
};
|
|
274
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath,
|
|
298
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "tsconfig.json"), JSON.stringify(projectTsConfig, null, 2));
|
|
275
299
|
// .gitignore
|
|
276
300
|
const gitignoreContent = `node_modules
|
|
277
301
|
dist
|
|
278
302
|
.env
|
|
279
303
|
*.log
|
|
280
304
|
`;
|
|
281
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath,
|
|
282
|
-
s.stop(
|
|
305
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, ".gitignore"), gitignoreContent);
|
|
306
|
+
s.stop("Project structure created successfully.");
|
|
283
307
|
if (shouldInstall) {
|
|
284
308
|
const instSpinner = (0, prompts_1.spinner)();
|
|
285
|
-
instSpinner.start(
|
|
309
|
+
instSpinner.start("Installing dependencies with pnpm...");
|
|
286
310
|
try {
|
|
287
|
-
(0, child_process_1.execSync)(
|
|
288
|
-
instSpinner.stop(
|
|
311
|
+
(0, child_process_1.execSync)("pnpm install", { cwd: targetPath, stdio: "ignore" });
|
|
312
|
+
instSpinner.stop("Dependencies installed successfully.");
|
|
289
313
|
}
|
|
290
314
|
catch (err) {
|
|
291
|
-
instSpinner.stop(
|
|
315
|
+
instSpinner.stop("Failed to install dependencies automatically.");
|
|
292
316
|
}
|
|
293
317
|
}
|
|
294
318
|
(0, prompts_1.outro)(`Project created in ${chalk_1.default.cyan(projectDir)}!\n\n` +
|
|
295
319
|
`Next steps:\n` +
|
|
296
320
|
` ${chalk_1.default.cyan(`cd ${projectDir}`)}\n` +
|
|
297
|
-
` ${chalk_1.default.cyan(
|
|
321
|
+
` ${chalk_1.default.cyan("pnpm dev")}`);
|
|
298
322
|
});
|
|
299
323
|
program.parse(process.argv);
|