@apex-stack/core 0.7.7 → 0.8.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/dist/{build-C3FW7BTM.js → build-WKK4BCQI.js} +39 -7
- package/dist/{chunk-EVFABT7B.js → chunk-S3HCE23H.js} +26 -8
- package/dist/{chunk-P6KQSPAV.js → chunk-TWAGSGFN.js} +2 -0
- package/dist/cli.js +5 -5
- package/dist/client.d.ts +1 -1
- package/dist/client.js +2 -1
- package/dist/{dev-SXOWAX4N.js → dev-3EVUK364.js} +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/{server-AV533LKD.js → server-UVY6DFK2.js} +12 -3
- package/dist/{start-VBGP3HFC.js → start-FIRWZ55Y.js} +3 -1
- package/dist/{upgrade-KGUW3C3O.js → upgrade-YZN6TVNI.js} +80 -8
- package/package.json +3 -3
- package/templates/default/pages/loading.alpine +13 -0
|
@@ -7,12 +7,13 @@ import {
|
|
|
7
7
|
renderPage,
|
|
8
8
|
resolveApexConfig,
|
|
9
9
|
scanPages
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-S3HCE23H.js";
|
|
11
11
|
import "./chunk-PMLGY6Z3.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/build.ts
|
|
14
14
|
import { cpSync, existsSync as existsSync3, mkdirSync, readdirSync as readdirSync3, rmSync, writeFileSync } from "fs";
|
|
15
15
|
import { dirname, join as join3, resolve } from "path";
|
|
16
|
+
import { renderFragment } from "@apex-stack/kit";
|
|
16
17
|
import { apex as apex3 } from "@apex-stack/vite";
|
|
17
18
|
import { defineCommand } from "citty";
|
|
18
19
|
import { createServer as createViteServer } from "vite";
|
|
@@ -57,11 +58,20 @@ async function buildClient(root, routes, outDir, base = "/") {
|
|
|
57
58
|
return [
|
|
58
59
|
...appCssRel ? [`import ${JSON.stringify(`/${appCssRel}`)}`] : [],
|
|
59
60
|
`import Alpine from 'alpinejs'`,
|
|
61
|
+
`import { installNav } from '@apex-stack/core/client'`,
|
|
60
62
|
...storeIds.map((sid, i) => `import __s${i} from ${JSON.stringify(sid)}`),
|
|
63
|
+
// Registers this page's Alpine factory as a side effect. During client-side
|
|
64
|
+
// navigation this bundle is dynamic-imported again for the target page —
|
|
65
|
+
// the import runs (registering the new page), the boot guard below skips
|
|
66
|
+
// the one-time Alpine.start()/installNav so nothing double-initialises.
|
|
61
67
|
`import ${JSON.stringify(pageId)}`,
|
|
62
|
-
"window.
|
|
63
|
-
|
|
64
|
-
"Alpine
|
|
68
|
+
"if (!window.__apexBooted) {",
|
|
69
|
+
" window.__apexBooted = true",
|
|
70
|
+
" window.Alpine = Alpine",
|
|
71
|
+
...storeIds.map((_, i) => ` Alpine.store(__s${i}.name, __s${i}.factory())`),
|
|
72
|
+
" Alpine.start()",
|
|
73
|
+
" installNav()",
|
|
74
|
+
"}"
|
|
65
75
|
].join("\n");
|
|
66
76
|
}
|
|
67
77
|
}
|
|
@@ -222,12 +232,18 @@ var buildCommand = defineCommand({
|
|
|
222
232
|
(id) => vite.ssrLoadModule(id)
|
|
223
233
|
);
|
|
224
234
|
const stores = await loadStores(root, (id) => vite.ssrLoadModule(id));
|
|
225
|
-
const { runtimeConfig, publicConfig } = await resolveApexConfig(
|
|
235
|
+
const { config, runtimeConfig, publicConfig } = await resolveApexConfig(
|
|
226
236
|
root,
|
|
227
237
|
(id) => vite.ssrLoadModule(id)
|
|
228
238
|
);
|
|
239
|
+
const clientNav = config.clientNav !== false;
|
|
229
240
|
const layoutsDir = join3(root, "layouts");
|
|
230
241
|
const layouts = existsSync3(layoutsDir) ? readdirSync3(layoutsDir).filter((f) => f.endsWith(".alpine")).map((f) => f.replace(/\.alpine$/, "")) : [];
|
|
242
|
+
let loadingHtml;
|
|
243
|
+
if (!args.islands && clientNav && existsSync3(join3(root, "pages", "loading.alpine"))) {
|
|
244
|
+
const l = await vite.ssrLoadModule("/pages/loading.alpine");
|
|
245
|
+
loadingHtml = renderFragment(l.template, {}, l.scopeId, registry);
|
|
246
|
+
}
|
|
231
247
|
for (const route of staticRoutes) {
|
|
232
248
|
const common = {
|
|
233
249
|
loadModule: (id) => vite.ssrLoadModule(id),
|
|
@@ -241,7 +257,13 @@ var buildCommand = defineCommand({
|
|
|
241
257
|
publicConfig
|
|
242
258
|
};
|
|
243
259
|
const assets = hrefs.get(route.pageId);
|
|
244
|
-
const html = args.islands ? await renderIslandsPage(common) : await renderPage({
|
|
260
|
+
const html = args.islands ? await renderIslandsPage(common) : await renderPage({
|
|
261
|
+
...common,
|
|
262
|
+
clientHref: assets?.js,
|
|
263
|
+
clientCss: assets?.css,
|
|
264
|
+
clientNav,
|
|
265
|
+
loadingHtml
|
|
266
|
+
});
|
|
245
267
|
const dest = join3(outDir, outFile(route.pattern));
|
|
246
268
|
mkdirSync(dirname(dest), { recursive: true });
|
|
247
269
|
writeFileSync(dest, html);
|
|
@@ -268,6 +290,8 @@ async function buildServerTarget(root, outDir, outLabel, routes) {
|
|
|
268
290
|
const clientHrefs = await buildClient(root, routes, outDir);
|
|
269
291
|
const server = await buildServer(root, routes, outDir);
|
|
270
292
|
let runtimeConfig = { public: {} };
|
|
293
|
+
let clientNav = true;
|
|
294
|
+
let loadingHtml;
|
|
271
295
|
const cfgVite = await createViteServer({
|
|
272
296
|
root,
|
|
273
297
|
appType: "custom",
|
|
@@ -278,6 +302,12 @@ async function buildServerTarget(root, outDir, outLabel, routes) {
|
|
|
278
302
|
const resolved = await resolveApexConfig(root, (id) => cfgVite.ssrLoadModule(id));
|
|
279
303
|
runtimeConfig = { public: {}, ...resolved.config.runtimeConfig ?? {} };
|
|
280
304
|
if (!runtimeConfig.public) runtimeConfig.public = {};
|
|
305
|
+
clientNav = resolved.config.clientNav !== false;
|
|
306
|
+
if (clientNav && existsSync3(join3(root, "pages", "loading.alpine"))) {
|
|
307
|
+
const { registry } = await loadComponents(root, (id) => cfgVite.ssrLoadModule(id));
|
|
308
|
+
const l = await cfgVite.ssrLoadModule("/pages/loading.alpine");
|
|
309
|
+
loadingHtml = renderFragment(l.template, {}, l.scopeId, registry);
|
|
310
|
+
}
|
|
281
311
|
} finally {
|
|
282
312
|
await cfgVite.close();
|
|
283
313
|
}
|
|
@@ -316,7 +346,9 @@ async function buildServerTarget(root, outDir, outLabel, routes) {
|
|
|
316
346
|
components,
|
|
317
347
|
api,
|
|
318
348
|
middleware,
|
|
319
|
-
runtimeConfig
|
|
349
|
+
runtimeConfig,
|
|
350
|
+
clientNav,
|
|
351
|
+
loadingHtml
|
|
320
352
|
};
|
|
321
353
|
writeFileSync(join3(outDir, "apex-manifest.json"), JSON.stringify(manifest, null, 2));
|
|
322
354
|
const pub = join3(root, "public");
|
|
@@ -135,12 +135,12 @@ function renderHead(head) {
|
|
|
135
135
|
const parts = [`<title>${head?.title ? escAttr(head.title) : "Apex JS"}</title>`];
|
|
136
136
|
for (const m of head?.meta ?? []) {
|
|
137
137
|
parts.push(
|
|
138
|
-
`<meta ${Object.entries(m).map(([k, v]) => `${k}="${escAttr(v)}"`).join(" ")} />`
|
|
138
|
+
`<meta ${Object.entries(m).map(([k, v]) => `${k}="${escAttr(v)}"`).join(" ")} data-apex-head />`
|
|
139
139
|
);
|
|
140
140
|
}
|
|
141
141
|
for (const l of head?.link ?? []) {
|
|
142
142
|
parts.push(
|
|
143
|
-
`<link ${Object.entries(l).map(([k, v]) => `${k}="${escAttr(v)}"`).join(" ")} />`
|
|
143
|
+
`<link ${Object.entries(l).map(([k, v]) => `${k}="${escAttr(v)}"`).join(" ")} data-apex-head />`
|
|
144
144
|
);
|
|
145
145
|
}
|
|
146
146
|
return parts.join("\n ");
|
|
@@ -207,7 +207,11 @@ async function renderPage(opts) {
|
|
|
207
207
|
appCss: opts.appCss,
|
|
208
208
|
clientCss: opts.clientCss,
|
|
209
209
|
headTags: renderHead(head),
|
|
210
|
-
configScript: clientConfigScript(opts.publicConfig ?? {})
|
|
210
|
+
configScript: clientConfigScript(opts.publicConfig ?? {}),
|
|
211
|
+
// dev imports the page module by path; prod imports its hashed bundle.
|
|
212
|
+
moduleUrl: opts.clientHref ?? opts.pageId,
|
|
213
|
+
clientNav: opts.clientNav !== false,
|
|
214
|
+
loadingHtml: opts.loadingHtml
|
|
211
215
|
});
|
|
212
216
|
return opts.transformHtml ? opts.transformHtml(opts.url, doc) : doc;
|
|
213
217
|
}
|
|
@@ -221,31 +225,44 @@ function shell({
|
|
|
221
225
|
appCss,
|
|
222
226
|
clientCss = [],
|
|
223
227
|
headTags = "<title>Apex JS</title>",
|
|
224
|
-
configScript = ""
|
|
228
|
+
configScript = "",
|
|
229
|
+
moduleUrl,
|
|
230
|
+
clientNav = true,
|
|
231
|
+
loadingHtml
|
|
225
232
|
}) {
|
|
226
233
|
const storeImports = storeIds.map((id, i) => ` import __s${i} from ${JSON.stringify(id)}`).join("\n");
|
|
227
234
|
const storeRegs = storeIds.map((_, i) => ` Alpine.store(__s${i}.name, __s${i}.factory())`).join("\n");
|
|
235
|
+
const navImport = clientNav ? ` import { installNav } from '@apex-stack/core/client'
|
|
236
|
+
` : "";
|
|
237
|
+
const navInstall = clientNav ? ` installNav()
|
|
238
|
+
` : "";
|
|
228
239
|
const clientScript = clientHref ? `<script type="module" src="${clientHref}"></script>` : `<script type="module">
|
|
229
240
|
import Alpine from 'alpinejs'
|
|
230
|
-
${storeImports ? `${storeImports}
|
|
241
|
+
${navImport}${storeImports ? `${storeImports}
|
|
231
242
|
` : ""} import ${JSON.stringify(pageId)}
|
|
232
243
|
window.Alpine = Alpine
|
|
233
244
|
${storeRegs ? `${storeRegs}
|
|
234
245
|
` : ""} Alpine.start()
|
|
235
|
-
</script>`;
|
|
246
|
+
${navInstall}</script>`;
|
|
236
247
|
const cssLinks = [...appCss ? [appCss] : [], ...clientCss].map((href) => `<link rel="stylesheet" href="${href}" />`).join("\n ");
|
|
248
|
+
const moduleMeta = moduleUrl ? `
|
|
249
|
+
<meta name="apex:page-module" content="${escAttr(moduleUrl)}" />` : "";
|
|
250
|
+
const loadingTpl = loadingHtml ? `
|
|
251
|
+
<template data-apex-loading>${loadingHtml}</template>` : "";
|
|
237
252
|
return `<!DOCTYPE html>
|
|
238
253
|
<html lang="en">
|
|
239
254
|
<head>
|
|
240
255
|
<meta charset="utf-8" />
|
|
241
256
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
242
|
-
<link rel="icon" type="image/svg+xml" href="/favicon.svg"
|
|
257
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />${moduleMeta}
|
|
243
258
|
${cssLinks ? `${cssLinks}
|
|
244
259
|
` : ""}${headTags}
|
|
245
260
|
<style>${css}</style>
|
|
246
261
|
</head>
|
|
247
262
|
<body>
|
|
263
|
+
<div id="__apex" data-apex-root>
|
|
248
264
|
${body}
|
|
265
|
+
</div>${loadingTpl}
|
|
249
266
|
${island}
|
|
250
267
|
${configScript}
|
|
251
268
|
${clientScript}
|
|
@@ -364,7 +381,8 @@ function walkAlpine(dir) {
|
|
|
364
381
|
function scanPages(root) {
|
|
365
382
|
const dir = join3(root, "pages");
|
|
366
383
|
if (!existsSync3(dir)) return [];
|
|
367
|
-
const
|
|
384
|
+
const RESERVED = /* @__PURE__ */ new Set(["error.alpine", "loading.alpine"]);
|
|
385
|
+
const routes = walkAlpine(dir).filter((abs) => !RESERVED.has(relative(dir, abs).split(sep).join("/"))).map((abs) => {
|
|
368
386
|
const rel = relative(dir, abs).split(sep).join("/");
|
|
369
387
|
const pageId = `/pages/${rel}`;
|
|
370
388
|
const parts = rel.replace(/\.alpine$/, "").split("/");
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
offerExtension
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-TWAGSGFN.js";
|
|
5
5
|
import {
|
|
6
6
|
VERSION,
|
|
7
7
|
banner,
|
|
@@ -147,13 +147,13 @@ var main = defineCommand2({
|
|
|
147
147
|
},
|
|
148
148
|
subCommands: {
|
|
149
149
|
new: newCommand,
|
|
150
|
-
dev: () => import("./dev-
|
|
151
|
-
build: () => import("./build-
|
|
152
|
-
start: () => import("./start-
|
|
150
|
+
dev: () => import("./dev-3EVUK364.js").then((m) => m.devCommand),
|
|
151
|
+
build: () => import("./build-WKK4BCQI.js").then((m) => m.buildCommand),
|
|
152
|
+
start: () => import("./start-FIRWZ55Y.js").then((m) => m.startCommand),
|
|
153
153
|
make: () => import("./make-VAYO5GWA.js").then((m) => m.makeCommand),
|
|
154
154
|
add: () => import("./add-M3YLIFF5.js").then((m) => m.addCommand),
|
|
155
155
|
theme: () => import("./theme-UUOIV44V.js").then((m) => m.themeCommand),
|
|
156
|
-
upgrade: () => import("./upgrade-
|
|
156
|
+
upgrade: () => import("./upgrade-YZN6TVNI.js").then((m) => m.upgradeCommand),
|
|
157
157
|
migrate: () => import("./migrate-X6LIHMIE.js").then((m) => m.migrateCommand),
|
|
158
158
|
mcp: () => import("./mcp-CH7L4GF3.js").then((m) => m.mcpCommand)
|
|
159
159
|
},
|
package/dist/client.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ActionOptions, ActionState, createAction, registerApexComponent } from '@apex-stack/kit/client';
|
|
1
|
+
export { ActionOptions, ActionState, NavOptions, createAction, installNav, registerApexComponent } from '@apex-stack/kit/client';
|
package/dist/client.js
CHANGED
|
@@ -24,7 +24,7 @@ var devCommand = defineCommand({
|
|
|
24
24
|
process.stdout.write(banner());
|
|
25
25
|
const sp = spinner(`Starting dev server${args.islands ? " (islands mode)" : ""}\u2026`);
|
|
26
26
|
try {
|
|
27
|
-
const { startDevServer } = await import("./server-
|
|
27
|
+
const { startDevServer } = await import("./server-UVY6DFK2.js");
|
|
28
28
|
const { port: actual } = await startDevServer({ root, port, islands: Boolean(args.islands) });
|
|
29
29
|
sp.succeed("Dev server ready");
|
|
30
30
|
ready([
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,11 @@ interface ApexConfig {
|
|
|
14
14
|
* `APEX_PUBLIC_<KEY>` for `public` keys (camelCase ↔ SCREAMING_SNAKE).
|
|
15
15
|
*/
|
|
16
16
|
runtimeConfig?: RuntimeConfig;
|
|
17
|
+
/**
|
|
18
|
+
* Client-side navigation (SPA link nav + prefetch + progress bar). On by
|
|
19
|
+
* default; set `false` to fall back to full-page loads.
|
|
20
|
+
*/
|
|
21
|
+
clientNav?: boolean;
|
|
17
22
|
[key: string]: unknown;
|
|
18
23
|
}
|
|
19
24
|
/** Author an `apex.config.ts`. Identity function — exists for types + discoverability. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
openInEditor
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TWAGSGFN.js";
|
|
4
4
|
import {
|
|
5
5
|
loadComponents
|
|
6
6
|
} from "./chunk-4VG3CZ6H.js";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
renderPage,
|
|
20
20
|
resolveApexConfig,
|
|
21
21
|
scanPages
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-S3HCE23H.js";
|
|
23
23
|
import "./chunk-PMLGY6Z3.js";
|
|
24
24
|
|
|
25
25
|
// src/dev/server.ts
|
|
@@ -28,6 +28,7 @@ import { createServer as createHttpServer } from "http";
|
|
|
28
28
|
import { createRequire } from "module";
|
|
29
29
|
import { join as join2, resolve } from "path";
|
|
30
30
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
31
|
+
import { renderFragment } from "@apex-stack/kit";
|
|
31
32
|
import { apex } from "@apex-stack/vite";
|
|
32
33
|
import {
|
|
33
34
|
createApp,
|
|
@@ -388,10 +389,11 @@ async function startDevServer(options) {
|
|
|
388
389
|
const resolved = id[0] === "/" && !id.startsWith(options.root) ? join2(options.root, id).replace(/\\/g, "/") : id;
|
|
389
390
|
return vite.ssrLoadModule(resolved);
|
|
390
391
|
};
|
|
391
|
-
const { runtimeConfig, publicConfig } = await resolveApexConfig(
|
|
392
|
+
const { config, runtimeConfig, publicConfig } = await resolveApexConfig(
|
|
392
393
|
options.root,
|
|
393
394
|
(id) => ssrLoad(id)
|
|
394
395
|
);
|
|
396
|
+
const clientNav = config.clientNav !== false;
|
|
395
397
|
const app = createApp();
|
|
396
398
|
app.use(fromNodeMiddleware(vite.middlewares));
|
|
397
399
|
app.use(
|
|
@@ -463,6 +465,11 @@ async function startDevServer(options) {
|
|
|
463
465
|
const stores = await loadStores(options.root, (id) => ssrLoad(id));
|
|
464
466
|
const layoutsDir = join2(options.root, "layouts");
|
|
465
467
|
const layouts = existsSync2(layoutsDir) ? readdirSync2(layoutsDir).filter((f) => f.endsWith(".alpine")).map((f) => f.replace(/\.alpine$/, "")) : [];
|
|
468
|
+
let loadingHtml;
|
|
469
|
+
if (!options.islands && clientNav && existsSync2(join2(options.root, "pages", "loading.alpine"))) {
|
|
470
|
+
const l = await ssrLoad("/pages/loading.alpine");
|
|
471
|
+
loadingHtml = renderFragment(l.template, {}, l.scopeId, registry);
|
|
472
|
+
}
|
|
466
473
|
const render = options.islands ? renderIslandsPage : renderPage;
|
|
467
474
|
const html = await render({
|
|
468
475
|
loadModule: (id) => ssrLoad(id),
|
|
@@ -476,6 +483,8 @@ async function startDevServer(options) {
|
|
|
476
483
|
layouts,
|
|
477
484
|
runtimeConfig,
|
|
478
485
|
publicConfig,
|
|
486
|
+
clientNav,
|
|
487
|
+
loadingHtml,
|
|
479
488
|
locals: event.context.apexLocals ?? {},
|
|
480
489
|
errorPageId: existsSync2(join2(options.root, "pages", "error.alpine")) ? "/pages/error.alpine" : void 0,
|
|
481
490
|
transformHtml: (u, doc) => vite.transformIndexHtml(u, doc)
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
matchRoute,
|
|
12
12
|
renderIslandsPage,
|
|
13
13
|
renderPage
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-S3HCE23H.js";
|
|
15
15
|
import "./chunk-PMLGY6Z3.js";
|
|
16
16
|
|
|
17
17
|
// src/commands/start.ts
|
|
@@ -133,6 +133,8 @@ async function startProdServer(options) {
|
|
|
133
133
|
clientCss: route?.clientCss,
|
|
134
134
|
runtimeConfig,
|
|
135
135
|
publicConfig,
|
|
136
|
+
clientNav: manifest.clientNav !== false,
|
|
137
|
+
loadingHtml: manifest.loadingHtml,
|
|
136
138
|
locals: event.context.apexLocals ?? {},
|
|
137
139
|
errorPageId
|
|
138
140
|
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
cmpVersion,
|
|
3
|
+
offerExtension,
|
|
4
|
+
promptYesNo
|
|
5
|
+
} from "./chunk-TWAGSGFN.js";
|
|
4
6
|
import {
|
|
5
7
|
VERSION,
|
|
6
8
|
banner,
|
|
@@ -8,12 +10,69 @@ import {
|
|
|
8
10
|
} from "./chunk-QIXJSQLW.js";
|
|
9
11
|
|
|
10
12
|
// src/commands/upgrade.ts
|
|
11
|
-
import { spawnSync } from "child_process";
|
|
13
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
12
14
|
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "fs";
|
|
13
|
-
import { basename, dirname, join, relative, resolve } from "path";
|
|
14
|
-
import { fileURLToPath } from "url";
|
|
15
|
+
import { basename, dirname, join, relative, resolve as resolve2 } from "path";
|
|
16
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15
17
|
import { defineCommand } from "citty";
|
|
16
|
-
|
|
18
|
+
|
|
19
|
+
// src/selfUpdate.ts
|
|
20
|
+
import { spawnSync } from "child_process";
|
|
21
|
+
import { resolve, sep } from "path";
|
|
22
|
+
import { fileURLToPath } from "url";
|
|
23
|
+
var PKG = "@apex-stack/core";
|
|
24
|
+
var WIN = process.platform === "win32";
|
|
25
|
+
function latestPublished() {
|
|
26
|
+
try {
|
|
27
|
+
const r = spawnSync("npm", ["view", PKG, "version"], {
|
|
28
|
+
encoding: "utf8",
|
|
29
|
+
timeout: 4e3,
|
|
30
|
+
shell: WIN
|
|
31
|
+
});
|
|
32
|
+
if (r.status !== 0 || !r.stdout) return null;
|
|
33
|
+
const v = r.stdout.trim();
|
|
34
|
+
return /^\d+\.\d+\.\d+/.test(v) ? v : null;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function isGlobalInstall() {
|
|
40
|
+
const self = fileURLToPath(import.meta.url);
|
|
41
|
+
const localRoot = resolve(process.cwd(), "node_modules") + sep;
|
|
42
|
+
return !self.startsWith(localRoot);
|
|
43
|
+
}
|
|
44
|
+
function installGlobalLatest() {
|
|
45
|
+
return spawnSync("npm", ["install", "-g", `${PKG}@latest`], { stdio: "inherit", shell: WIN }).status === 0;
|
|
46
|
+
}
|
|
47
|
+
async function maybeSelfUpdate(reexecArgv, choice) {
|
|
48
|
+
if (choice === false) return false;
|
|
49
|
+
if (!isGlobalInstall()) return false;
|
|
50
|
+
const latest = latestPublished();
|
|
51
|
+
if (!latest || cmpVersion(latest, VERSION) <= 0) return false;
|
|
52
|
+
const log = console.log;
|
|
53
|
+
log(
|
|
54
|
+
`
|
|
55
|
+
${color.cyan("\u2191")} A newer Apex CLI is available: ${color.gray(VERSION)} \u2192 ${color.green(latest)}`
|
|
56
|
+
);
|
|
57
|
+
const yes = choice ?? (process.stdin.isTTY ? await promptYesNo(` Update the global CLI now?`) : false);
|
|
58
|
+
if (!yes) {
|
|
59
|
+
log(` ${color.gray("Skipped. Update later with")} ${color.cyan(`npm i -g ${PKG}@latest`)}
|
|
60
|
+
`);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (!installGlobalLatest()) {
|
|
64
|
+
log(` ${color.red("\u2717")} Global update failed \u2014 run ${color.cyan(`npm i -g ${PKG}@latest`)}
|
|
65
|
+
`);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
log(` ${color.green("\u2713")} CLI updated to ${latest} \u2014 re-running on the new engine\u2026
|
|
69
|
+
`);
|
|
70
|
+
const r = spawnSync("apex", reexecArgv, { stdio: "inherit", shell: WIN });
|
|
71
|
+
process.exit(r.status ?? 0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/commands/upgrade.ts
|
|
75
|
+
var TEMPLATE_DIR = fileURLToPath2(new URL("../templates/default", import.meta.url));
|
|
17
76
|
var PROTECTED = /* @__PURE__ */ new Set(["package.json"]);
|
|
18
77
|
function projectName(root) {
|
|
19
78
|
try {
|
|
@@ -79,10 +138,14 @@ var upgradeCommand = defineCommand({
|
|
|
79
138
|
vscode: {
|
|
80
139
|
type: "boolean",
|
|
81
140
|
description: "Install the Apex VS Code extension (skip the prompt)"
|
|
141
|
+
},
|
|
142
|
+
self: {
|
|
143
|
+
type: "boolean",
|
|
144
|
+
description: "Update the global Apex CLI first if a newer one is published (default: ask)"
|
|
82
145
|
}
|
|
83
146
|
},
|
|
84
147
|
async run({ args }) {
|
|
85
|
-
const root =
|
|
148
|
+
const root = resolve2(process.cwd(), String(args.root));
|
|
86
149
|
const log = console.log;
|
|
87
150
|
if (!existsSync(join(root, "package.json"))) {
|
|
88
151
|
console.error(`
|
|
@@ -90,6 +153,15 @@ var upgradeCommand = defineCommand({
|
|
|
90
153
|
`);
|
|
91
154
|
process.exit(1);
|
|
92
155
|
}
|
|
156
|
+
const reexecArgv = [
|
|
157
|
+
"upgrade",
|
|
158
|
+
String(args.root),
|
|
159
|
+
...args.force ? ["--force"] : [],
|
|
160
|
+
...args.install === false ? ["--no-install"] : [],
|
|
161
|
+
...args.vscode === true ? ["--vscode"] : args.vscode === false ? ["--no-vscode"] : [],
|
|
162
|
+
"--no-self"
|
|
163
|
+
];
|
|
164
|
+
if (await maybeSelfUpdate(reexecArgv, args.self)) return;
|
|
93
165
|
const name = projectName(root);
|
|
94
166
|
process.stdout.write(banner());
|
|
95
167
|
const added = [];
|
|
@@ -141,7 +213,7 @@ var upgradeCommand = defineCommand({
|
|
|
141
213
|
const pm = detectPm();
|
|
142
214
|
log(`
|
|
143
215
|
${color.gray(`Installing with ${pm}\u2026`)}`);
|
|
144
|
-
const ok =
|
|
216
|
+
const ok = spawnSync2(pm, ["install"], {
|
|
145
217
|
cwd: root,
|
|
146
218
|
stdio: "inherit",
|
|
147
219
|
shell: process.platform === "win32"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apex-stack/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "The full-stack meta-framework for Alpine.js — CLI and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"h3": "^1.13.0",
|
|
48
48
|
"vite": "^6.0.7",
|
|
49
49
|
"zod": "^4.4.3",
|
|
50
|
-
"@apex-stack/kit": "0.
|
|
51
|
-
"@apex-stack/vite": "0.1.
|
|
50
|
+
"@apex-stack/kit": "0.4.0",
|
|
51
|
+
"@apex-stack/vite": "0.1.8",
|
|
52
52
|
"@apex-stack/theme": "0.3.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
pages/loading.alpine — the client-side navigation loading boundary.
|
|
3
|
+
|
|
4
|
+
Apex renders this once and shows it in the page region during a navigation that
|
|
5
|
+
takes longer than a moment (e.g. a slow loader). It's plain, presentational
|
|
6
|
+
HTML — no loader, no interactivity needed.
|
|
7
|
+
-->
|
|
8
|
+
<template x-data>
|
|
9
|
+
<div class="flex flex-col items-center justify-center gap-3 py-24 text-center">
|
|
10
|
+
<div class="size-8 animate-spin rounded-full border-2 border-outline border-t-primary dark:border-outline-dark dark:border-t-primary-dark"></div>
|
|
11
|
+
<p class="text-sm text-on-surface/70 dark:text-on-surface-dark/70">Loading…</p>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|