vite-plugin-vanjs 0.1.6 → 0.1.7

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/client/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { unwrap } from "../router/index.mjs";
1
+ import { unwrap } from "../router/unwrap.mjs";
2
2
  import { getTagKey } from "../meta/helpers.mjs";
3
3
 
4
4
  /**
@@ -118,6 +118,7 @@ function createHydrationContext() {
118
118
 
119
119
  /** @type {(oldDom: HTMLElement, newDom: HTMLElement | HTMLElement[]) => HTMLElement} */
120
120
  function diffAndHydrate(oldDom, newDom) {
121
+ if (!oldDom || !newDom) return;
121
122
  // SPA mode
122
123
  // istanbul ignore else
123
124
  if (!oldDom.children.length && !elementsMatch(oldDom, newDom)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-vanjs",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "author": "thednp",
5
5
  "license": "MIT",
6
6
  "description": "A mini meta-framework for VanJS powered by Vite",
package/plugin/index.mjs CHANGED
@@ -203,7 +203,8 @@ export default function VitePluginVanJS(options = {}) {
203
203
  }
204
204
 
205
205
  const routesScript = `
206
- import { Route, routes } from "@vanjs/router/routes.mjs";
206
+ import { Route } from "@vanjs/router/route.mjs";
207
+ import { routes } from "@vanjs/router/routes.mjs";
207
208
  import { lazy } from "@vanjs/router/lazy.mjs";
208
209
 
209
210
  // Reset current routes
package/router/a.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // router/a.mjs
2
2
  import van from "vanjs-core";
3
- import { matchRoute } from "./routes.mjs";
3
+ import { matchRoute } from "./matchRoute.mjs";
4
4
  import { executeLifecycle, isCurrentPage, navigate } from "./helpers.mjs";
5
5
 
6
6
  /** @typedef {typeof import("./types").A} A */
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Extract route params
3
+ * @param {string} pattern
4
+ * @param {string} path
5
+ * @returns {Record<string, string> | null}
6
+ */
7
+ export const extractParams = (pattern, path) => {
8
+ /** @type {Record<string, string>} */
9
+ const params = {};
10
+ const patternParts = pattern.split("/");
11
+ const pathParts = path.split("/");
12
+
13
+ if (patternParts.length !== pathParts.length) return null;
14
+
15
+ for (let i = 0; i < patternParts.length; i++) {
16
+ const patternPart = patternParts[i];
17
+ const pathPart = pathParts[i];
18
+
19
+ if (patternPart.startsWith(":")) {
20
+ params[patternPart.slice(1)] = pathPart;
21
+ } else if (patternPart !== pathPart) {
22
+ return null;
23
+ }
24
+ }
25
+
26
+ return params;
27
+ };
@@ -1,9 +1,7 @@
1
- // import van from "vanjs-core";
2
1
  import isServer from "../setup/isServer.mjs";
3
2
  import { routerState, setRouterState } from "./state.mjs";
4
- import { matchRoute } from "./routes.mjs";
3
+ import { matchRoute } from "./matchRoute.mjs";
5
4
 
6
- /** @typedef {typeof import("./types.d.ts").unwrap} Unwrap */
7
5
  /** @typedef {typeof import("./types.d.ts").navigate} Navigate */
8
6
  /** @typedef {import("./types.d.ts").Route} Route */
9
7
  /** @typedef {import("./types.d.ts").VanNode} VanNode */
@@ -21,41 +19,6 @@ export const isCurrentPage = (pageName) => {
21
19
  return routerState.pathname.val === pageName;
22
20
  };
23
21
 
24
- /**
25
- * Merge the children of an Element or an array of elements with an optional array of children
26
- * into the childen prperty of a simple object.
27
- * @type {Unwrap}
28
- */
29
- export const unwrap = (source, ...children) => {
30
- const layout = () => {
31
- /** @type {VanNode[]} */
32
- const pageChildren =
33
- source && typeof source === "object" && "children" in source &&
34
- Array.isArray(source?.children)
35
- ? source.children
36
- : typeof source === "function"
37
- // @ts-expect-error - this case is specific to VanJS components in SSR
38
- ? [...source()?.children || source()]
39
- : typeof HTMLElement !== "undefined" && source instanceof HTMLElement
40
- ? [...source.children]
41
- : /* istanbul ignore next */ Array.isArray(source)
42
- ? source
43
- : [source];
44
-
45
- // return van.tags.fragment(
46
- // ...(children || /* istanbul ignore next */ []),
47
- // ...pageChildren,
48
- // );
49
- return {
50
- children: [
51
- ...(children || /* istanbul ignore next */ []),
52
- ...pageChildren,
53
- ],
54
- };
55
- };
56
- return layout();
57
- };
58
-
59
22
  /**
60
23
  * Check if component is a lazy component
61
24
  * @param {ComponentFn | (() => LazyComponent)} component
@@ -121,47 +84,6 @@ export const navigate = (path, options = {}) => {
121
84
  }
122
85
  };
123
86
 
124
- /**
125
- * Extract route params
126
- * @param {string} pattern
127
- * @param {string} path
128
- * @returns {Record<string, string> | null}
129
- */
130
- export const extractParams = (pattern, path) => {
131
- /** @type {Record<string, string>} */
132
- const params = {};
133
- const patternParts = pattern.split("/");
134
- const pathParts = path.split("/");
135
-
136
- if (patternParts.length !== pathParts.length) return null;
137
-
138
- for (let i = 0; i < patternParts.length; i++) {
139
- const patternPart = patternParts[i];
140
- const pathPart = pathParts[i];
141
-
142
- if (patternPart.startsWith(":")) {
143
- params[patternPart.slice(1)] = pathPart;
144
- } else if (patternPart !== pathPart) {
145
- return null;
146
- }
147
- }
148
-
149
- return params;
150
- };
151
-
152
- /**
153
- * Fix the URL of a route
154
- * @param {string=} url
155
- * @returns
156
- */
157
- export const fixRouteUrl = (url) => {
158
- if (!url) return "/";
159
- if (url.startsWith("/")) {
160
- return url;
161
- }
162
- return `/${url}`;
163
- };
164
-
165
87
  /**
166
88
  * Client only reload utility
167
89
  * WORK IN PROGRESS
package/router/index.mjs CHANGED
@@ -1,7 +1,10 @@
1
1
  export * from "./router.mjs";
2
2
  export * from "./routes.mjs";
3
+ export * from "./route.mjs";
3
4
  export * from "./a.mjs";
4
5
  export * from "./state.mjs";
5
6
  export * from "./lazy.mjs";
6
7
  export * from "./helpers.mjs";
7
8
  export * from "./cache.mjs";
9
+ export * from "./unwrap.mjs";
10
+ export * from "./extractParams.mjs";
package/router/lazy.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import isServer from "../setup/isServer.mjs";
1
+ // router/lazy.mjs
2
2
  import van from "vanjs-core";
3
+ import isServer from "../setup/isServer.mjs";
3
4
  import { cache, getCached } from "./cache.mjs";
4
5
 
5
6
  /** @typedef {import('./types').VanNode} VanNode */
@@ -0,0 +1,49 @@
1
+ // router/matchRoute.mjs
2
+ import { extractParams } from "./extractParams.mjs";
3
+ import { routes } from "./routes.mjs";
4
+
5
+ /** @typedef {import("./types.d.ts").RouteEntry} RouteEntry */
6
+
7
+ /**
8
+ * Find a registered route that matches the given path
9
+ * @param {string} initialPath
10
+ * @returns {RouteEntry | null}
11
+ */
12
+ export const matchRoute = (initialPath) => {
13
+ const path = initialPath !== "/" && initialPath.endsWith("/")
14
+ ? initialPath.slice(0, -1)
15
+ : initialPath;
16
+
17
+ // First try exact match (excluding wildcards)
18
+ let foundMatch = routes.find((r) => r.path === path && !r.path.includes("*"));
19
+
20
+ // Then try nested wildcard match if no exact match found
21
+ if (!foundMatch) {
22
+ // Build the path for potential nested wildcard, e.g. /admin/* for /admin/articles
23
+ const nestedPath = path.split("/").slice(0, -1).join("/") + "/*";
24
+ foundMatch = routes.find((r) => r.path === nestedPath);
25
+ }
26
+
27
+ // If we found either an exact or nested wildcard match, return it with params
28
+ if (foundMatch) {
29
+ return {
30
+ ...foundMatch,
31
+ params: extractParams(foundMatch.path, path) ?? /* istanbul ignore next */
32
+ undefined,
33
+ };
34
+ }
35
+
36
+ // Try parameterized routes (like /users/:id)
37
+ for (const route of routes) {
38
+ // Skip the global catch-all
39
+ if (route.path === "*") continue;
40
+ const params = extractParams(route.path, path);
41
+
42
+ if (params) {
43
+ return { ...route, params };
44
+ }
45
+ }
46
+
47
+ // Finally, fallback to global catch-all route
48
+ return routes.find((r) => r.path === "*") || null;
49
+ };
@@ -0,0 +1,36 @@
1
+ // router/routes.mjs
2
+ import { isLazyComponent } from "./helpers.mjs";
3
+ import { routes } from "./routes.mjs";
4
+ import { lazy } from "./lazy.mjs";
5
+ /** @typedef {import("./types.d.ts").RouteProps} RouteProps */
6
+ /** @typedef {import("./types.d.ts").ComponentModule} ComponentModule */
7
+
8
+ /**
9
+ * @param {RouteProps} routeProps
10
+ */
11
+ export const Route = (routeProps) => {
12
+ const { path, component, preload, load, ...rest } = routeProps;
13
+
14
+ // istanbul ignore next - no point testing this error
15
+ if (routes.some((r) => r.path === path)) {
16
+ console.error(`🍦 @vanjs/router: duplicated route for "${path}".`);
17
+ return;
18
+ }
19
+
20
+ // If component isn't lazy, make it lazy
21
+ if (!isLazyComponent(component)) {
22
+ /** @type {() => Promise<ComponentModule>} */
23
+ const wrappedComponent = lazy(() =>
24
+ Promise.resolve({
25
+ Page: component,
26
+ route: { preload, load },
27
+ })
28
+ );
29
+ routes.push({ ...rest, path, component: wrappedComponent });
30
+ return;
31
+ }
32
+
33
+ // Otherwise keep original component
34
+ // @ts-expect-error - RouteProps and RouteEntry are now equivalent
35
+ routes.push(routeProps);
36
+ };
package/router/router.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  import van from "vanjs-core";
2
2
  import isServer from "../setup/isServer.mjs";
3
3
  import { routerState, setRouterState } from "./state.mjs";
4
- import { matchRoute } from "./routes.mjs";
5
- import { executeLifecycle, unwrap } from "./helpers.mjs";
4
+ import { matchRoute } from "./matchRoute.mjs";
5
+ import { executeLifecycle } from "./helpers.mjs";
6
+ import { unwrap } from "./unwrap.mjs";
6
7
  import { hydrate } from "../client/index.mjs";
7
8
  import { Head, initializeHeadTags } from "../meta/index.mjs";
8
9
 
package/router/routes.mjs CHANGED
@@ -1,85 +1,4 @@
1
1
  // router/routes.mjs
2
- import { extractParams, isLazyComponent } from "./helpers.mjs";
3
- import { lazy } from "./lazy.mjs";
4
-
5
2
  /** @typedef {import("./types.d.ts").RouteEntry} RouteEntry */
6
- /** @typedef {import("./types.d.ts").RouteProps} RouteProps */
7
- /** @typedef {import("./types.d.ts").DynamicModule} DynamicModule */
8
- /** @typedef {import("./types.d.ts").ComponentModule} ComponentModule */
9
-
10
3
  /** @type {RouteEntry[]} */
11
4
  export const routes = [];
12
-
13
- /**
14
- * @param {RouteProps} routeProps
15
- */
16
- export const Route = (routeProps) => {
17
- const { path, component, preload, load, ...rest } = routeProps;
18
-
19
- // istanbul ignore next - no point testing this error
20
- if (routes.some((r) => r.path === path)) {
21
- console.error(`🍦 @vanjs/router: duplicated route for "${path}".`);
22
- return;
23
- }
24
-
25
- // If component isn't lazy, make it lazy
26
- if (!isLazyComponent(component)) {
27
- /** @type {() => Promise<ComponentModule>} */
28
- const wrappedComponent = lazy(() =>
29
- Promise.resolve({
30
- Page: component,
31
- route: { preload, load },
32
- })
33
- );
34
- routes.push({ ...rest, path, component: wrappedComponent });
35
- return;
36
- }
37
-
38
- // Otherwise keep original component
39
- // @ts-expect-error - RouteProps and RouteEntry are now equivalent
40
- routes.push(routeProps);
41
- };
42
-
43
- /**
44
- * Find a registered route that matches the given path
45
- * @param {string} initialPath
46
- * @returns {RouteEntry | null}
47
- */
48
- export const matchRoute = (initialPath) => {
49
- const path = initialPath !== "/" && initialPath.endsWith("/")
50
- ? initialPath.slice(0, -1)
51
- : initialPath;
52
-
53
- // First try exact match (excluding wildcards)
54
- let foundMatch = routes.find((r) => r.path === path && !r.path.includes("*"));
55
-
56
- // Then try nested wildcard match if no exact match found
57
- if (!foundMatch) {
58
- // Build the path for potential nested wildcard, e.g. /admin/* for /admin/articles
59
- const nestedPath = path.split("/").slice(0, -1).join("/") + "/*";
60
- foundMatch = routes.find((r) => r.path === nestedPath);
61
- }
62
-
63
- // If we found either an exact or nested wildcard match, return it with params
64
- if (foundMatch) {
65
- return {
66
- ...foundMatch,
67
- params: extractParams(foundMatch.path, path) ?? /* istanbul ignore next */
68
- undefined,
69
- };
70
- }
71
-
72
- // Try parameterized routes (like /users/:id)
73
- for (const route of routes) {
74
- // Skip the global catch-all
75
- if (route.path === "*") continue;
76
- const params = extractParams(route.path, path);
77
-
78
- if (params) {
79
- return { ...route, params };
80
- }
81
- }
82
-
83
- // Finally, fallback to global catch-all route
84
- return routes.find((r) => r.path === "*") || null;
85
- };
package/router/state.mjs CHANGED
@@ -1,7 +1,19 @@
1
1
  // router/state.js
2
2
  import van from "vanjs-core";
3
3
  import isServer from "../setup/isServer.mjs";
4
- import { fixRouteUrl } from "./helpers.mjs";
4
+
5
+ /**
6
+ * Fix the URL of a route
7
+ * @param {string=} url
8
+ * @returns
9
+ */
10
+ export const fixRouteUrl = (url) => {
11
+ if (!url) return "/";
12
+ if (url.startsWith("/")) {
13
+ return url;
14
+ }
15
+ return `/${url}`;
16
+ };
5
17
 
6
18
  const initialPath = !isServer ? globalThis.location.pathname : "/";
7
19
  const initialSearch = !isServer ? globalThis.location.search : "";
@@ -0,0 +1,33 @@
1
+ /** @typedef {typeof import("./types.d.ts").unwrap} Unwrap */
2
+ /** @typedef {import("./types.d.ts").VanNode} VanNode */
3
+
4
+ /**
5
+ * Merge the children of an Element or an array of elements with an optional array of children
6
+ * into the childen prperty of a simple object.
7
+ * @type {Unwrap}
8
+ */
9
+ export const unwrap = (source, ...children) => {
10
+ const layout = () => {
11
+ /** @type {VanNode[]} */
12
+ const pageChildren =
13
+ source && typeof source === "object" && "children" in source &&
14
+ Array.isArray(source?.children)
15
+ ? source.children
16
+ : typeof source === "function"
17
+ // @ts-expect-error - this case is specific to VanJS components in SSR
18
+ ? [...source()?.children || source()]
19
+ : typeof HTMLElement !== "undefined" && source instanceof HTMLElement
20
+ ? [...source.children]
21
+ : /* istanbul ignore next */ Array.isArray(source)
22
+ ? source
23
+ : [source];
24
+
25
+ return {
26
+ children: [
27
+ ...(children || /* istanbul ignore next */ []),
28
+ ...pageChildren,
29
+ ],
30
+ };
31
+ };
32
+ return layout();
33
+ };
package/server/index.mjs CHANGED
@@ -67,9 +67,6 @@ function renderPreloadLink(file) {
67
67
  }
68
68
  }
69
69
 
70
- /**
71
- * @type {typeof import("./types.d.ts").renderPreloadLinks}
72
- */
73
70
  /**
74
71
  * @type {typeof import("./types.d.ts").renderPreloadLinks}
75
72
  */
@@ -82,7 +79,7 @@ export function renderPreloadLinks(modules, manifest) {
82
79
  Object.entries(manifest).forEach(([id, files]) => {
83
80
  // istanbul ignore else - don't pre-render routes, layouts and JSX stuff
84
81
  if (
85
- ["src/pages", "src/routes", "vite-plugin-vanjs/jsx"].some((l) =>
82
+ ["src/pages", "src/routes", "vite-plugin-vanjs/"].some((l) =>
86
83
  id.includes(l)
87
84
  )
88
85
  ) {
package/server/types.d.ts CHANGED
@@ -21,11 +21,11 @@ type ValidVanNode =
21
21
  | VanElement
22
22
  | TagFunc;
23
23
 
24
- type VanComponent = () => HTMLElement | ValidVanNode | ValidVanNode[];
24
+ type VComponent = () => HTMLElement | ValidVanNode | ValidVanNode[];
25
25
  export type Source =
26
26
  | Promise<ValidVanNode>
27
- | VanComponent
28
- | (() => VanComponent)
27
+ | VComponent
28
+ | (() => VComponent)
29
29
  | ValidVanNode
30
30
  | ValidVanNode[]
31
31
  | undefined;