@mauroandre/velojs 0.0.12 → 0.0.14

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 CHANGED
@@ -52,6 +52,7 @@ export default defineConfig({
52
52
  "scripts": {
53
53
  "dev": "velojs dev",
54
54
  "build": "velojs build",
55
+ "build:static": "velojs build --static",
55
56
  "start": "velojs start"
56
57
  }
57
58
  }
@@ -619,10 +620,12 @@ export const Component = ({ children }) => (
619
620
  **Production:**
620
621
  ```html
621
622
  <link rel="icon" href="/favicon.ico" type="image/x-icon" />
622
- <link rel="stylesheet" href="/client.css" />
623
- <script type="module" src="/client.js"></script>
623
+ <link rel="stylesheet" href="/client.a1b2c3.css" />
624
+ <script type="module" src="/client.x9y8z7.js"></script>
624
625
  ```
625
626
 
627
+ Asset filenames include a content hash for cache busting. The hash changes only when the file content changes.
628
+
626
629
  ---
627
630
 
628
631
  ## Middlewares
@@ -984,6 +987,87 @@ interface VeloConfig {
984
987
 
985
988
  ---
986
989
 
990
+ ## Static Site Generation (SSG)
991
+
992
+ Build a fully static site with pre-rendered HTML and JSON files:
993
+
994
+ ```bash
995
+ velojs build --static
996
+ ```
997
+
998
+ ### Output
999
+
1000
+ ```
1001
+ dist/
1002
+ index.html # Pre-rendered HTML
1003
+ index.json # Loader data
1004
+ about/
1005
+ index.html
1006
+ index.json
1007
+ client/
1008
+ client.a1b2c3.js
1009
+ client.x9y8z7.css
1010
+ logos/ # Files from public/ are copied to dist/
1011
+ logo.svg
1012
+ ```
1013
+
1014
+ ### Public assets
1015
+
1016
+ Files in the `public/` folder are automatically copied to `dist/` root during static generation. Reference them with absolute paths:
1017
+
1018
+ ```tsx
1019
+ <img src="/logos/logo.svg" />
1020
+ ```
1021
+
1022
+ This works in both dev mode (Vite serves `public/` at root) and static builds (`public/` is copied to `dist/`).
1023
+
1024
+ ### Dynamic routes
1025
+
1026
+ For routes with `:params`, export a `staticPaths` function that returns all possible parameter combinations:
1027
+
1028
+ ```typescript
1029
+ // app/pages/UserDetail.tsx
1030
+ export const staticPaths = async () => {
1031
+ const { getUsers } = await import("./user.service.js");
1032
+ const users = await getUsers();
1033
+ return users.map((u) => ({ id: u.id }));
1034
+ };
1035
+ ```
1036
+
1037
+ Routes without `staticPaths` are skipped with a warning.
1038
+
1039
+ ### Deploying
1040
+
1041
+ The `dist/` folder is self-contained. Deploy to any static hosting (Nginx, Cloudflare Pages, S3, etc.). No server required.
1042
+
1043
+ ---
1044
+
1045
+ ## Cache Busting & Auto-Update Detection
1046
+
1047
+ VeloJS has built-in cache management for zero-downtime deployments:
1048
+
1049
+ ### Content-hashed assets
1050
+
1051
+ JS and CSS files are generated with content hashes (`client.a1b2c3.js`). When the content changes, the hash changes, and browsers automatically fetch the new version. Unchanged assets stay cached indefinitely.
1052
+
1053
+ ### HTML no-cache
1054
+
1055
+ HTML responses include `Cache-Control: no-cache`, so browsers always check for the latest version. Since HTML is small (a few KB), this has negligible performance impact.
1056
+
1057
+ ### SPA deploy detection
1058
+
1059
+ When a user is navigating a SPA and a new deploy happens, VeloJS detects it automatically:
1060
+
1061
+ 1. Each build generates a unique `__VELO_BUILD_HASH__`, embedded in the client JS
1062
+ 2. JSON data responses (both SSR and SSG) include a `__buildHash` field
1063
+ 3. On SPA navigation, `useLoader` compares the response hash with the client hash
1064
+ 4. If they differ, an internal `__veloUpdatePending` flag is set
1065
+ 5. On the next `<Link>` click, VeloJS does a full page navigation instead of SPA — loading the new HTML with updated asset references
1066
+
1067
+ This means users get the new version without needing `Ctrl+Shift+R`. The transition is seamless — from the user's perspective, it looks like a normal page navigation.
1068
+
1069
+ ---
1070
+
987
1071
  ## Docker / Production Deploy
988
1072
 
989
1073
  ### Dockerfile
@@ -1014,12 +1098,15 @@ CMD ["npx", "velojs", "start"]
1014
1098
  velojs build
1015
1099
  # dist/
1016
1100
  # client/ # Static assets (JS, CSS, images)
1017
- # client.js
1018
- # client.css
1101
+ # client.a1b2c3.js
1102
+ # client.x9y8z7.css
1103
+ # .vite/manifest.json
1019
1104
  # server.js # SSR server entry (single file)
1020
1105
  ```
1021
1106
 
1022
- In production, `velojs start` sets `NODE_ENV=production` automatically and serves static files from `dist/client/`.
1107
+ Asset filenames include content hashes for long-term browser caching. The server build reads the Vite manifest to inject the correct filenames into `<Scripts>`.
1108
+
1109
+ In production, `velojs start` sets `NODE_ENV=production` automatically and serves static files from `dist/client/`. HTML responses are served with `Cache-Control: no-cache` so browsers always fetch the latest HTML (which references the current hashed assets).
1023
1110
 
1024
1111
  ### Static assets on CDN
1025
1112
 
@@ -1,31 +1,48 @@
1
- import { jsx as i, jsxs as u, Fragment as p } from "preact/jsx-runtime";
2
- import { Link as m } from "wouter-preact";
3
- function y({ basePath: e, favicon: n = "/favicon.ico" } = {}) {
1
+ import { jsx as r, jsxs as u, Fragment as a } from "preact/jsx-runtime";
2
+ import { Link as S } from "wouter-preact";
3
+ import { __veloUpdatePending as v } from "./hooks.js";
4
+ function C({ basePath: e, favicon: n = "/favicon.ico" } = {}) {
4
5
  const t = process.env.NODE_ENV !== "production";
5
6
  e = e || process.env.STATIC_BASE_URL || (process.env.VELO_STATIC ? "/client" : "");
6
- const r = n !== !1 && /* @__PURE__ */ i("link", { rel: "icon", href: `${e}${n}`, type: "image/x-icon" });
7
- return t ? /* @__PURE__ */ u(p, { children: [
8
- r,
9
- /* @__PURE__ */ i("script", { type: "module", src: "/@vite/client" }),
10
- /* @__PURE__ */ i("script", { type: "module", src: "/__velo_client.js" })
11
- ] }) : /* @__PURE__ */ u(p, { children: [
12
- r,
13
- /* @__PURE__ */ i("link", { rel: "stylesheet", href: `${e}/client.css` }),
14
- /* @__PURE__ */ i("script", { type: "module", src: `${e}/client.js` })
7
+ const i = n !== !1 && /* @__PURE__ */ r("link", { rel: "icon", href: `${e}${n}`, type: "image/x-icon" });
8
+ if (t)
9
+ return /* @__PURE__ */ u(a, { children: [
10
+ i,
11
+ /* @__PURE__ */ r("script", { type: "module", src: "/@vite/client" }),
12
+ /* @__PURE__ */ r("script", { type: "module", src: "/__velo_client.js" })
13
+ ] });
14
+ const o = typeof __VELO_CLIENT_JS__ < "u" ? __VELO_CLIENT_JS__ : "client.js";
15
+ return /* @__PURE__ */ u(a, { children: [
16
+ i,
17
+ /* @__PURE__ */ r("link", { rel: "stylesheet", href: `${e}/${typeof __VELO_CLIENT_CSS__ < "u" ? __VELO_CLIENT_CSS__ : "client.css"}` }),
18
+ /* @__PURE__ */ r("script", { type: "module", src: `${e}/${o}` })
15
19
  ] });
16
20
  }
17
- function $(e, n) {
21
+ function E(e, n) {
18
22
  let t = e;
19
- for (const [r, c] of Object.entries(n))
20
- t = t.replace(`:${r}`, c);
23
+ for (const [i, o] of Object.entries(n))
24
+ t = t.replace(`:${i}`, o);
21
25
  return t;
22
26
  }
23
- function S({ to: e, params: n, search: t, absolute: r, ...c }) {
24
- const s = typeof e != "string", o = s ? (r ? e.metadata?.fullPath : e.metadata?.path) ?? "/" : e, l = n ? $(o, n) : o, f = s && r ? `~${l}` : l, a = t ? `?${new URLSearchParams(t).toString()}` : "";
25
- return /* @__PURE__ */ i(m, { to: `${f}${a}`, ...c });
27
+ function T({ to: e, params: n, search: t, absolute: i, ...o }) {
28
+ const c = typeof e != "string", _ = c ? (i ? e.metadata?.fullPath : e.metadata?.path) ?? "/" : e, f = n ? E(_, n) : _, d = c && i ? `~${f}` : f, m = t ? `?${new URLSearchParams(t).toString()}` : "", s = `${d}${m}`;
29
+ if (typeof window < "u" && v.value) {
30
+ const { onClick: p, ...L } = o;
31
+ return /* @__PURE__ */ r(
32
+ "a",
33
+ {
34
+ href: s.replace(/^~/, ""),
35
+ onClick: (l) => {
36
+ p && p(l), l.defaultPrevented || (l.preventDefault(), window.location.href = s.replace(/^~/, ""));
37
+ },
38
+ ...L
39
+ }
40
+ );
41
+ }
42
+ return /* @__PURE__ */ r(S, { to: s, ...o });
26
43
  }
27
44
  export {
28
- S as Link,
29
- y as Scripts,
30
- $ as substituteParams
45
+ T as Link,
46
+ C as Scripts,
47
+ E as substituteParams
31
48
  };
package/dist/hooks.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { type Signal } from "@preact/signals";
2
+ export declare const __veloUpdatePending: Signal<boolean>;
2
3
  /**
3
4
  * Força o signal a notificar mudanças após mutação de propriedades aninhadas
4
5
  *
package/dist/hooks.js CHANGED
@@ -1,11 +1,12 @@
1
- import { signal as d, useSignal as v } from "@preact/signals";
1
+ import { signal as c, useSignal as v } from "@preact/signals";
2
2
  import { useRef as D, useEffect as p } from "preact/hooks";
3
3
  import { useLocation as w, useParams as S } from "wouter-preact";
4
+ const y = c(!1);
4
5
  function P(e) {
5
6
  e.value !== null && typeof e.value == "object" && (e.value = { ...e.value });
6
7
  }
7
8
  function T(e) {
8
- const a = d(!1);
9
+ const a = c(!1);
9
10
  if (typeof window > "u")
10
11
  return { data: {
11
12
  get value() {
@@ -13,50 +14,50 @@ function T(e) {
13
14
  }
14
15
  }, loading: a };
15
16
  const t = window.__PAGE_DATA__, n = e && t?.[e] ? t[e] : null;
16
- return { data: d(n), loading: a };
17
+ return { data: c(n), loading: a };
17
18
  }
18
- function L(e, a) {
19
+ function E(e, a) {
19
20
  let t, n;
20
21
  Array.isArray(e) ? n = e : (t = e, n = a);
21
22
  let r = null;
22
23
  if (typeof window > "u" && t) {
23
- const c = globalThis.__veloServerData?.getStore?.();
24
- c?.[t] && (r = c[t]);
24
+ const u = globalThis.__veloServerData?.getStore?.();
25
+ u?.[t] && (r = u[t]);
25
26
  }
26
27
  if (typeof window < "u" && t) {
27
28
  const o = window.__PAGE_DATA__;
28
29
  o?.[t] && (r = o[t], delete o[t]);
29
30
  }
30
- const u = v(r), i = v(!1), _ = () => {
31
+ const _ = v(r), i = v(!1), f = () => {
31
32
  if (typeof window > "u" || !t) return;
32
33
  const o = window.location.pathname;
33
34
  i.value = !0;
34
- const l = typeof __VELO_STATIC__ < "u" && __VELO_STATIC__ ? `${o === "/" ? "" : o}/index.json` : (() => {
35
+ const d = typeof __VELO_STATIC__ < "u" && __VELO_STATIC__ ? `${o === "/" ? "" : o}/index.json` : (() => {
35
36
  const s = new URLSearchParams(window.location.search);
36
37
  return s.set("_data", "1"), `${o}?${s.toString()}`;
37
- })(), g = l.includes("?") ? "&" : "?", h = typeof __VELO_BUILD_HASH__ < "u" ? `${g}v=${__VELO_BUILD_HASH__}` : "";
38
- fetch(`${l}${h}`).then((s) => s.json()).then((s) => {
39
- u.value = s[t], i.value = !1;
38
+ })(), g = d.includes("?") ? "&" : "?", h = typeof __VELO_BUILD_HASH__ < "u" ? `${g}v=${__VELO_BUILD_HASH__}` : "";
39
+ fetch(`${d}${h}`).then((s) => s.json()).then((s) => {
40
+ typeof __VELO_BUILD_HASH__ < "u" && s.__buildHash && s.__buildHash !== __VELO_BUILD_HASH__ && (y.value = !0), _.value = s[t], i.value = !1;
40
41
  }).catch(() => {
41
42
  i.value = !1;
42
43
  });
43
- }, f = D(r !== null);
44
+ }, l = D(r !== null);
44
45
  return p(() => {
45
- if (f.current) {
46
- f.current = !1;
46
+ if (l.current) {
47
+ l.current = !1;
47
48
  return;
48
49
  }
49
- _();
50
- }, n ?? []), { data: u, loading: i, refetch: _ };
50
+ f();
51
+ }, n ?? []), { data: _, loading: i, refetch: f };
51
52
  }
52
- function E() {
53
+ function H() {
53
54
  const [, e] = w();
54
55
  return e;
55
56
  }
56
- function $() {
57
+ function b() {
57
58
  return typeof window > "u" ? globalThis.__veloServerData?.getStore?.()?.__params ?? {} : S();
58
59
  }
59
- function b() {
60
+ function U() {
60
61
  if (typeof window > "u")
61
62
  return globalThis.__veloServerData?.getStore?.()?.__query ?? {};
62
63
  const e = window.__PAGE_DATA__;
@@ -67,15 +68,16 @@ function b() {
67
68
  t[r] = n;
68
69
  }), t;
69
70
  }
70
- function H() {
71
+ function $() {
71
72
  return typeof window > "u" ? globalThis.__veloServerData?.getStore?.()?.__pathname ?? "/" : (w(), window.location.pathname);
72
73
  }
73
74
  export {
74
75
  T as Loader,
76
+ y as __veloUpdatePending,
75
77
  P as touch,
76
- L as useLoader,
77
- E as useNavigate,
78
- $ as useParams,
79
- H as usePathname,
80
- b as useQuery
78
+ E as useLoader,
79
+ H as useNavigate,
80
+ b as useParams,
81
+ $ as usePathname,
82
+ U as useQuery
81
83
  };
package/dist/server.js CHANGED
@@ -1,48 +1,50 @@
1
1
  import { jsx as h } from "preact/jsx-runtime";
2
- import { Hono as T } from "hono";
3
- import { logger as A } from "hono/logger";
2
+ import { Hono as P } from "hono";
3
+ import { logger as T } from "hono/logger";
4
4
  import { trimTrailingSlash as D } from "hono/trailing-slash";
5
- import { render as R } from "preact-render-to-string";
6
- import { Router as N } from "wouter-preact";
7
- import { AsyncLocalStorage as O } from "node:async_hooks";
8
- const v = new O();
5
+ import { render as O } from "preact-render-to-string";
6
+ import { Router as b } from "wouter-preact";
7
+ import { AsyncLocalStorage as I } from "node:async_hooks";
8
+ const v = new I();
9
9
  globalThis.__veloServerData = v;
10
- const g = [];
10
+ const _ = [];
11
11
  let p = null;
12
- function x(t) {
12
+ function M(t) {
13
13
  if (p) {
14
14
  t(p);
15
15
  return;
16
16
  }
17
- g.push(t);
17
+ _.push(t);
18
18
  }
19
19
  function y(t) {
20
20
  p = t;
21
- for (const e of g) e(t);
22
- g.length = 0;
21
+ for (const e of _) e(t);
22
+ _.length = 0;
23
23
  }
24
- const w = [];
25
- function B(t) {
26
- w.push(t);
24
+ const S = [];
25
+ function G(t) {
26
+ S.push(t);
27
27
  }
28
- const I = (t, e, o) => {
29
- if (t.req.query("_data") === "1")
30
- return t.json(o ?? null);
31
- const s = t.req.path, r = v.run(
28
+ const R = (t, e, o) => {
29
+ if (t.req.query("_data") === "1") {
30
+ const c = typeof __VELO_BUILD_HASH__ < "u" ? __VELO_BUILD_HASH__ : void 0, r = o ? { ...o, __buildHash: c } : { __buildHash: c };
31
+ return t.json(r);
32
+ }
33
+ const s = t.req.path, n = v.run(
32
34
  o ?? {},
33
- () => R(/* @__PURE__ */ h(N, { ssrPath: s, children: e }))
35
+ () => O(/* @__PURE__ */ h(b, { ssrPath: s, children: e }))
34
36
  );
35
- if (!o)
36
- return t.html(r);
37
+ if (t.header("Cache-Control", "no-cache"), !o)
38
+ return t.html(n);
37
39
  const a = `<script>window.__PAGE_DATA__=${JSON.stringify(
38
40
  o
39
41
  )}<\/script>`;
40
- return t.html(r.replace("</head>", `${a}</head>`));
41
- }, b = async (t, e) => {
42
- const o = e.req.param(), s = e.req.query(), r = { params: o, query: s, c: e }, a = await Promise.all(
43
- t.map(async (n) => {
44
- if (!n.loader) return null;
45
- const u = await n.loader(r), i = n.metadata?.moduleId;
42
+ return t.html(n.replace("</head>", `${a}</head>`));
43
+ }, C = async (t, e) => {
44
+ const o = e.req.param(), s = e.req.query(), n = { params: o, query: s, c: e }, a = await Promise.all(
45
+ t.map(async (r) => {
46
+ if (!r.loader) return null;
47
+ const u = await r.loader(n), i = r.metadata?.moduleId;
46
48
  return i ? { moduleId: i, loaderData: u } : null;
47
49
  })
48
50
  ), c = {
@@ -50,81 +52,81 @@ const I = (t, e, o) => {
50
52
  __query: s,
51
53
  __pathname: e.req.path
52
54
  };
53
- for (const n of a)
54
- n && (c[n.moduleId] = n.loaderData);
55
+ for (const r of a)
56
+ r && (c[r.moduleId] = r.loaderData);
55
57
  return {
56
- components: t.map((n) => n.Component),
58
+ components: t.map((r) => r.Component),
57
59
  data: c
58
60
  };
59
- }, j = (t) => {
61
+ }, N = (t) => {
60
62
  if (t.length === 0) return null;
61
63
  const e = t.filter(Boolean);
62
64
  if (e.length === 0) return null;
63
65
  if (e.length === 1) {
64
- const r = e[0];
65
- return /* @__PURE__ */ h(r, {});
66
+ const n = e[0];
67
+ return /* @__PURE__ */ h(n, {});
66
68
  }
67
69
  const o = e[e.length - 1];
68
- return e.slice(0, -1).reduceRight((r, a) => /* @__PURE__ */ h(a, { children: r }), /* @__PURE__ */ h(o, {}));
69
- }, S = (t, e, o = [], s = []) => {
70
- for (const r of e) {
71
- const a = [...o, r.module], c = [
70
+ return e.slice(0, -1).reduceRight((n, a) => /* @__PURE__ */ h(a, { children: n }), /* @__PURE__ */ h(o, {}));
71
+ }, w = (t, e, o = [], s = []) => {
72
+ for (const n of e) {
73
+ const a = [...o, n.module], c = [
72
74
  ...s,
73
- ...r.middlewares || []
75
+ ...n.middlewares || []
74
76
  ];
75
- if (r.children)
76
- S(
77
+ if (n.children)
78
+ w(
77
79
  t,
78
- r.children,
80
+ n.children,
79
81
  a,
80
82
  c
81
83
  );
82
84
  else {
83
- const n = r.module.metadata?.fullPath;
84
- if (!n) {
85
+ const r = n.module.metadata?.fullPath;
86
+ if (!r) {
85
87
  console.warn(
86
- `Module ${r.module.metadata?.moduleId} has no fullPath`
88
+ `Module ${n.module.metadata?.moduleId} has no fullPath`
87
89
  );
88
90
  continue;
89
91
  }
90
92
  const u = async (i) => {
91
- const { components: d, data: f } = await b(a, i), l = j(d);
92
- return I(i, l, f);
93
+ const { components: d, data: f } = await C(a, i), l = N(d);
94
+ return R(i, l, f);
93
95
  };
94
- c.length > 0 ? t.on(["GET"], [n], ...c, u) : t.on(["GET"], [n], u);
96
+ c.length > 0 ? t.on(["GET"], [r], ...c, u) : t.on(["GET"], [r], u);
95
97
  }
96
98
  }
97
- }, q = (t, e, o = []) => {
99
+ }, E = (t, e, o = []) => {
98
100
  for (const s of e) {
99
- const r = s.module.metadata?.moduleId, a = [
101
+ const n = s.module.metadata?.moduleId, a = [
100
102
  ...o,
101
103
  ...s.middlewares || []
102
104
  ];
103
- if (r) {
105
+ if (n) {
104
106
  const c = Object.keys(s.module).filter(
105
- (n) => n.startsWith("action_")
107
+ (r) => r.startsWith("action_")
106
108
  );
107
- for (const n of c) {
108
- const u = n.replace("action_", ""), i = s.module[n];
109
+ for (const r of c) {
110
+ const u = r.replace("action_", ""), i = s.module[r];
109
111
  if (typeof i == "function") {
110
- const d = `/_action/${r}/${u}`, f = async (l) => {
111
- let _ = {};
112
+ const d = `/_action/${n}/${u}`, f = async (l) => {
113
+ let g = {};
112
114
  try {
113
- _ = await l.req.json();
115
+ g = await l.req.json();
114
116
  } catch {
115
117
  }
116
- const E = {
117
- body: _,
118
+ const q = {
119
+ body: g,
118
120
  params: l.req.param(),
119
121
  query: l.req.query(),
120
122
  c: l
121
123
  };
122
124
  try {
123
- const m = await i(E);
125
+ const m = await i(q);
124
126
  return l.json(m ?? { ok: !0 });
125
127
  } catch (m) {
126
- const P = m instanceof Error ? m.message : "Action failed";
127
- return l.json({ error: P }, 500);
128
+ const A = m instanceof Error ? m.message : "Action failed";
129
+ return l.json({ error: A }, 500);
128
130
  }
129
131
  };
130
132
  a.length > 0 ? t.on(
@@ -136,33 +138,33 @@ const I = (t, e, o) => {
136
138
  }
137
139
  }
138
140
  }
139
- s.children && q(t, s.children, a);
141
+ s.children && E(t, s.children, a);
140
142
  }
141
- }, C = async (t) => {
142
- const e = new T();
143
- e.use(D()), process.env.NODE_ENV !== "production" && e.use("*", A());
144
- for (const o of w)
143
+ }, j = async (t) => {
144
+ const e = new P();
145
+ e.use(D()), process.env.NODE_ENV !== "production" && e.use("*", T());
146
+ for (const o of S)
145
147
  await o(e);
146
- if (S(e, t), q(e, t), process.env.NODE_ENV !== "production" && !p) {
148
+ if (w(e, t), E(e, t), process.env.NODE_ENV !== "production" && !p) {
147
149
  const o = globalThis.__veloDevServer;
148
150
  o && y(o);
149
151
  }
150
152
  return e;
151
- }, K = async (t) => {
152
- const { routes: e, port: o = Number(process.env.SERVER_PORT) || 3e3 } = t, s = await C(e);
153
+ }, x = async (t) => {
154
+ const { routes: e, port: o = Number(process.env.SERVER_PORT) || 3e3 } = t, s = await j(e);
153
155
  if (process.env.NODE_ENV === "production" && !process.env.VELO_STATIC) {
154
- const { serve: r } = await import("@hono/node-server"), { serveStatic: a } = await import("@hono/node-server/serve-static"), { join: c } = await import("node:path"), n = c(process.cwd(), "dist/client");
155
- (process.env.STATIC_BASE_URL || "").startsWith("http") || s.use("/*", a({ root: n })), console.log(`Server running on http://localhost:${o}`);
156
- const i = r({ fetch: s.fetch, port: o });
156
+ const { serve: n } = await import("@hono/node-server"), { serveStatic: a } = await import("@hono/node-server/serve-static"), { join: c } = await import("node:path"), r = c(process.cwd(), "dist/client");
157
+ (process.env.STATIC_BASE_URL || "").startsWith("http") || s.use("/*", a({ root: r })), console.log(`Server running on http://localhost:${o}`);
158
+ const i = n({ fetch: s.fetch, port: o });
157
159
  y(i);
158
160
  }
159
161
  return s;
160
162
  };
161
163
  export {
162
- B as addRoutes,
163
- C as createApp,
164
- C as default,
165
- x as onServer,
164
+ G as addRoutes,
165
+ j as createApp,
166
+ j as default,
167
+ M as onServer,
166
168
  v as serverDataStorage,
167
- K as startServer
169
+ x as startServer
168
170
  };
package/dist/static.js CHANGED
@@ -1,62 +1,75 @@
1
- import f from "node:fs";
2
- import r from "node:path";
3
- async function h(a, n = "") {
4
- const o = [];
5
- for (const t of a) {
6
- const s = t.module.metadata?.fullPath ?? "";
1
+ import i from "node:fs";
2
+ import a from "node:path";
3
+ async function h(c, n = "") {
4
+ const e = [];
5
+ for (const t of c) {
6
+ const o = t.module.metadata?.fullPath ?? "";
7
7
  if (t.children) {
8
- const e = await h(t.children, s);
9
- o.push(...e);
8
+ const s = await h(t.children, o);
9
+ e.push(...s);
10
10
  } else {
11
- const e = t.module.metadata?.fullPath;
12
- if (!e) continue;
13
- const l = Object.keys(t.module).filter((c) => c.startsWith("action_"));
14
- if (l.length > 0 && console.warn(
15
- `⚠ Route ${e} has actions (${l.join(", ")}) — they won't work in static mode`
16
- ), e.includes(":")) {
17
- const c = t.module.staticPaths;
18
- if (typeof c == "function") {
19
- const i = await c();
20
- for (const d of i) {
21
- let u = e;
22
- for (const [m, p] of Object.entries(d))
23
- u = u.replace(`:${m}`, p);
24
- o.push({ fullPath: u, module: t.module });
11
+ const s = t.module.metadata?.fullPath;
12
+ if (!s) continue;
13
+ const r = Object.keys(t.module).filter((l) => l.startsWith("action_"));
14
+ if (r.length > 0 && console.warn(
15
+ `⚠ Route ${s} has actions (${r.join(", ")}) — they won't work in static mode`
16
+ ), s.includes(":")) {
17
+ const l = t.module.staticPaths;
18
+ if (typeof l == "function") {
19
+ const u = await l();
20
+ for (const d of u) {
21
+ let f = s;
22
+ for (const [p, m] of Object.entries(d))
23
+ f = f.replace(`:${p}`, m);
24
+ e.push({ fullPath: f, module: t.module });
25
25
  }
26
26
  } else
27
27
  console.warn(
28
- `Skipping ${e} — dynamic route without staticPaths export`
28
+ `Skipping ${s} — dynamic route without staticPaths export`
29
29
  );
30
30
  } else
31
- o.push({ fullPath: e, module: t.module });
31
+ e.push({ fullPath: s, module: t.module });
32
32
  }
33
33
  }
34
- return o;
34
+ return e;
35
35
  }
36
- async function w(a, n, o) {
37
- const t = "http://localhost", s = await a.fetch(new Request(`${t}${n}`));
38
- if (s.status !== 200) {
39
- console.warn(`Skipping ${n} — got status ${s.status}`);
36
+ async function y(c, n, e) {
37
+ const t = "http://localhost", o = await c.fetch(new Request(`${t}${n}`));
38
+ if (o.status !== 200) {
39
+ console.warn(`Skipping ${n} — got status ${o.status}`);
40
40
  return;
41
41
  }
42
- const e = await s.text(), c = await (await a.fetch(
42
+ const s = await o.text(), l = await (await c.fetch(
43
43
  new Request(`${t}${n}?_data=1`)
44
- )).text(), i = n === "/" ? o : r.join(o, n);
45
- f.mkdirSync(i, { recursive: !0 }), f.writeFileSync(r.join(i, "index.html"), e), f.writeFileSync(r.join(i, "index.json"), c);
44
+ )).text(), u = n === "/" ? e : a.join(e, n);
45
+ i.mkdirSync(u, { recursive: !0 }), i.writeFileSync(a.join(u, "index.html"), s), i.writeFileSync(a.join(u, "index.json"), l);
46
46
  }
47
- async function $(a, n) {
48
- const o = r.resolve(process.cwd(), "dist");
47
+ function w(c) {
48
+ const n = a.resolve(process.cwd(), "public");
49
+ if (!i.existsSync(n)) return;
50
+ const e = (t, o) => {
51
+ if (i.statSync(t).isDirectory()) {
52
+ i.mkdirSync(o, { recursive: !0 });
53
+ for (const r of i.readdirSync(t))
54
+ e(a.join(t, r), a.join(o, r));
55
+ } else
56
+ i.copyFileSync(t, o);
57
+ };
58
+ e(n, c);
59
+ }
60
+ async function j(c, n) {
61
+ const e = a.resolve(process.cwd(), "dist");
49
62
  console.log("Generating static pages...");
50
63
  const t = await h(n);
51
64
  if (t.length === 0) {
52
65
  console.warn("No routes found for static generation.");
53
66
  return;
54
67
  }
55
- for (const s of t)
56
- await w(a, s.fullPath, o), console.log(` ✓ ${s.fullPath}`);
57
- console.log(`
68
+ for (const o of t)
69
+ await y(c, o.fullPath, e), console.log(` ✓ ${o.fullPath}`);
70
+ w(e), console.log(`
58
71
  Generated ${t.length} static pages.`);
59
72
  }
60
73
  export {
61
- $ as generateStatic
74
+ j as generateStatic
62
75
  };
package/dist/vite.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import d from "node:path";
2
- import S from "node:fs";
3
- import F from "@preact/preset-vite";
4
- import w from "@hono/vite-dev-server";
2
+ import b from "node:fs";
3
+ import C from "@preact/preset-vite";
4
+ import F from "@hono/vite-dev-server";
5
5
  import { parse as v } from "@babel/parser";
6
6
  import L from "@babel/traverse";
7
7
  import j from "@babel/generator";
8
8
  import * as e from "@babel/types";
9
- const m = typeof L == "function" ? L : L.default, h = typeof j == "function" ? j : j.default;
10
- function C(u, o, r, l) {
9
+ const m = typeof L == "function" ? L : L.default, S = typeof j == "function" ? j : j.default;
10
+ function w(u, c, r, l) {
11
11
  const i = v(u, {
12
12
  sourceType: "module",
13
13
  plugins: ["typescript", "jsx"]
@@ -16,28 +16,28 @@ function C(u, o, r, l) {
16
16
  if (m(i, {
17
17
  // Procura: export const metadata = { ... }
18
18
  ExportNamedDeclaration(s) {
19
- const c = s.node.declaration;
20
- if (e.isVariableDeclaration(c) && c.declarations.length === 1) {
21
- const a = c.declarations[0];
19
+ const o = s.node.declaration;
20
+ if (e.isVariableDeclaration(o) && o.declarations.length === 1) {
21
+ const a = o.declarations[0];
22
22
  if (a && e.isIdentifier(a.id, { name: "metadata" }) && e.isObjectExpression(a.init)) {
23
23
  t = !0;
24
- const f = a.init.properties.filter((y) => e.isObjectProperty(y) && e.isIdentifier(y.key) ? y.key.name !== "moduleId" && y.key.name !== "fullPath" && y.key.name !== "path" : !0), x = [
24
+ const p = a.init.properties.filter((y) => e.isObjectProperty(y) && e.isIdentifier(y.key) ? y.key.name !== "moduleId" && y.key.name !== "fullPath" && y.key.name !== "path" : !0), h = [
25
25
  e.objectProperty(
26
26
  e.identifier("moduleId"),
27
- e.stringLiteral(o)
27
+ e.stringLiteral(c)
28
28
  )
29
29
  ];
30
- r !== void 0 && x.push(
30
+ r !== void 0 && h.push(
31
31
  e.objectProperty(
32
32
  e.identifier("fullPath"),
33
33
  e.stringLiteral(r)
34
34
  )
35
- ), l !== void 0 && x.push(
35
+ ), l !== void 0 && h.push(
36
36
  e.objectProperty(
37
37
  e.identifier("path"),
38
38
  e.stringLiteral(l)
39
39
  )
40
- ), a.init.properties = [...x, ...f];
40
+ ), a.init.properties = [...h, ...p];
41
41
  }
42
42
  }
43
43
  }
@@ -45,7 +45,7 @@ function C(u, o, r, l) {
45
45
  const s = [
46
46
  e.objectProperty(
47
47
  e.identifier("moduleId"),
48
- e.stringLiteral(o)
48
+ e.stringLiteral(c)
49
49
  )
50
50
  ];
51
51
  r !== void 0 && s.push(
@@ -59,7 +59,7 @@ function C(u, o, r, l) {
59
59
  e.stringLiteral(l)
60
60
  )
61
61
  );
62
- const c = e.exportNamedDeclaration(
62
+ const o = e.exportNamedDeclaration(
63
63
  e.variableDeclaration("const", [
64
64
  e.variableDeclarator(
65
65
  e.identifier("metadata"),
@@ -67,11 +67,11 @@ function C(u, o, r, l) {
67
67
  )
68
68
  ])
69
69
  );
70
- i.program.body.unshift(c);
70
+ i.program.body.unshift(o);
71
71
  }
72
- return h(i, { retainLines: !0 }).code;
72
+ return S(i, { retainLines: !0 }).code;
73
73
  }
74
- function R(u, o) {
74
+ function R(u, c) {
75
75
  const r = v(u, {
76
76
  sourceType: "module",
77
77
  plugins: ["typescript", "jsx"]
@@ -80,12 +80,12 @@ function R(u, o) {
80
80
  CallExpression(i) {
81
81
  const t = i.node.callee, n = e.isIdentifier(t, { name: "Loader" }) || e.isTSInstantiationExpression(t) && e.isIdentifier(t.expression, { name: "Loader" }), s = e.isIdentifier(t, { name: "useLoader" }) || e.isTSInstantiationExpression(t) && e.isIdentifier(t.expression, { name: "useLoader" });
82
82
  if (!n && !s) return;
83
- const c = i.node.arguments, a = e.stringLiteral(o), p = c[0];
84
- e.isStringLiteral(p) && p.value.includes("/") || (i.node.arguments = [a, ...c]);
83
+ const o = i.node.arguments, a = e.stringLiteral(c), f = o[0];
84
+ e.isStringLiteral(f) && f.value.includes("/") || (i.node.arguments = [a, ...o]);
85
85
  }
86
- }), h(r, { retainLines: !0 }).code;
86
+ }), S(r, { retainLines: !0 }).code;
87
87
  }
88
- function V(u, o) {
88
+ function V(u, c) {
89
89
  const r = v(u, {
90
90
  sourceType: "module",
91
91
  plugins: ["typescript", "jsx"]
@@ -98,15 +98,15 @@ function V(u, o) {
98
98
  if (!n || !e.isIdentifier(n.id)) return;
99
99
  const s = n.id.name;
100
100
  if (!s.startsWith("action_")) return;
101
- const c = s.replace("action_", ""), a = n.init;
101
+ const o = s.replace("action_", ""), a = n.init;
102
102
  if (!e.isArrowFunctionExpression(a) || !a.async) return;
103
- const p = a.params, f = W(o, c, p);
104
- a.body = e.blockStatement([e.returnStatement(f)]), $(a, p);
103
+ const f = a.params, p = W(c, o, f);
104
+ a.body = e.blockStatement([e.returnStatement(p)]), $(a, f);
105
105
  }
106
- }), h(r, { retainLines: !0 }).code;
106
+ }), S(r, { retainLines: !0 }).code;
107
107
  }
108
- function W(u, o, r) {
109
- const l = `/_action/${u}/${o}`;
108
+ function W(u, c, r) {
109
+ const l = `/_action/${u}/${c}`;
110
110
  return r.length === 0 ? e.callExpression(
111
111
  e.memberExpression(
112
112
  e.callExpression(e.identifier("fetch"), [
@@ -175,9 +175,9 @@ function W(u, o, r) {
175
175
  ]
176
176
  );
177
177
  }
178
- function $(u, o) {
179
- if (o.length === 0) return;
180
- const r = o[0];
178
+ function $(u, c) {
179
+ if (c.length === 0) return;
180
+ const r = c[0];
181
181
  if (e.isObjectPattern(r)) {
182
182
  let l = null;
183
183
  if (e.isTSTypeAnnotation(r.typeAnnotation) && e.isTSTypeReference(r.typeAnnotation.typeAnnotation)) {
@@ -202,25 +202,25 @@ function $(u, o) {
202
202
  }
203
203
  }
204
204
  function U(u) {
205
- const o = v(u, {
205
+ const c = v(u, {
206
206
  sourceType: "module",
207
207
  plugins: ["typescript", "jsx"]
208
208
  });
209
- return m(o, {
209
+ return m(c, {
210
210
  ExportNamedDeclaration(l) {
211
211
  const i = l.node.declaration;
212
212
  if (!e.isVariableDeclaration(i)) return;
213
213
  const t = i.declarations[0];
214
214
  !t || !e.isIdentifier(t.id) || t.id.name === "loader" && l.remove();
215
215
  }
216
- }), h(o, { retainLines: !0 }).code;
216
+ }), S(c, { retainLines: !0 }).code;
217
217
  }
218
218
  function k(u) {
219
- const o = v(u, {
219
+ const c = v(u, {
220
220
  sourceType: "module",
221
221
  plugins: ["typescript", "jsx"]
222
222
  }), r = /* @__PURE__ */ new Set();
223
- return m(o, {
223
+ return m(c, {
224
224
  ObjectProperty(i) {
225
225
  if (e.isIdentifier(i.node.key, { name: "middlewares" }) && e.isArrayExpression(i.node.value)) {
226
226
  for (const t of i.node.value.elements)
@@ -228,25 +228,25 @@ function k(u) {
228
228
  i.remove();
229
229
  }
230
230
  }
231
- }), r.size === 0 ? u : (m(o, {
231
+ }), r.size === 0 ? u : (m(c, {
232
232
  ImportDeclaration(i) {
233
233
  const t = i.node.specifiers, n = t.filter((s) => {
234
234
  if (e.isImportSpecifier(s)) {
235
- const c = s.local.name;
236
- return !r.has(c);
235
+ const o = s.local.name;
236
+ return !r.has(o);
237
237
  }
238
238
  return !0;
239
239
  });
240
240
  n.length === 0 ? i.remove() : n.length !== t.length && (i.node.specifiers = n);
241
241
  }
242
- }), h(o, { retainLines: !0 }).code);
242
+ }), S(c, { retainLines: !0 }).code);
243
243
  }
244
- function T(u) {
245
- const o = v(u, {
244
+ function _(u) {
245
+ const c = v(u, {
246
246
  sourceType: "module",
247
247
  plugins: ["typescript", "jsx"]
248
248
  }), r = /* @__PURE__ */ new Map();
249
- m(o, {
249
+ m(c, {
250
250
  ImportDeclaration(t) {
251
251
  const n = t.node.source.value;
252
252
  for (const s of t.node.specifiers)
@@ -254,85 +254,85 @@ function T(u) {
254
254
  }
255
255
  });
256
256
  const l = /* @__PURE__ */ new Map();
257
- m(o, {
257
+ m(c, {
258
258
  ExportDefaultDeclaration(t) {
259
259
  const n = t.node.declaration;
260
260
  let s = null;
261
- e.isArrayExpression(n) ? s = n : e.isTSSatisfiesExpression(n) && e.isArrayExpression(n.expression) && (s = n.expression), s && A(s.elements, "", l);
261
+ e.isArrayExpression(n) ? s = n : e.isTSSatisfiesExpression(n) && e.isArrayExpression(n.expression) && (s = n.expression), s && N(s.elements, "", l);
262
262
  }
263
263
  });
264
264
  const i = /* @__PURE__ */ new Map();
265
265
  for (const [t, n] of l) {
266
266
  const s = r.get(t);
267
267
  if (s) {
268
- const c = s.replace(/^\.\//, "").replace(/\.(tsx?|jsx?|js)$/, "");
269
- i.set(c, n);
268
+ const o = s.replace(/^\.\//, "").replace(/\.(tsx?|jsx?|js)$/, "");
269
+ i.set(o, n);
270
270
  }
271
271
  }
272
272
  return i;
273
273
  }
274
- function A(u, o, r) {
274
+ function N(u, c, r) {
275
275
  for (const l of u) {
276
276
  if (!e.isObjectExpression(l)) continue;
277
- let i = "", t = o, n = null, s = null;
278
- for (const c of l.properties) {
279
- if (!e.isObjectProperty(c)) continue;
280
- const a = c.key, p = e.isIdentifier(a) ? a.name : null;
281
- p === "path" && e.isStringLiteral(c.value) && (i = c.value.value, i && !i.startsWith("/") ? t = o + "/" + i : t = o + i), p === "module" && e.isIdentifier(c.value) && (n = c.value.name), p === "children" && e.isArrayExpression(c.value) && (s = c.value);
277
+ let i = "", t = c, n = null, s = null;
278
+ for (const o of l.properties) {
279
+ if (!e.isObjectProperty(o)) continue;
280
+ const a = o.key, f = e.isIdentifier(a) ? a.name : null;
281
+ f === "path" && e.isStringLiteral(o.value) && (i = o.value.value, i && !i.startsWith("/") ? t = c + "/" + i : t = c + i), f === "module" && e.isIdentifier(o.value) && (n = o.value.name), f === "children" && e.isArrayExpression(o.value) && (s = o.value);
282
282
  }
283
283
  if (n) {
284
- const a = !s && i === "/" ? o || "/" : t;
284
+ const a = !s && i === "/" ? c || "/" : t;
285
285
  r.set(n, {
286
286
  fullPath: a,
287
287
  path: i
288
288
  });
289
289
  }
290
- s && A(s.elements, t, r);
290
+ s && N(s.elements, t, r);
291
291
  }
292
292
  }
293
- const g = "virtual:velo/server-entry", E = "virtual:velo/client-entry", _ = "\0" + g, P = "\0" + E;
294
- function M(u, o) {
295
- let r = d.resolve(process.cwd(), o);
293
+ const g = "virtual:velo/server-entry", x = "virtual:velo/client-entry", T = "\0" + g, P = "\0" + x;
294
+ function J(u, c) {
295
+ let r = d.resolve(process.cwd(), c);
296
296
  const l = u.routesFile ?? "routes.tsx", i = /* @__PURE__ */ new Map();
297
297
  return {
298
298
  name: "velo:transform",
299
299
  enforce: "pre",
300
300
  configResolved(t) {
301
- r = d.resolve(t.root, o);
301
+ r = d.resolve(t.root, c);
302
302
  },
303
303
  buildStart() {
304
304
  const t = d.join(r, l);
305
- if (S.existsSync(t)) {
306
- const n = S.readFileSync(t, "utf-8"), s = T(n);
305
+ if (b.existsSync(t)) {
306
+ const n = b.readFileSync(t, "utf-8"), s = _(n);
307
307
  i.clear();
308
- for (const [c, a] of s)
309
- i.set(c, a);
308
+ for (const [o, a] of s)
309
+ i.set(o, a);
310
310
  }
311
311
  },
312
312
  handleHotUpdate({ file: t, server: n }) {
313
313
  const s = d.join(r, l);
314
314
  if (t === s) {
315
- const c = S.readFileSync(s, "utf-8"), a = T(c);
315
+ const o = b.readFileSync(s, "utf-8"), a = _(o);
316
316
  i.clear();
317
- for (const [p, f] of a)
318
- i.set(p, f);
317
+ for (const [f, p] of a)
318
+ i.set(f, p);
319
319
  return n.ws.send({ type: "full-reload" }), [];
320
320
  }
321
321
  },
322
322
  resolveId(t) {
323
- return t === g || t.endsWith(g) ? _ : t === E || t.endsWith(E) || t === "/__velo_client.js" ? P : null;
323
+ return t === g || t.endsWith(g) ? T : t === x || t.endsWith(x) || t === "/__velo_client.js" ? P : null;
324
324
  },
325
325
  load(t) {
326
- const n = u.routesFile ?? "routes.tsx", s = u.serverInit ?? "server.tsx", c = u.clientInit ?? "client.tsx", a = d.join(r, n).replace(/\.tsx?$/, ".js"), p = d.join(r, s).replace(/\.tsx?$/, ".js"), f = d.join(r, c).replace(/\.tsx?$/, ".js");
327
- return t === _ ? `
328
- import "${p}";
326
+ const n = u.routesFile ?? "routes.tsx", s = u.serverInit ?? "server.tsx", o = u.clientInit ?? "client.tsx", a = d.join(r, n).replace(/\.tsx?$/, ".js"), f = d.join(r, s).replace(/\.tsx?$/, ".js"), p = d.join(r, o).replace(/\.tsx?$/, ".js");
327
+ return t === T ? `
328
+ import "${f}";
329
329
  import routes from "${a}";
330
330
  import { startServer } from "@mauroandre/velojs/server";
331
331
 
332
332
  export { routes };
333
333
  export default await startServer({ routes });
334
334
  ` : t === P ? `
335
- import "${f}";
335
+ import "${p}";
336
336
  import routes from "${a}";
337
337
  import { startClient } from "@mauroandre/velojs/client";
338
338
 
@@ -340,36 +340,46 @@ startClient({ routes });
340
340
  ` : null;
341
341
  },
342
342
  transform(t, n, s) {
343
- const c = s?.ssr === !0;
343
+ const o = s?.ssr === !0;
344
344
  if (n.startsWith("\0") || n.includes("/.velojs/") || !n.endsWith(".tsx") && !n.endsWith(".ts") || !n.startsWith(r)) return null;
345
- let a = t, p = !1;
346
- const f = /middlewares:\s*\[/.test(t), x = /export\s+(const|function)\s+Component/.test(
345
+ let a = t, f = !1;
346
+ const p = /middlewares:\s*\[/.test(t), h = /export\s+(const|function)\s+Component/.test(
347
347
  t
348
- ), y = /export\s+(const|function)\s+loader/.test(t), N = /export\s+const\s+action_\w+/.test(t), D = /\bLoader\s*</.test(t) || /\bLoader\s*\(/.test(t), O = /\buseLoader\s*</.test(t) || /\buseLoader\s*\(/.test(t);
349
- if (!c && f && (a = k(a), p = !0), x || y || N || D || O) {
350
- const b = d.relative(r, n).replace(/\.(tsx?|jsx?)$/, "").replace(/\\/g, "/"), I = i.get(b);
351
- a = C(a, b, I?.fullPath, I?.path), a = R(a, b), c || (a = V(
348
+ ), y = /export\s+(const|function)\s+loader/.test(t), A = /export\s+const\s+action_\w+/.test(t), O = /\bLoader\s*</.test(t) || /\bLoader\s*\(/.test(t), D = /\buseLoader\s*</.test(t) || /\buseLoader\s*\(/.test(t);
349
+ if (!o && p && (a = k(a), f = !0), h || y || A || O || D) {
350
+ const E = d.relative(r, n).replace(/\.(tsx?|jsx?)$/, "").replace(/\\/g, "/"), I = i.get(E);
351
+ a = w(a, E, I?.fullPath, I?.path), a = R(a, E), o || (a = V(
352
352
  a,
353
- b
354
- )), c || (a = U(a)), p = !0;
353
+ E
354
+ )), o || (a = U(a)), f = !0;
355
355
  }
356
- return p ? {
356
+ return f ? {
357
357
  code: a,
358
358
  map: null
359
359
  } : null;
360
360
  }
361
361
  };
362
362
  }
363
- function B() {
363
+ function M() {
364
364
  return {
365
365
  name: "velo:config",
366
- config(u, { mode: o }) {
367
- const r = o === "server", l = o === "development", i = !!process.env.VELO_STATIC, t = {
366
+ config(u, { mode: c }) {
367
+ const r = c === "server", l = c === "development", i = !!process.env.VELO_STATIC;
368
+ let t = "client.js", n = "client.css";
369
+ if (r)
370
+ try {
371
+ const o = d.resolve(process.cwd(), "dist/client/.vite/manifest.json"), f = JSON.parse(b.readFileSync(o, "utf-8"))[x];
372
+ f && (t = f.file || t, f.css?.[0] && (n = f.css[0]));
373
+ } catch {
374
+ }
375
+ const s = {
368
376
  define: {
369
377
  "process.env.NODE_ENV": JSON.stringify(l ? "development" : "production"),
370
378
  "process.env.STATIC_BASE_URL": JSON.stringify(process.env.STATIC_BASE_URL || (i ? "/client" : "")),
371
379
  __VELO_STATIC__: JSON.stringify(i),
372
- __VELO_BUILD_HASH__: JSON.stringify(Date.now().toString(36))
380
+ __VELO_BUILD_HASH__: JSON.stringify(Date.now().toString(36)),
381
+ __VELO_CLIENT_JS__: JSON.stringify(t),
382
+ __VELO_CLIENT_CSS__: JSON.stringify(n)
373
383
  },
374
384
  resolve: {
375
385
  alias: {
@@ -378,7 +388,7 @@ function B() {
378
388
  }
379
389
  }
380
390
  };
381
- return r ? t.build = {
391
+ return r ? s.build = {
382
392
  ssr: g,
383
393
  outDir: "dist",
384
394
  emptyOutDir: !1,
@@ -388,29 +398,29 @@ function B() {
388
398
  entryFileNames: "server.js"
389
399
  }
390
400
  }
391
- } : l || (t.build = {
401
+ } : l || (s.build = {
392
402
  manifest: !0,
393
403
  outDir: "dist/client",
394
404
  rollupOptions: {
395
- input: E,
405
+ input: x,
396
406
  output: {
397
- entryFileNames: "client.js",
398
- assetFileNames: (n) => n.names?.[0]?.endsWith(".css") ? "client.css" : "[name][extname]"
407
+ entryFileNames: "client.[hash].js",
408
+ assetFileNames: (o) => o.names?.[0]?.endsWith(".css") ? "client.[hash].css" : "[name].[hash][extname]"
399
409
  }
400
410
  }
401
- }), t;
411
+ }), s;
402
412
  }
403
413
  };
404
414
  }
405
- function J() {
415
+ function B() {
406
416
  return {
407
417
  name: "velo:static-url",
408
418
  apply: "build",
409
419
  enforce: "post",
410
- generateBundle(u, o) {
420
+ generateBundle(u, c) {
411
421
  const r = process.env.STATIC_BASE_URL || "";
412
422
  if (r)
413
- for (const l of Object.values(o))
423
+ for (const l of Object.values(c))
414
424
  l.type === "asset" && typeof l.source == "string" && l.fileName.endsWith(".css") && (l.source = l.source.replace(
415
425
  /url\(\s*(['"]?)\/(?!\/)/g,
416
426
  `url($1${r}/`
@@ -419,13 +429,13 @@ function J() {
419
429
  };
420
430
  }
421
431
  function Z(u) {
422
- const o = u ?? {}, r = o.appDirectory ?? "./app";
432
+ const c = u ?? {}, r = c.appDirectory ?? "./app";
423
433
  return [
434
+ M(),
435
+ J(c, r),
424
436
  B(),
425
- M(o, r),
426
- J(),
427
- F(),
428
- w({
437
+ C(),
438
+ F({
429
439
  entry: g
430
440
  }),
431
441
  H()
@@ -440,9 +450,9 @@ function H() {
440
450
  };
441
451
  }
442
452
  export {
443
- T as buildFullPathMap,
444
- A as collectFullPaths,
445
- C as injectMetadata,
453
+ _ as buildFullPathMap,
454
+ N as collectFullPaths,
455
+ w as injectMetadata,
446
456
  U as removeLoaders,
447
457
  k as removeMiddlewares,
448
458
  V as transformActionsForClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mauroandre/velojs",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "type": "module",
5
5
  "description": "Fullstack web framework built on Hono + Preact with Vite-powered AST transforms",
6
6
  "keywords": [