create-avalon 0.1.24 → 0.1.25
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 +2 -0
- package/dist/cli.js +316 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ The CLI walks you through:
|
|
|
22
22
|
- Framework selection (React, Preact, Vue, Svelte, Solid, Lit, Qwik — or multiple)
|
|
23
23
|
- Styling approach (CSS Modules, Tailwind, vanilla CSS)
|
|
24
24
|
- Optional features (API routes, middleware, layouts, MDX)
|
|
25
|
+
- Scheduled jobs (cron) — scaffolds an example task and wires up `nitro.cron`
|
|
25
26
|
- Package manager preference
|
|
26
27
|
|
|
27
28
|
## What you get
|
|
@@ -43,6 +44,7 @@ my-project/
|
|
|
43
44
|
├── middleware/ # Server middleware
|
|
44
45
|
├── routes/
|
|
45
46
|
│ └── api/ # API routes
|
|
47
|
+
├── tasks/ # Scheduled jobs (cron) — optional
|
|
46
48
|
├── server/ # Server config & env
|
|
47
49
|
├── public/ # Static assets
|
|
48
50
|
├── vite.config.ts
|
package/dist/cli.js
CHANGED
|
@@ -76,12 +76,65 @@ var require_src = __commonJS((exports, module) => {
|
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
// src/cli.ts
|
|
79
|
-
import { basename, resolve } from "node:path";
|
|
80
79
|
import { createRequire } from "node:module";
|
|
80
|
+
import { basename, resolve } from "node:path";
|
|
81
81
|
|
|
82
82
|
// src/cli-utils.ts
|
|
83
|
-
import { parseArgs } from "node:util";
|
|
84
83
|
import { existsSync, readdirSync } from "node:fs";
|
|
84
|
+
import { parseArgs } from "node:util";
|
|
85
|
+
|
|
86
|
+
// src/types.ts
|
|
87
|
+
var RENDER_ENGINES = ["preact", "react"];
|
|
88
|
+
var INTEGRATIONS = [
|
|
89
|
+
"preact",
|
|
90
|
+
"react",
|
|
91
|
+
"vue",
|
|
92
|
+
"svelte",
|
|
93
|
+
"solid",
|
|
94
|
+
"lit",
|
|
95
|
+
"qwik"
|
|
96
|
+
];
|
|
97
|
+
var STYLING_OPTIONS = [
|
|
98
|
+
"css-modules",
|
|
99
|
+
"tailwind",
|
|
100
|
+
"shadcn"
|
|
101
|
+
];
|
|
102
|
+
var PLUGINS = [
|
|
103
|
+
"seo",
|
|
104
|
+
"agent-optimization",
|
|
105
|
+
"syntax-highlighting"
|
|
106
|
+
];
|
|
107
|
+
var MIDDLEWARE_OPTIONS = [
|
|
108
|
+
"h3",
|
|
109
|
+
"hono",
|
|
110
|
+
"elysia"
|
|
111
|
+
];
|
|
112
|
+
var DEPLOY_TARGETS = ["netlify", "none"];
|
|
113
|
+
var INTEGRATION_PACKAGES = {
|
|
114
|
+
preact: "@useavalon/preact",
|
|
115
|
+
react: "@useavalon/react",
|
|
116
|
+
vue: "@useavalon/vue",
|
|
117
|
+
svelte: "@useavalon/svelte",
|
|
118
|
+
solid: "@useavalon/solid",
|
|
119
|
+
lit: "@useavalon/lit",
|
|
120
|
+
qwik: "@useavalon/qwik"
|
|
121
|
+
};
|
|
122
|
+
var BASE_DIRS = [
|
|
123
|
+
"app/modules/main/pages",
|
|
124
|
+
"app/modules/main/components",
|
|
125
|
+
"app/modules/main/layouts",
|
|
126
|
+
"app/shared/layouts",
|
|
127
|
+
"app/shared/components",
|
|
128
|
+
"app/shared/styles",
|
|
129
|
+
"middleware",
|
|
130
|
+
"routes/api",
|
|
131
|
+
"public",
|
|
132
|
+
"server"
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
// src/cli-utils.ts
|
|
136
|
+
class CliArgError extends Error {
|
|
137
|
+
}
|
|
85
138
|
function validateDirectory(dir) {
|
|
86
139
|
if (!existsSync(dir)) {
|
|
87
140
|
return { valid: true };
|
|
@@ -100,7 +153,15 @@ function parseCliArgs(argv) {
|
|
|
100
153
|
args: argv,
|
|
101
154
|
options: {
|
|
102
155
|
help: { type: "boolean", default: false, short: "h" },
|
|
103
|
-
version: { type: "boolean", default: false, short: "v" }
|
|
156
|
+
version: { type: "boolean", default: false, short: "v" },
|
|
157
|
+
yes: { type: "boolean", default: false, short: "y" },
|
|
158
|
+
core: { type: "string" },
|
|
159
|
+
integrations: { type: "string" },
|
|
160
|
+
styling: { type: "string" },
|
|
161
|
+
plugins: { type: "string" },
|
|
162
|
+
middleware: { type: "string" },
|
|
163
|
+
deploy: { type: "string" },
|
|
164
|
+
cron: { type: "boolean", default: false }
|
|
104
165
|
},
|
|
105
166
|
strict: true,
|
|
106
167
|
allowPositionals: true
|
|
@@ -108,7 +169,58 @@ function parseCliArgs(argv) {
|
|
|
108
169
|
return {
|
|
109
170
|
projectName: positionals[0] ?? undefined,
|
|
110
171
|
help: values.help ?? false,
|
|
111
|
-
version: values.version ?? false
|
|
172
|
+
version: values.version ?? false,
|
|
173
|
+
yes: values.yes ?? false,
|
|
174
|
+
core: values.core,
|
|
175
|
+
integrations: values.integrations,
|
|
176
|
+
styling: values.styling,
|
|
177
|
+
plugins: values.plugins,
|
|
178
|
+
middleware: values.middleware,
|
|
179
|
+
deploy: values.deploy,
|
|
180
|
+
cron: values.cron ?? false
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
var csv = (value) => value ? value.split(",").map((v) => v.trim()).filter(Boolean) : undefined;
|
|
184
|
+
function assertOneOf(value, allowed, flag) {
|
|
185
|
+
if (value === undefined)
|
|
186
|
+
return;
|
|
187
|
+
if (!allowed.includes(value)) {
|
|
188
|
+
throw new CliArgError(`Invalid value "${value}" for --${flag}. Allowed: ${allowed.join(", ")}.`);
|
|
189
|
+
}
|
|
190
|
+
return value;
|
|
191
|
+
}
|
|
192
|
+
function assertAllOf(values, allowed, flag) {
|
|
193
|
+
if (values === undefined)
|
|
194
|
+
return;
|
|
195
|
+
for (const value of values) {
|
|
196
|
+
if (!allowed.includes(value)) {
|
|
197
|
+
throw new CliArgError(`Invalid value "${value}" for --${flag}. Allowed: ${allowed.join(", ")}.`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return values;
|
|
201
|
+
}
|
|
202
|
+
function resolveConfigNonInteractive(args) {
|
|
203
|
+
const core = assertOneOf(args.core, RENDER_ENGINES, "core") ?? "preact";
|
|
204
|
+
const integrations = assertAllOf(csv(args.integrations), INTEGRATIONS, "integrations") ?? [];
|
|
205
|
+
const styling = assertOneOf(args.styling, STYLING_OPTIONS, "styling") ?? "css-modules";
|
|
206
|
+
const plugins = assertAllOf(csv(args.plugins), PLUGINS, "plugins") ?? ["seo"];
|
|
207
|
+
const middleware = assertOneOf(args.middleware, MIDDLEWARE_OPTIONS, "middleware") ?? "h3";
|
|
208
|
+
const deploy = assertOneOf(args.deploy, DEPLOY_TARGETS, "deploy") ?? "none";
|
|
209
|
+
if (styling === "shadcn" && core !== "react") {
|
|
210
|
+
throw new CliArgError("--styling=shadcn requires --core=react (shadcn is Radix/React based).");
|
|
211
|
+
}
|
|
212
|
+
if (core === "react" && !integrations.includes("react")) {
|
|
213
|
+
integrations.push("react");
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
projectName: args.projectName ?? ".",
|
|
217
|
+
core,
|
|
218
|
+
integrations,
|
|
219
|
+
styling,
|
|
220
|
+
plugins,
|
|
221
|
+
middleware,
|
|
222
|
+
deploy,
|
|
223
|
+
cron: args.cron
|
|
112
224
|
};
|
|
113
225
|
}
|
|
114
226
|
|
|
@@ -543,6 +655,25 @@ class Vt extends B {
|
|
|
543
655
|
}
|
|
544
656
|
}
|
|
545
657
|
}
|
|
658
|
+
|
|
659
|
+
class kt extends B {
|
|
660
|
+
get cursor() {
|
|
661
|
+
return this.value ? 0 : 1;
|
|
662
|
+
}
|
|
663
|
+
get _value() {
|
|
664
|
+
return this.cursor === 0;
|
|
665
|
+
}
|
|
666
|
+
constructor(e) {
|
|
667
|
+
super(e, false), this.value = !!e.initialValue, this.on("userInput", () => {
|
|
668
|
+
this.value = this._value;
|
|
669
|
+
}), this.on("confirm", (s) => {
|
|
670
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = s, this.state = "submit", this.close();
|
|
671
|
+
}), this.on("cursor", () => {
|
|
672
|
+
this.value = !this.value;
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
546
677
|
class yt extends B {
|
|
547
678
|
options;
|
|
548
679
|
cursor = 0;
|
|
@@ -961,6 +1092,33 @@ var X2 = ({ cursor: e, options: r, style: s, output: i = process.stdout, maxItem
|
|
|
961
1092
|
C.push(b);
|
|
962
1093
|
return $ && C.push(c), C;
|
|
963
1094
|
};
|
|
1095
|
+
var Rt = (e) => {
|
|
1096
|
+
const r = e.active ?? "Yes", s = e.inactive ?? "No";
|
|
1097
|
+
return new kt({ active: r, inactive: s, signal: e.signal, input: e.input, output: e.output, initialValue: e.initialValue ?? true, render() {
|
|
1098
|
+
const i = e.withGuide ?? _.withGuide, a = `${i ? `${t("gray", h)}
|
|
1099
|
+
` : ""}${W2(this.state)} ${e.message}
|
|
1100
|
+
`, o = this.value ? r : s;
|
|
1101
|
+
switch (this.state) {
|
|
1102
|
+
case "submit": {
|
|
1103
|
+
const u = i ? `${t("gray", h)} ` : "";
|
|
1104
|
+
return `${a}${u}${t("dim", o)}`;
|
|
1105
|
+
}
|
|
1106
|
+
case "cancel": {
|
|
1107
|
+
const u = i ? `${t("gray", h)} ` : "";
|
|
1108
|
+
return `${a}${u}${t(["strikethrough", "dim"], o)}${i ? `
|
|
1109
|
+
${t("gray", h)}` : ""}`;
|
|
1110
|
+
}
|
|
1111
|
+
default: {
|
|
1112
|
+
const u = i ? `${t("cyan", h)} ` : "", l = i ? t("cyan", x2) : "";
|
|
1113
|
+
return `${a}${u}${this.value ? `${t("green", z2)} ${r}` : `${t("dim", H2)} ${t("dim", r)}`}${e.vertical ? i ? `
|
|
1114
|
+
${t("cyan", h)} ` : `
|
|
1115
|
+
` : ` ${t("dim", "/")} `}${this.value ? `${t("dim", H2)} ${t("dim", s)}` : `${t("green", z2)} ${s}`}
|
|
1116
|
+
${l}
|
|
1117
|
+
`;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
} }).prompt();
|
|
1121
|
+
};
|
|
964
1122
|
var Nt = (e = "", r) => {
|
|
965
1123
|
const s = r?.output ?? process.stdout, i = r?.withGuide ?? _.withGuide ? `${t("gray", x2)} ` : "";
|
|
966
1124
|
s.write(`${i}${t("red", e)}
|
|
@@ -1124,6 +1282,26 @@ async function collectProjectConfig(initialName) {
|
|
|
1124
1282
|
}
|
|
1125
1283
|
projectName = nameResult;
|
|
1126
1284
|
}
|
|
1285
|
+
const coreResult = await Jt({
|
|
1286
|
+
message: "Which rendering engine should render your pages (the shell)?",
|
|
1287
|
+
options: [
|
|
1288
|
+
{
|
|
1289
|
+
value: "preact",
|
|
1290
|
+
label: "Preact",
|
|
1291
|
+
hint: "Smallest runtime (default). React libs run via preact/compat."
|
|
1292
|
+
},
|
|
1293
|
+
{
|
|
1294
|
+
value: "react",
|
|
1295
|
+
label: "React",
|
|
1296
|
+
hint: "Real react-dom/server. React libs like Radix/shadcn work natively."
|
|
1297
|
+
}
|
|
1298
|
+
],
|
|
1299
|
+
initialValue: "preact"
|
|
1300
|
+
});
|
|
1301
|
+
if (Ct(coreResult)) {
|
|
1302
|
+
Nt("Operation cancelled.");
|
|
1303
|
+
process.exit(1);
|
|
1304
|
+
}
|
|
1127
1305
|
const integrationsResult = await Lt2({
|
|
1128
1306
|
message: "Which integrations would you like to include? (use space to toggle, enter to confirm)",
|
|
1129
1307
|
options: [
|
|
@@ -1141,13 +1319,20 @@ async function collectProjectConfig(initialName) {
|
|
|
1141
1319
|
Nt("Operation cancelled.");
|
|
1142
1320
|
process.exit(1);
|
|
1143
1321
|
}
|
|
1322
|
+
const stylingOptions = [
|
|
1323
|
+
{ value: "css-modules", label: "CSS Modules" },
|
|
1324
|
+
{ value: "tailwind", label: "Tailwind CSS" }
|
|
1325
|
+
];
|
|
1326
|
+
if (coreResult === "react") {
|
|
1327
|
+
stylingOptions.push({
|
|
1328
|
+
value: "shadcn",
|
|
1329
|
+
label: "shadcn",
|
|
1330
|
+
hint: "Radix-based components — requires the React engine"
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1144
1333
|
const stylingResult = await Jt({
|
|
1145
1334
|
message: "Which styling approach would you like to use?",
|
|
1146
|
-
options:
|
|
1147
|
-
{ value: "css-modules", label: "CSS Modules" },
|
|
1148
|
-
{ value: "tailwind", label: "Tailwind CSS" },
|
|
1149
|
-
{ value: "shadcn", label: "shadcn" }
|
|
1150
|
-
]
|
|
1335
|
+
options: stylingOptions
|
|
1151
1336
|
});
|
|
1152
1337
|
if (Ct(stylingResult)) {
|
|
1153
1338
|
Nt("Operation cancelled.");
|
|
@@ -1156,8 +1341,16 @@ async function collectProjectConfig(initialName) {
|
|
|
1156
1341
|
const pluginsResult = await Lt2({
|
|
1157
1342
|
message: "Which plugins would you like to include? (use space to toggle, enter to confirm)",
|
|
1158
1343
|
options: [
|
|
1159
|
-
{
|
|
1160
|
-
|
|
1344
|
+
{
|
|
1345
|
+
value: "seo",
|
|
1346
|
+
label: "seo",
|
|
1347
|
+
hint: "Auto-injects OG, Twitter cards, JSON-LD, canonical URLs"
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
value: "agent-optimization",
|
|
1351
|
+
label: "agent-optimization",
|
|
1352
|
+
hint: "LLM/AI optimization (llms.txt, markdown, sitemap)"
|
|
1353
|
+
},
|
|
1161
1354
|
{
|
|
1162
1355
|
value: "syntax-highlighting",
|
|
1163
1356
|
label: "syntax-highlighting",
|
|
@@ -1186,7 +1379,11 @@ async function collectProjectConfig(initialName) {
|
|
|
1186
1379
|
const deployResult = await Jt({
|
|
1187
1380
|
message: "Where will you deploy?",
|
|
1188
1381
|
options: [
|
|
1189
|
-
{
|
|
1382
|
+
{
|
|
1383
|
+
value: "netlify",
|
|
1384
|
+
label: "Netlify",
|
|
1385
|
+
hint: "Generates netlify.toml, build.mjs, post-build.mjs"
|
|
1386
|
+
},
|
|
1190
1387
|
{ value: "none", label: "None / Other", hint: "Node server preset, no deploy config" }
|
|
1191
1388
|
]
|
|
1192
1389
|
});
|
|
@@ -1194,13 +1391,28 @@ async function collectProjectConfig(initialName) {
|
|
|
1194
1391
|
Nt("Operation cancelled.");
|
|
1195
1392
|
process.exit(1);
|
|
1196
1393
|
}
|
|
1394
|
+
const cronResult = await Rt({
|
|
1395
|
+
message: "Set up scheduled jobs (cron)?",
|
|
1396
|
+
initialValue: false
|
|
1397
|
+
});
|
|
1398
|
+
if (Ct(cronResult)) {
|
|
1399
|
+
Nt("Operation cancelled.");
|
|
1400
|
+
process.exit(1);
|
|
1401
|
+
}
|
|
1402
|
+
const core = coreResult;
|
|
1403
|
+
const integrations = integrationsResult;
|
|
1404
|
+
if (core === "react" && !integrations.includes("react")) {
|
|
1405
|
+
integrations.push("react");
|
|
1406
|
+
}
|
|
1197
1407
|
return {
|
|
1198
1408
|
projectName,
|
|
1199
|
-
|
|
1409
|
+
core,
|
|
1410
|
+
integrations,
|
|
1200
1411
|
styling: stylingResult,
|
|
1201
1412
|
plugins: pluginsResult,
|
|
1202
1413
|
middleware: middlewareResult,
|
|
1203
|
-
deploy: deployResult
|
|
1414
|
+
deploy: deployResult,
|
|
1415
|
+
cron: cronResult
|
|
1204
1416
|
};
|
|
1205
1417
|
}
|
|
1206
1418
|
|
|
@@ -1218,6 +1430,31 @@ export default defineHandler(() => {
|
|
|
1218
1430
|
`;
|
|
1219
1431
|
}
|
|
1220
1432
|
|
|
1433
|
+
// src/templates/cron.ts
|
|
1434
|
+
var EXAMPLE_CRON_HANDLER = "tasks/cleanup.ts";
|
|
1435
|
+
var EXAMPLE_CRON_SCHEDULE = "0 * * * *";
|
|
1436
|
+
function generateExampleCronTask(_config) {
|
|
1437
|
+
return `import { defineCronJob } from '@useavalon/avalon/cron';
|
|
1438
|
+
|
|
1439
|
+
/**
|
|
1440
|
+
* Example scheduled job. Runs on the schedule defined in vite.config.ts
|
|
1441
|
+
* (\`nitro.cron\`). The task name is derived from this file path: "cleanup".
|
|
1442
|
+
*
|
|
1443
|
+
* In production this runs via your deployment preset's scheduler
|
|
1444
|
+
* (Vercel Cron, Cloudflare Triggers, or the Node server's in-process
|
|
1445
|
+
* scheduler). In development Avalon runs it inside the Vite dev server.
|
|
1446
|
+
*/
|
|
1447
|
+
export default defineCronJob({
|
|
1448
|
+
meta: { description: 'Example scheduled job' },
|
|
1449
|
+
async run() {
|
|
1450
|
+
console.log('[cron] cleanup ran at', new Date().toISOString());
|
|
1451
|
+
// TODO: replace with your scheduled work.
|
|
1452
|
+
return { result: 'ok' };
|
|
1453
|
+
},
|
|
1454
|
+
});
|
|
1455
|
+
`;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1221
1458
|
// src/templates/deploy.ts
|
|
1222
1459
|
function generateNetlifyToml(_config) {
|
|
1223
1460
|
return `[build]
|
|
@@ -1453,36 +1690,28 @@ export default defineHandler((event) => {
|
|
|
1453
1690
|
`;
|
|
1454
1691
|
}
|
|
1455
1692
|
|
|
1456
|
-
// src/types.ts
|
|
1457
|
-
var INTEGRATION_PACKAGES = {
|
|
1458
|
-
preact: "@useavalon/preact",
|
|
1459
|
-
react: "@useavalon/react",
|
|
1460
|
-
vue: "@useavalon/vue",
|
|
1461
|
-
svelte: "@useavalon/svelte",
|
|
1462
|
-
solid: "@useavalon/solid",
|
|
1463
|
-
lit: "@useavalon/lit",
|
|
1464
|
-
qwik: "@useavalon/qwik"
|
|
1465
|
-
};
|
|
1466
|
-
var BASE_DIRS = [
|
|
1467
|
-
"app/modules/main/pages",
|
|
1468
|
-
"app/modules/main/components",
|
|
1469
|
-
"app/modules/main/layouts",
|
|
1470
|
-
"app/shared/layouts",
|
|
1471
|
-
"app/shared/components",
|
|
1472
|
-
"app/shared/styles",
|
|
1473
|
-
"middleware",
|
|
1474
|
-
"routes/api",
|
|
1475
|
-
"public",
|
|
1476
|
-
"server"
|
|
1477
|
-
];
|
|
1478
|
-
|
|
1479
1693
|
// src/templates/package-json.ts
|
|
1694
|
+
var INTEGRATION_RUNTIME_DEPS = {
|
|
1695
|
+
preact: { preact: "^10.0.0", "preact-render-to-string": "^6.0.0" },
|
|
1696
|
+
react: { react: "^19.0.0", "react-dom": "^19.0.0" },
|
|
1697
|
+
vue: { vue: "^3.4.0" },
|
|
1698
|
+
svelte: { svelte: "^5.0.0" },
|
|
1699
|
+
solid: { "solid-js": "^1.8.0" },
|
|
1700
|
+
lit: {
|
|
1701
|
+
lit: "^3.0.0",
|
|
1702
|
+
"@lit-labs/ssr": "^4.0.0",
|
|
1703
|
+
"@lit-labs/ssr-client": "^1.0.0",
|
|
1704
|
+
"@lit-labs/ssr-dom-shim": "^1.0.0"
|
|
1705
|
+
},
|
|
1706
|
+
qwik: { "@builder.io/qwik": "^1.5.0" }
|
|
1707
|
+
};
|
|
1480
1708
|
function generatePackageJson(config) {
|
|
1481
1709
|
const dependencies = {
|
|
1482
1710
|
"@useavalon/avalon": "latest"
|
|
1483
1711
|
};
|
|
1484
1712
|
for (const integration of config.integrations) {
|
|
1485
1713
|
dependencies[INTEGRATION_PACKAGES[integration]] = "latest";
|
|
1714
|
+
Object.assign(dependencies, INTEGRATION_RUNTIME_DEPS[integration]);
|
|
1486
1715
|
}
|
|
1487
1716
|
if (config.plugins.includes("seo")) {
|
|
1488
1717
|
dependencies["@useavalon/seo"] = "latest";
|
|
@@ -1830,7 +2059,7 @@ function generateShadcnComponentsJson(config) {
|
|
|
1830
2059
|
}
|
|
1831
2060
|
|
|
1832
2061
|
// src/templates/tsconfig.ts
|
|
1833
|
-
function generateTsConfig() {
|
|
2062
|
+
function generateTsConfig(core = "preact") {
|
|
1834
2063
|
const tsconfig = {
|
|
1835
2064
|
compilerOptions: {
|
|
1836
2065
|
target: "ESNext",
|
|
@@ -1843,6 +2072,7 @@ function generateTsConfig() {
|
|
|
1843
2072
|
allowImportingTsExtensions: true,
|
|
1844
2073
|
noEmit: true,
|
|
1845
2074
|
jsx: "react-jsx",
|
|
2075
|
+
jsxImportSource: core,
|
|
1846
2076
|
paths: {
|
|
1847
2077
|
"@shared/*": ["./app/shared/*"],
|
|
1848
2078
|
"@modules/*": ["./app/modules/*"]
|
|
@@ -1943,12 +2173,20 @@ function generateViteConfig(config) {
|
|
|
1943
2173
|
if (needsTailwind) {
|
|
1944
2174
|
pluginEntries.push(` tailwindcss(),`);
|
|
1945
2175
|
}
|
|
2176
|
+
const cronLines = config.cron ? [
|
|
2177
|
+
` // Scheduled jobs (cron). Each entry maps a schedule to a task file`,
|
|
2178
|
+
` // in tasks/. See https://useavalon.dev/docs/cron-jobs`,
|
|
2179
|
+
` cron: [`,
|
|
2180
|
+
` { schedule: '${EXAMPLE_CRON_SCHEDULE}', handler: '${EXAMPLE_CRON_HANDLER}' },`,
|
|
2181
|
+
` ],`
|
|
2182
|
+
] : [];
|
|
1946
2183
|
const lines = [
|
|
1947
2184
|
imports.join(`
|
|
1948
2185
|
`),
|
|
1949
2186
|
"",
|
|
1950
2187
|
`export default defineConfig(async (): Promise<UserConfig> => {`,
|
|
1951
2188
|
` const avalonPlugins = await avalon({`,
|
|
2189
|
+
` core: '${config.core}',`,
|
|
1952
2190
|
` integrations: [${integrationsList}],`,
|
|
1953
2191
|
` modules: 'app/modules',`,
|
|
1954
2192
|
` layoutsDir: 'app/shared/layouts',`,
|
|
@@ -1963,6 +2201,7 @@ function generateViteConfig(config) {
|
|
|
1963
2201
|
` crawlLinks: true,`,
|
|
1964
2202
|
` ignore: [],`,
|
|
1965
2203
|
` },`,
|
|
2204
|
+
...cronLines,
|
|
1966
2205
|
` },`,
|
|
1967
2206
|
` });`,
|
|
1968
2207
|
"",
|
|
@@ -2053,7 +2292,7 @@ async function scaffoldProject(config, targetDir) {
|
|
|
2053
2292
|
await mkdir(join(targetDir, dir), { recursive: true });
|
|
2054
2293
|
}
|
|
2055
2294
|
await writeFile(join(targetDir, "package.json"), generatePackageJson(config));
|
|
2056
|
-
await writeFile(join(targetDir, "tsconfig.json"), generateTsConfig());
|
|
2295
|
+
await writeFile(join(targetDir, "tsconfig.json"), generateTsConfig(config.core));
|
|
2057
2296
|
await writeFile(join(targetDir, "vite.config.ts"), generateViteConfig(config));
|
|
2058
2297
|
await writeFile(join(targetDir, "app/shared/layouts/_layout.tsx"), generateRootLayout(config));
|
|
2059
2298
|
await writeFile(join(targetDir, "app/modules/main/layouts/_layout.tsx"), generateMainLayout(config));
|
|
@@ -2061,6 +2300,11 @@ async function scaffoldProject(config, targetDir) {
|
|
|
2061
2300
|
await writeFile(join(targetDir, "app/modules/main/pages/404.tsx"), generate404Page());
|
|
2062
2301
|
await writeFile(join(targetDir, "middleware/01.logger.ts"), generateSampleMiddleware(config));
|
|
2063
2302
|
await writeFile(join(targetDir, "routes/api/hello.ts"), generateHelloRoute(config));
|
|
2303
|
+
if (config.cron) {
|
|
2304
|
+
const cronPath = join(targetDir, EXAMPLE_CRON_HANDLER);
|
|
2305
|
+
await mkdir(dirname(cronPath), { recursive: true });
|
|
2306
|
+
await writeFile(cronPath, generateExampleCronTask(config));
|
|
2307
|
+
}
|
|
2064
2308
|
if (config.middleware === "hono") {
|
|
2065
2309
|
await writeFile(join(targetDir, "server.ts"), generateHonoServerEntry());
|
|
2066
2310
|
} else if (config.middleware === "elysia") {
|
|
@@ -2076,6 +2320,8 @@ async function scaffoldProject(config, targetDir) {
|
|
|
2076
2320
|
await writeFile(join(targetDir, "server/env.d.ts"), `/// <reference types="nitro" />
|
|
2077
2321
|
`);
|
|
2078
2322
|
await writeFile(join(targetDir, "app/env.d.ts"), generateEnvDts(config.integrations));
|
|
2323
|
+
await writeFile(join(targetDir, "app/entry-client.ts"), `import "virtual:avalon/client-entry";
|
|
2324
|
+
`);
|
|
2079
2325
|
await writeFile(join(targetDir, "server/renderer.ts"), [
|
|
2080
2326
|
`/**`,
|
|
2081
2327
|
` * SSR Renderer — provided by Avalon's virtual module system.`,
|
|
@@ -2121,6 +2367,7 @@ function formatSummary(config, scaffoldedInPlace = false) {
|
|
|
2121
2367
|
` Plugins: ${plugins}`,
|
|
2122
2368
|
` Middleware: ${config.middleware}`,
|
|
2123
2369
|
` Deploy: ${deploy}`,
|
|
2370
|
+
` Cron: ${config.cron ? "yes" : "no"}`,
|
|
2124
2371
|
"",
|
|
2125
2372
|
" Next steps:",
|
|
2126
2373
|
...nextSteps,
|
|
@@ -2142,11 +2389,28 @@ async function main() {
|
|
|
2142
2389
|
process.exit(0);
|
|
2143
2390
|
}
|
|
2144
2391
|
if (args.help) {
|
|
2145
|
-
console.log(
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2392
|
+
console.log([
|
|
2393
|
+
"Usage: create-avalon [project-name] [options]",
|
|
2394
|
+
"",
|
|
2395
|
+
"Runs interactively by default. Pass --yes (or run without a TTY, e.g. in",
|
|
2396
|
+
"CI/Docker) to scaffold non-interactively from flags + defaults.",
|
|
2397
|
+
"",
|
|
2398
|
+
"Options:",
|
|
2399
|
+
" -v, --version Show version number",
|
|
2400
|
+
" -h, --help Show help",
|
|
2401
|
+
" -y, --yes Skip prompts; use flags and defaults",
|
|
2402
|
+
" --core Rendering engine: preact (default) | react",
|
|
2403
|
+
" --integrations Comma list: preact,react,vue,svelte,solid,lit,qwik",
|
|
2404
|
+
" --styling css-modules (default) | tailwind | shadcn",
|
|
2405
|
+
" --plugins Comma list: seo (default),agent-optimization,syntax-highlighting",
|
|
2406
|
+
" --middleware h3 (default) | hono | elysia",
|
|
2407
|
+
" --deploy netlify | none (default)",
|
|
2408
|
+
" --cron Scaffold an example cron task + config",
|
|
2409
|
+
"",
|
|
2410
|
+
"Example:",
|
|
2411
|
+
" create-avalon my-app --yes --core react --integrations react,vue --styling shadcn"
|
|
2412
|
+
].join(`
|
|
2413
|
+
`));
|
|
2150
2414
|
process.exit(0);
|
|
2151
2415
|
}
|
|
2152
2416
|
if (args.projectName && args.projectName !== ".") {
|
|
@@ -2156,7 +2420,8 @@ Options:
|
|
|
2156
2420
|
process.exit(1);
|
|
2157
2421
|
}
|
|
2158
2422
|
}
|
|
2159
|
-
const
|
|
2423
|
+
const nonInteractive = args.yes || !process.stdin.isTTY;
|
|
2424
|
+
const config = nonInteractive ? resolveConfigNonInteractive(args) : await collectProjectConfig(args.projectName);
|
|
2160
2425
|
if (!args.projectName && config.projectName !== ".") {
|
|
2161
2426
|
const dirResult = validateDirectory(resolve(config.projectName));
|
|
2162
2427
|
if (!dirResult.valid) {
|
|
@@ -2173,4 +2438,9 @@ Options:
|
|
|
2173
2438
|
printSummary(config, scaffoldedInPlace);
|
|
2174
2439
|
process.exit(0);
|
|
2175
2440
|
}
|
|
2176
|
-
|
|
2441
|
+
try {
|
|
2442
|
+
await main();
|
|
2443
|
+
} catch (error) {
|
|
2444
|
+
console.error(error instanceof CliArgError ? error.message : error);
|
|
2445
|
+
process.exit(1);
|
|
2446
|
+
}
|