vite-plugin-vanjs 0.0.10 → 0.1.1

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/router/types.d.ts CHANGED
@@ -12,22 +12,26 @@ import type {
12
12
  PropValueOrDerived,
13
13
  State,
14
14
  } from "vanjs-core";
15
+ import { LayoutFile } from "../plugin/types";
15
16
 
16
17
  // type VanElement = VElement | Exclude<Primitive, boolean | undefined>;
17
- type DOMElement = globalThis.Element;
18
+ // type DOMElement = globalThis.Element;
18
19
  type PrimitiveChild = Primitive | State<Primitive | undefined | null>;
19
20
 
20
- type VanElement =
21
+ type DOMElement<T extends keyof HTMLElementTagNameMap = "div"> =
21
22
  | SVGElement
22
23
  | HTMLElement
23
- | DOMElement
24
24
  | Node
25
+ | HTMLElementTagNameMap[T];
26
+
27
+ export type VanElement =
28
+ | DOMElement
25
29
  | VElement
26
30
  | PrimitiveChild;
27
31
  export type VanNode =
28
32
  | VanElement
29
- | VanNode[]
30
- | (() => VanNode)
33
+ | VanElement[]
34
+ | (() => VanElement | VanElement[])
31
35
  | null
32
36
  | undefined;
33
37
 
@@ -70,6 +74,9 @@ export type VanComponent<
70
74
  export const Router:
71
75
  & VanComponent<"main">
72
76
  & JSX.Component<"main">;
77
+ export const FileSystemRouter:
78
+ & VanComponent<"main">
79
+ & JSX.Component<"main">;
73
80
 
74
81
  // a.mjs
75
82
  /**
@@ -122,20 +129,51 @@ export const redirect: (href?: string) => void | (() => void);
122
129
  // routes.mjs
123
130
  export type RouteEntry = {
124
131
  path: string;
125
- component: Promise<ComponentModule>;
126
- preload?: (params?: Record<string, string>) => void;
127
- load?: (params?: Record<string, string>) => void;
132
+ component: () => Promise<ComponentModule>;
133
+ // component: () => Promise<DynamicModule>;
134
+ params?: Record<string, string>;
135
+ preload?: (
136
+ params?: Record<string, string>,
137
+ ) => boolean | void | Promise<boolean | void>;
138
+ load?: (
139
+ params?: Record<string, string>,
140
+ ) => boolean | void | Promise<boolean | void>;
128
141
  };
129
142
 
143
+ export type ImportFn = () => LazyComponent;
144
+
145
+ /**
146
+ * Registers a lazy component.
147
+ * @param importFn
148
+ */
149
+ export const lazy: (importFn: ImportFn) => () => Promise<ComponentModule>;
150
+
130
151
  export type RouteProps = {
131
152
  path: string;
153
+ params?: Record<string, string>;
132
154
  component:
133
- | (() => HTMLElementTagNameMap[unknown] | HTMLElementTagNameMap[unknown][])
155
+ // | (() => HTMLElementTagNameMap[unknown] | HTMLElementTagNameMap[unknown][])
156
+ // | VanNode
157
+ | (() => DOMElement)
134
158
  | VanComponent
135
- | (() => ComponentModule);
136
- preload?: (params?: Record<string, string>) => void;
137
- load?: (params?: Record<string, string>) => void;
159
+ | ComponentFn
160
+ | (() => Promise<DynamicModule>);
161
+ // | ComponentModule["component"];
162
+ // component: ComponentFn | (() => Promise<ComponentModule>);
163
+ preload?: (
164
+ params?: Record<string, string>,
165
+ ) => boolean | void | Promise<boolean | void>;
166
+ load?: (
167
+ params?: Record<string, string>,
168
+ ) => boolean | void | Promise<boolean | void>;
138
169
  };
170
+
171
+ export type RouteConfig = {
172
+ routePath: string;
173
+ path: string;
174
+ layouts?: LayoutFile[];
175
+ };
176
+
139
177
  export const routes: RouteEntry[];
140
178
 
141
179
  /**
@@ -181,43 +219,79 @@ export const setRouterState: (
181
219
  params?: Record<string, string>,
182
220
  ) => void;
183
221
 
222
+ export type UnwrapResult = {
223
+ children: VanNode[];
224
+ };
225
+
184
226
  /**
185
227
  * Merge the children of an Element or an array of elements with an optional array of children
186
- * into the childen of a single HTMLFragmentElement element.
187
- * @param source
188
- * @param {...VanNode[]} children
228
+ * into the childen prperty of a simple object.
229
+ * @param source
230
+ * @param children
189
231
  */
232
+
190
233
  export const unwrap: (
191
234
  source:
192
235
  | VanNode
193
- | IsoTagFunc
194
236
  | VanNode[]
195
- | IsoTagFunc[]
196
- | (() => IsoTagFunc | IsoTagFunc[] | VanNode | VanNode[]),
237
+ | VanComponent
238
+ | { children: VanNode[] }
239
+ | ComponentFn
240
+ | ReturnType<IsoTagFunc>
241
+ | ReturnType<IsoTagFunc>[]
242
+ | (() =>
243
+ | ReturnType<IsoTagFunc>
244
+ | ReturnType<IsoTagFunc>[]
245
+ | VanNode
246
+ | VanNode[]),
197
247
  ...children: VanNode[]
198
- ) => VanNode;
248
+ ) => UnwrapResult;
249
+
250
+ export type JSXComponentFn = () => JSX.Element;
251
+ export type FragmentFn = () => ChildDom | ChildDom[];
252
+ export type ComponentFn = FragmentFn | VanComponent | JSXComponentFn;
199
253
 
200
254
  export type ComponentModule = {
201
- component: VanComponent | JSX.Element;
202
- route: Pick<RouteEntry, "load" | "preload">;
255
+ component: ComponentFn;
256
+ route?: Pick<RouteEntry, "load" | "preload">;
203
257
  };
204
258
 
205
259
  export type DynamicModule = {
206
- Page: VanComponent | JSX.Element;
207
- default?: VanComponent | JSX.Element;
260
+ Page: ComponentFn;
261
+ default?: ComponentFn;
208
262
  route?: Pick<RouteEntry, "load" | "preload">;
209
263
  };
210
264
 
211
265
  export type LazyComponent = Promise<DynamicModule>;
212
266
 
213
- /**
214
- * Registers a lazy component.
215
- * @param importFn
216
- */
217
- export const lazy: (importFn: () => LazyComponent) => () => ComponentModule;
218
-
219
267
  /**
220
268
  * Fixes the URL of a route.
221
269
  * @param url
222
270
  */
223
271
  export const fixRouteUrl: (url: string) => string;
272
+
273
+ /**
274
+ * Cache a route.
275
+ * @param key the cache route key
276
+ * @param value the cache route
277
+ */
278
+ export const cache: (key: ImportFn, value: ComponentModule) => void;
279
+
280
+ /**
281
+ * Return a route cache.
282
+ * @param key the cache route key
283
+ */
284
+ export const getCached: (key: typeof importFn) => ComponentModule | undefined;
285
+
286
+ /**
287
+ * Execute lifecycle methods preload and / or load
288
+ */
289
+ export const executeLifecycle: (
290
+ { route }: ComponentModule,
291
+ params: Record<string, string> | undefined,
292
+ ) => Promise<boolean>;
293
+
294
+ /**
295
+ * Find a registered route that matches the given path
296
+ */
297
+ export const matchRoute: (path: string) => RouteEntry | null;
package/server/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { basename } from "node:path";
2
+ export * from "../plugin/helpers.mjs";
2
3
 
3
4
  /**
4
5
  * @type {typeof import("./types.d.ts").renderToString}
@@ -66,32 +67,54 @@ function renderPreloadLink(file) {
66
67
  }
67
68
  }
68
69
 
70
+ /**
71
+ * @type {typeof import("./types.d.ts").renderPreloadLinks}
72
+ */
69
73
  /**
70
74
  * @type {typeof import("./types.d.ts").renderPreloadLinks}
71
75
  */
72
76
  export function renderPreloadLinks(modules, manifest) {
73
77
  let links = "";
74
78
  const seen = new Set();
79
+ const ignoredAssets = new Set();
80
+
81
+ // First pass: collect all assets from ignored paths
82
+ Object.entries(manifest).forEach(([id, files]) => {
83
+ // istanbul ignore else
84
+ if (["src/pages", "src/routes"].some((l) => id.includes(l))) {
85
+ files.forEach((asset) => ignoredAssets.add(asset));
86
+ }
87
+ });
88
+
89
+ // Second pass: generate preload links
75
90
  modules.forEach((id) => {
76
91
  const files = manifest[id];
77
- /* istanbul ignore else */
92
+
93
+ // istanbul ignore else
78
94
  if (files?.length) {
79
95
  files.forEach((file) => {
80
- /* istanbul ignore else */
81
- if (!seen.has(file)) {
82
- seen.add(file);
83
- const filename = basename(file);
84
- /* istanbul ignore next - impossible to test */
85
- if (manifest[filename]) {
86
- for (const depFile of manifest[filename]) {
96
+ // Skip if we've seen this file or if it's an asset from an ignored path
97
+ if (seen.has(file) || ignoredAssets.has(file)) return;
98
+
99
+ seen.add(file);
100
+ const filename = basename(file);
101
+
102
+ // Handle dependencies
103
+ // istanbul ignore next - no way to test this
104
+ if (manifest[filename]) {
105
+ for (const depFile of manifest[filename]) {
106
+ // istanbul ignore else
107
+ if (!seen.has(depFile) && !ignoredAssets.has(depFile)) {
87
108
  links += renderPreloadLink(depFile);
88
109
  seen.add(depFile);
89
110
  }
90
111
  }
91
- links += renderPreloadLink(file);
92
112
  }
113
+
114
+ links += renderPreloadLink(file);
93
115
  });
94
116
  }
95
117
  });
118
+
96
119
  return links;
97
120
  }
package/server/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /// <reference path="global.d.ts" />
2
2
  import type { Element as VanElement, TagFunc } from "mini-van-plate/van-plate";
3
+ import { ResolvedConfig } from "vite";
3
4
 
4
5
  /**
5
6
  * A function that takes a list of files and a manifest and returns a string
@@ -36,3 +37,58 @@ export type Source =
36
37
  * @returns HTML string
37
38
  */
38
39
  export const renderToString: (source: Source) => Promise<string>;
40
+
41
+ // FILE SYSTEM ROUTER
42
+ /**
43
+ * Get the file most probable route path for a given potential route.
44
+ */
45
+ export const fileToRoute: (file: string, routesDir: string) => string;
46
+
47
+ export type PageFile = { path: string; routePath: string };
48
+ export type LayoutFile = { id: string; path: string };
49
+ export type RouteFile = PageFile & { layouts: Array<LayoutFile> };
50
+ export type PluginConfig = { routesDir: string; extensions: string[] };
51
+ /**
52
+ * Find all layout files for a given route.
53
+ */
54
+
55
+ export const findLayouts: (
56
+ routePath: string,
57
+ config: ResolvedConfig,
58
+ pluginConfig: PluginConfig,
59
+ ) => Array<LayoutFile>;
60
+
61
+ /**
62
+ * Identify all files in a folder.
63
+ */
64
+ export const globFiles: (
65
+ dir: string,
66
+ extensions: string[],
67
+ ) => Promise<Array<string>>;
68
+
69
+ /**
70
+ * Scan routes directory and generate routes.
71
+ */
72
+ export const scanRoutes: (
73
+ config: ResolvedConfig,
74
+ pluginConfig: PluginConfig,
75
+ ) => Promise<
76
+ Array<{ path: string; routePath: string }>
77
+ >;
78
+
79
+ /**
80
+ * Process routes and identify their layouts
81
+ */
82
+ export const processLayoutRoutes: (
83
+ routes: Array<PageFile>,
84
+ config: ResolvedConfig,
85
+ pluginConfig: PluginConfig,
86
+ ) => Array<PRouteFile>;
87
+
88
+ /**
89
+ * Scan and process layouts and return them.
90
+ */
91
+ export const getRoutes: (
92
+ config: ResolvedConfig,
93
+ pluginConfig: PluginConfig,
94
+ ) => Promise<Array<RouteFile>>;
package/setup/global.d.ts CHANGED
@@ -5,49 +5,51 @@ declare module "@vanjs/van" {
5
5
  }
6
6
 
7
7
  declare module "@vanjs/vanX" {
8
- import {
9
- calc,
10
- compact,
11
- list,
12
- noreactive,
13
- raw,
14
- reactive,
15
- replace,
16
- stateFields,
8
+ import type {
9
+ CalcFunction,
10
+ CompactFunction,
11
+ ListFunction,
12
+ NoreactiveFunction,
13
+ RawFunction,
14
+ ReactiveFunction,
15
+ ReplaceFunction,
16
+ StateFieldsFunction,
17
17
  } from "vanjs-ext";
18
- const vanX: {
19
- calc: typeof calc;
20
- reactive: typeof reactive;
21
- noreactive: typeof noreactive;
22
- stateFields: typeof stateFields;
23
- raw: typeof raw;
24
- list: typeof list;
25
- replace: typeof replace;
26
- compact: typeof compact;
27
- };
18
+ import type { VanXObj } from "mini-van-plate/shared";
19
+
20
+ export const calc: CalcFunction;
21
+ export const compact: CompactFunction;
22
+ export const list: ListFunction;
23
+ export const noreactive: NoreactiveFunction;
24
+ export const raw: RawFunction;
25
+ export const reactive: ReactiveFunction;
26
+ export const replace: ReplaceFunction;
27
+ export const stateFields: StateFieldsFunction;
28
+
29
+ // Define the vanX object type
30
+ interface VanXObject {
31
+ calc: CalcFunction;
32
+ reactive: ReactiveFunction;
33
+ noreactive: NoreactiveFunction;
34
+ stateFields: StateFieldsFunction;
35
+ raw: RawFunction;
36
+ list: ListFunction;
37
+ replace: ReplaceFunction;
38
+ compact: CompactFunction;
39
+ readonly default: VanXObject;
40
+ }
41
+ interface VanXPlate extends VanXObj {
42
+ readonly default: VanXObj;
43
+ }
44
+
45
+ const vanX: VanXObject | VanXPlate;
28
46
  export default vanX;
29
- export {
30
- calc,
31
- compact,
32
- list,
33
- noreactive,
34
- raw,
35
- reactive,
36
- replace,
37
- stateFields,
38
- };
39
47
  }
40
48
 
41
49
  declare module "@vanjs/setup" {
42
- import type { Van } from "vanjs-core";
43
- import type * as vanX from "vanjs-ext";
44
- import type { dummyVanX } from "mini-van-plate/shared";
50
+ import van from "@vanjs/van";
51
+ import vanX from "@vanjs/vanX";
45
52
 
46
- interface Setup {
47
- isServer: boolean;
48
- van: Van;
49
- vanX: typeof vanX | typeof dummyVanX;
50
- }
51
- const setup: Setup;
52
- export default setup;
53
+ const isServer: boolean;
54
+ export { isServer, van, vanX };
53
55
  }
@@ -0,0 +1,7 @@
1
+ /** @type {(props: Record<string, unknown>) => boolean} */
2
+ export function needsHydration(props) {
3
+ return props && (
4
+ Object.keys(props).some((k) => k.startsWith("on")) || // has events
5
+ Object.values(props).some((v) => v && typeof v === "object" && "val" in v) // has state
6
+ );
7
+ }
@@ -1,21 +1,9 @@
1
- import { dummyVanX, registerEnv } from "mini-van-plate/shared";
2
- import vanPlate from "mini-van-plate/van-plate";
3
- import vanCore from "vanjs-core/debug";
4
- import * as vanX from "vanjs-ext";
5
-
6
- const vanXObject = { ...vanX, default: vanX };
7
- const dummyObject = { ...dummyVanX, default: dummyVanX };
8
-
9
- const setup = {
10
- isServer: typeof window === "undefined",
11
- get van() {
12
- return this.isServer ? vanPlate : vanCore;
13
- },
14
- get vanX() {
15
- return this.isServer ? dummyObject : vanXObject;
16
- },
1
+ import van from "./van-debug.mjs";
2
+ import vanX from "./vanX.mjs";
3
+ import isServer from "./isServer.mjs";
4
+
5
+ export default {
6
+ isServer,
7
+ van,
8
+ vanX,
17
9
  };
18
-
19
- registerEnv(setup);
20
-
21
- export default setup;
@@ -0,0 +1,5 @@
1
+ import van from "./van-ssr.mjs";
2
+ import vanX from "./vanX-ssr.mjs";
3
+ import isServer from "./isServer.mjs";
4
+
5
+ export { isServer, van, vanX };
package/setup/index.mjs CHANGED
@@ -1,21 +1,5 @@
1
- import { dummyVanX, registerEnv } from "mini-van-plate/shared";
2
- import vanPlate from "mini-van-plate/van-plate";
3
- import vanCore from "vanjs-core";
4
- import * as vanX from "vanjs-ext";
1
+ import van from "./van.mjs";
2
+ import vanX from "./vanX.mjs";
3
+ import isServer from "./isServer.mjs";
5
4
 
6
- const vanXObject = { ...vanX, default: vanX };
7
- const dummyObject = { ...dummyVanX, default: dummyVanX };
8
-
9
- const setup = {
10
- isServer: typeof window === "undefined",
11
- get van() {
12
- return this.isServer ? vanPlate : vanCore;
13
- },
14
- get vanX() {
15
- return this.isServer ? dummyObject : vanXObject;
16
- },
17
- };
18
-
19
- registerEnv(setup);
20
-
21
- export default setup;
5
+ export { isServer, van, vanX };
@@ -0,0 +1,2 @@
1
+ const isServer = typeof window === "undefined";
2
+ export default isServer;
@@ -9,13 +9,29 @@
9
9
  "types": "./types.d.ts",
10
10
  "import": "./index.mjs"
11
11
  },
12
+ "./debug": {
13
+ "types": "./types.d.ts",
14
+ "import": "./index-debug.mjs"
15
+ },
12
16
  "./van": {
13
17
  "types": "./van.d.ts",
14
18
  "import": "./van.mjs"
15
19
  },
20
+ "./van-ssr": {
21
+ "types": "./van-ssr.d.ts",
22
+ "import": "./van-ssr.mjs"
23
+ },
24
+ "./van-debug": {
25
+ "types": "./van.d.ts",
26
+ "import": "./van-debug.mjs"
27
+ },
16
28
  "./vanX": {
17
29
  "types": "./vanX.d.ts",
18
30
  "import": "./vanX.mjs"
31
+ },
32
+ "./vanX-ssr": {
33
+ "types": "./vanX.d.ts",
34
+ "import": "./vanX-ssr.mjs"
19
35
  }
20
36
  },
21
37
  "peerDependencies": {
@@ -1,2 +1,2 @@
1
- import setup from "./index-debug.mjs";
2
- export default setup.van;
1
+ import van from "vanjs-core/debug";
2
+ export default van;
@@ -0,0 +1 @@
1
+ export * from "mini-van-plate/van-plate";
@@ -0,0 +1,51 @@
1
+ // setup/van-ssr.mjs
2
+ import { registerEnv } from "mini-van-plate/shared";
3
+ import van from "mini-van-plate/van-plate";
4
+ import { needsHydration } from "./helpers.mjs";
5
+
6
+ function tagWithHydration(ns, name, ...args) {
7
+ const originalTag = ns ? van.tags(ns)[name] : van.tags[name];
8
+
9
+ const [props, ...children] =
10
+ Object.getPrototypeOf(args[0] ?? /* istanbul ignore next */ 0) ===
11
+ Object.prototype
12
+ ? args
13
+ : [{}, ...args];
14
+
15
+ // Create new props object without event handlers
16
+ const finalProps = { ...props };
17
+
18
+ if (needsHydration(props)) {
19
+ // Add data-hk for hydration
20
+ finalProps["data-hk"] = "";
21
+
22
+ // Remove all inline event handlers for server rendering
23
+ for (const key in finalProps) {
24
+ if (key.startsWith("on")) {
25
+ delete finalProps[key];
26
+ }
27
+ }
28
+ }
29
+
30
+ // Use filtered props for server rendering
31
+ return originalTag(finalProps, ...children);
32
+ }
33
+
34
+ const tagsProxy = new Proxy(
35
+ (ns) =>
36
+ new Proxy(tagWithHydration.bind(undefined, ns), {
37
+ get: (_, name) => tagWithHydration.bind(undefined, ns, name),
38
+ }),
39
+ {
40
+ get: (_, name) => tagWithHydration.bind(undefined, undefined, name),
41
+ },
42
+ );
43
+
44
+ const vanSSR = {
45
+ ...van,
46
+ tags: tagsProxy,
47
+ };
48
+
49
+ registerEnv({ van: vanSSR });
50
+
51
+ export default vanSSR;
package/setup/van.mjs CHANGED
@@ -1,2 +1,44 @@
1
- import setup from "./index.mjs";
2
- export default setup.van;
1
+ // setup/van.mjs
2
+ import van from "vanjs-core";
3
+ import { needsHydration } from "./helpers.mjs";
4
+
5
+ // Create our own tag function that wraps the original
6
+ function tagWithHydration(ns, name, ...args) {
7
+ // Get the correct tag function based on namespace
8
+ const originalTag = ns ? van.tags(ns)[name] : van.tags[name];
9
+
10
+ const [props, ...children] =
11
+ Object.getPrototypeOf(args[0] ?? 0) === Object.prototype
12
+ ? args
13
+ : [{}, ...args];
14
+
15
+ // Create new props object without event handlers
16
+ const finalProps = { ...props };
17
+
18
+ // Add data-hk if element needs hydration
19
+ if (needsHydration(props)) {
20
+ finalProps["data-hk"] = "";
21
+ }
22
+
23
+ // Call the original tag function
24
+ return originalTag(finalProps, ...children);
25
+ }
26
+
27
+ // Create our tags proxy using the same pattern as vanjs-core
28
+ const tagsProxy = new Proxy(
29
+ (ns) =>
30
+ new Proxy(tagWithHydration.bind(undefined, ns), {
31
+ get: (_, name) => tagWithHydration.bind(undefined, ns, name),
32
+ }),
33
+ {
34
+ get: (_, name) => tagWithHydration.bind(undefined, undefined, name),
35
+ },
36
+ );
37
+
38
+ // Export modified van instance with only tags overridden
39
+ const vanClient = {
40
+ ...van,
41
+ tags: tagsProxy,
42
+ };
43
+
44
+ export default vanClient;
@@ -0,0 +1 @@
1
+ export * from "mini-van-plate/van-plate";
@@ -0,0 +1,12 @@
1
+ import { dummyVanX, registerEnv } from "mini-van-plate/shared";
2
+
3
+ const vanX = {
4
+ ...dummyVanX,
5
+ get default() {
6
+ return dummyVanX;
7
+ },
8
+ };
9
+
10
+ registerEnv({ vanX });
11
+
12
+ export default vanX;