create-nxpress-app 1.0.2 → 1.0.4
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 +101 -80
- 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
|
}
|
|
67
|
-
let
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
+
}
|
|
88
|
+
let appDirName = options.appDir || "app";
|
|
89
|
+
let componentsDirName = options.componentsDir || "components";
|
|
90
|
+
let publicDirName = options.publicDir || "public";
|
|
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 %>
|
|
@@ -201,7 +225,7 @@ program
|
|
|
201
225
|
</div>`;
|
|
202
226
|
fs_extra_1.default.writeFileSync(path_1.default.join(appDir, `index.${ext}`), indexPageContent);
|
|
203
227
|
// Data loader for index page
|
|
204
|
-
const indexTsContent = `import { Request, Response } from '
|
|
228
|
+
const indexTsContent = `import type { Request, Response } from '@nxpress/core';
|
|
205
229
|
|
|
206
230
|
export async function props(req: Request, res: Response) {
|
|
207
231
|
return {
|
|
@@ -210,90 +234,87 @@ 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.4";
|
|
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 === 'handlebars' ? { hbs: '^4.2.0' } : {}),
|
|
253
|
-
...(engine === 'ejs' ? { ejs: '^3.1.10' } : {}),
|
|
275
|
+
"@nxpress/core": `^${pkgVersion}`,
|
|
254
276
|
},
|
|
255
277
|
devDependencies: {
|
|
256
|
-
typescript:
|
|
257
|
-
|
|
258
|
-
'@types/express': '^4.17.21',
|
|
278
|
+
typescript: "^5.3.3",
|
|
279
|
+
"@types/node": "^20.11.24",
|
|
259
280
|
},
|
|
260
281
|
};
|
|
261
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath,
|
|
282
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "package.json"), JSON.stringify(projectPkgJson, null, 2));
|
|
262
283
|
// tsconfig.json for target project
|
|
263
284
|
const projectTsConfig = {
|
|
264
285
|
compilerOptions: {
|
|
265
|
-
target:
|
|
266
|
-
module:
|
|
267
|
-
moduleResolution:
|
|
286
|
+
target: "ES2022",
|
|
287
|
+
module: "CommonJS",
|
|
288
|
+
moduleResolution: "node",
|
|
268
289
|
strict: true,
|
|
269
290
|
esModuleInterop: true,
|
|
270
291
|
skipLibCheck: true,
|
|
271
292
|
},
|
|
272
|
-
include: [
|
|
293
|
+
include: ["**/*"],
|
|
273
294
|
};
|
|
274
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath,
|
|
295
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "tsconfig.json"), JSON.stringify(projectTsConfig, null, 2));
|
|
275
296
|
// .gitignore
|
|
276
297
|
const gitignoreContent = `node_modules
|
|
277
298
|
dist
|
|
278
299
|
.env
|
|
279
300
|
*.log
|
|
280
301
|
`;
|
|
281
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath,
|
|
282
|
-
s.stop(
|
|
302
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, ".gitignore"), gitignoreContent);
|
|
303
|
+
s.stop("Project structure created successfully.");
|
|
283
304
|
if (shouldInstall) {
|
|
284
305
|
const instSpinner = (0, prompts_1.spinner)();
|
|
285
|
-
instSpinner.start(
|
|
306
|
+
instSpinner.start("Installing dependencies with pnpm...");
|
|
286
307
|
try {
|
|
287
|
-
(0, child_process_1.execSync)(
|
|
288
|
-
instSpinner.stop(
|
|
308
|
+
(0, child_process_1.execSync)("pnpm install", { cwd: targetPath, stdio: "ignore" });
|
|
309
|
+
instSpinner.stop("Dependencies installed successfully.");
|
|
289
310
|
}
|
|
290
311
|
catch (err) {
|
|
291
|
-
instSpinner.stop(
|
|
312
|
+
instSpinner.stop("Failed to install dependencies automatically.");
|
|
292
313
|
}
|
|
293
314
|
}
|
|
294
315
|
(0, prompts_1.outro)(`Project created in ${chalk_1.default.cyan(projectDir)}!\n\n` +
|
|
295
316
|
`Next steps:\n` +
|
|
296
317
|
` ${chalk_1.default.cyan(`cd ${projectDir}`)}\n` +
|
|
297
|
-
` ${chalk_1.default.cyan(
|
|
318
|
+
` ${chalk_1.default.cyan("pnpm dev")}`);
|
|
298
319
|
});
|
|
299
320
|
program.parse(process.argv);
|