vite-plugin-vanjs 0.1.16 → 0.1.17
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 +21 -15
- package/package.json +3 -2
- package/plugin/helpers.mjs +13 -11
- package/plugin/index.mjs +4 -2
- package/plugin/types.d.ts +1 -1
- package/router/a.mjs +28 -16
- package/router/dataCache.mjs +168 -0
- package/router/global.d.ts +108 -53
- package/router/helpers.mjs +61 -14
- package/router/index.mjs +2 -1
- package/router/lazy.mjs +15 -53
- package/router/route.mjs +6 -6
- package/router/{cache.mjs → routeCache.mjs} +2 -2
- package/router/router.mjs +39 -26
- package/router/state.mjs +21 -15
- package/router/types.d.ts +64 -133
- package/server/global.d.ts +22 -0
- package/server/index.mjs +26 -10
- package/tsconfig.json +0 -3
package/router/types.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ import type {
|
|
|
4
4
|
Element as VElement,
|
|
5
5
|
TagFunc as IsoTagFunc,
|
|
6
6
|
} from "mini-van-plate/van-plate";
|
|
7
|
-
// import van from "vanjs-core";
|
|
8
7
|
import type {
|
|
9
8
|
ChildDom,
|
|
10
9
|
Primitive,
|
|
@@ -13,10 +12,8 @@ import type {
|
|
|
13
12
|
PropValueOrDerived,
|
|
14
13
|
State,
|
|
15
14
|
} from "vanjs-core";
|
|
16
|
-
import { LayoutFile } from "../plugin/types.d.ts";
|
|
15
|
+
import type { LayoutFile } from "../plugin/types.d.ts";
|
|
17
16
|
|
|
18
|
-
// type VanElement = VElement | Exclude<Primitive, boolean | undefined>;
|
|
19
|
-
// type DOMElement = globalThis.Element;
|
|
20
17
|
type PrimitiveChild = Primitive | State<Primitive | undefined | null>;
|
|
21
18
|
|
|
22
19
|
type DOMElement<T extends keyof HTMLElementTagNameMap = "div"> =
|
|
@@ -36,9 +33,7 @@ export type VanNode =
|
|
|
36
33
|
| null
|
|
37
34
|
| undefined;
|
|
38
35
|
|
|
39
|
-
type ComponentProps1<T> =
|
|
40
|
-
& Props
|
|
41
|
-
& PropsWithKnownKeys<T>;
|
|
36
|
+
type ComponentProps1<T> = Props & PropsWithKnownKeys<T>;
|
|
42
37
|
|
|
43
38
|
type ComponentProps<K extends keyof HTMLElementTagNameMap> =
|
|
44
39
|
& Props
|
|
@@ -56,22 +51,6 @@ export type VanComponent<
|
|
|
56
51
|
};
|
|
57
52
|
|
|
58
53
|
// router.mjs
|
|
59
|
-
/**
|
|
60
|
-
* A virtual component that renders the current route
|
|
61
|
-
* in your VanJS application. It must be used in your main component.
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* import { Router } from '@vanjs/router';
|
|
65
|
-
*
|
|
66
|
-
* export const App = () => {
|
|
67
|
-
* return Router(); // or <Router /> for JSX
|
|
68
|
-
* }
|
|
69
|
-
*/
|
|
70
|
-
// export const Router: JSX.Component<HTMLElement> & VanComponent<HTMLElement>;
|
|
71
|
-
// export function Router(props?: ComponentProps<HTMLElement>): HTMLElement;
|
|
72
|
-
// export function Router(
|
|
73
|
-
// props?: JSX.IntrinsicElements["main"] & { children: null },
|
|
74
|
-
// ): HTMLElement;
|
|
75
54
|
export const Router:
|
|
76
55
|
& VanComponent<"main">
|
|
77
56
|
& JSX.Component<"main">;
|
|
@@ -80,58 +59,50 @@ export const FileSystemRouter:
|
|
|
80
59
|
& JSX.Component<"main">;
|
|
81
60
|
|
|
82
61
|
// a.mjs
|
|
83
|
-
/**
|
|
84
|
-
* A virtual component that creates an anchor element
|
|
85
|
-
* that navigates to the specified href when clicked.
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* import { A } from '@vanjs/router';
|
|
89
|
-
* import van from 'vanjs-core';
|
|
90
|
-
*
|
|
91
|
-
* export const Navigation = () => {
|
|
92
|
-
* const { nav } = van.tags
|
|
93
|
-
* return nav(
|
|
94
|
-
* A({ href="/" }, "Home"), // or <A href="/">Home</A> with JSX
|
|
95
|
-
* A({ href="/about" }, "About"), // or <A href="/about">About</A> with JSX
|
|
96
|
-
* // ...other children
|
|
97
|
-
* );
|
|
98
|
-
* }
|
|
99
|
-
*/
|
|
100
62
|
export const A:
|
|
101
63
|
& VanComponent<"a">
|
|
102
64
|
& JSX.Component<"a">;
|
|
103
65
|
|
|
104
66
|
// helpers.mjs
|
|
105
|
-
/**
|
|
106
|
-
* Navigates to the specified href in the client and sets the router state.
|
|
107
|
-
* Keep in mind that the router handles the search params and hash.
|
|
108
|
-
*
|
|
109
|
-
* @param href the URL to navigate to
|
|
110
|
-
* @param options when true, will replace the current history entry
|
|
111
|
-
*/
|
|
112
67
|
export const navigate: (
|
|
113
68
|
href: string,
|
|
114
69
|
options?: { replace?: boolean },
|
|
115
70
|
) => void;
|
|
116
71
|
|
|
117
|
-
/**
|
|
118
|
-
* A client only helper function that reloads the current page.
|
|
119
|
-
*/
|
|
120
72
|
export const reload: () => void;
|
|
121
73
|
|
|
122
|
-
/**
|
|
123
|
-
* A helper function that redirects the user to the specified href.
|
|
124
|
-
* When called in the server, it will return a function that will redirect the user
|
|
125
|
-
* to the specified href when called.
|
|
126
|
-
* @param {string | undefined} href the URL to redirect to
|
|
127
|
-
*/
|
|
128
74
|
export const redirect: (href?: string) => void | (() => void);
|
|
129
75
|
|
|
76
|
+
export const getValue: (v: unknown) => string;
|
|
77
|
+
|
|
78
|
+
export const isCurrentPage: (pageName: string) => boolean;
|
|
79
|
+
|
|
80
|
+
export const isCurrentLocation: (pageName: string) => boolean;
|
|
81
|
+
|
|
82
|
+
export const isLazyComponent: (component: unknown) => boolean;
|
|
83
|
+
|
|
84
|
+
export const executeLifecycle: (
|
|
85
|
+
route: RouteEntry | {
|
|
86
|
+
preload?: (params?: Record<string, string>) => unknown;
|
|
87
|
+
load?: (params?: Record<string, string>) => unknown;
|
|
88
|
+
} | null,
|
|
89
|
+
params: Record<string, string> | undefined,
|
|
90
|
+
) => Promise<boolean>;
|
|
91
|
+
|
|
92
|
+
export const useRouteData: <T>() => T | undefined;
|
|
93
|
+
|
|
94
|
+
export const matchRoute: (path: string) => RouteEntry | null;
|
|
95
|
+
|
|
96
|
+
// extractParams.mjs
|
|
97
|
+
export const extractParams: (
|
|
98
|
+
pattern: string,
|
|
99
|
+
path: string,
|
|
100
|
+
) => Record<string, string> | null;
|
|
101
|
+
|
|
130
102
|
// routes.mjs
|
|
131
103
|
export type RouteEntry = {
|
|
132
104
|
path: string;
|
|
133
105
|
component: () => Promise<ComponentModule>;
|
|
134
|
-
// component: () => Promise<DynamicModule>;
|
|
135
106
|
params?: Record<string, string>;
|
|
136
107
|
preload?: (
|
|
137
108
|
params?: Record<string, string>,
|
|
@@ -143,24 +114,16 @@ export type RouteEntry = {
|
|
|
143
114
|
|
|
144
115
|
export type ImportFn = () => LazyComponent;
|
|
145
116
|
|
|
146
|
-
/**
|
|
147
|
-
* Registers a lazy component.
|
|
148
|
-
* @param importFn
|
|
149
|
-
*/
|
|
150
117
|
export const lazy: (importFn: ImportFn) => () => Promise<ComponentModule>;
|
|
151
118
|
|
|
152
119
|
export type RouteProps = {
|
|
153
120
|
path: string;
|
|
154
121
|
params?: Record<string, string>;
|
|
155
122
|
component:
|
|
156
|
-
// | (() => HTMLElementTagNameMap[unknown] | HTMLElementTagNameMap[unknown][])
|
|
157
|
-
// | VanNode
|
|
158
123
|
| (() => DOMElement)
|
|
159
124
|
| VanComponent
|
|
160
125
|
| ComponentFn
|
|
161
|
-
| (() => Promise<
|
|
162
|
-
// | ComponentModule["component"];
|
|
163
|
-
// component: ComponentFn | (() => Promise<ComponentModule>);
|
|
126
|
+
| (() => Promise<ComponentModule>);
|
|
164
127
|
preload?: (
|
|
165
128
|
params?: Record<string, string>,
|
|
166
129
|
) => boolean | void | Promise<boolean | void>;
|
|
@@ -177,19 +140,6 @@ export type RouteConfig = {
|
|
|
177
140
|
|
|
178
141
|
export const routes: RouteEntry[];
|
|
179
142
|
|
|
180
|
-
/**
|
|
181
|
-
* Registers a new route in the router state.
|
|
182
|
-
* @param route the route to register
|
|
183
|
-
*
|
|
184
|
-
* @example
|
|
185
|
-
* import { Route, lazy } from '@vanjs/router';
|
|
186
|
-
* import Home from './pages/Home';
|
|
187
|
-
* import NotFound from './pages/NotFound';
|
|
188
|
-
*
|
|
189
|
-
* Route({ path: '/', component: Home });
|
|
190
|
-
* Route({ path: '/about', component: lazy(() => import("./pages/About.ts")) });
|
|
191
|
-
* Route({ path: '*', component: NotFound });
|
|
192
|
-
*/
|
|
193
143
|
export const Route: (route: RouteProps) => void;
|
|
194
144
|
|
|
195
145
|
// state.mjs
|
|
@@ -197,39 +147,33 @@ export type RouterState = {
|
|
|
197
147
|
pathname: string;
|
|
198
148
|
searchParams: URLSearchParams;
|
|
199
149
|
params: Record<string, string>;
|
|
150
|
+
status: "idle" | "pending" | "success" | "error";
|
|
200
151
|
};
|
|
201
|
-
|
|
202
|
-
* A reactive object that holds the current router state.
|
|
203
|
-
* This state is maintained by both server and client.
|
|
204
|
-
*/
|
|
152
|
+
|
|
205
153
|
export const routerState: {
|
|
206
154
|
pathname: RouterState["pathname"];
|
|
207
155
|
searchParams: RouterState["searchParams"];
|
|
208
156
|
params?: RouterState["params"];
|
|
157
|
+
status: RouterState["status"];
|
|
209
158
|
};
|
|
210
159
|
|
|
211
|
-
/**
|
|
212
|
-
* Sets the router state to the specified href.
|
|
213
|
-
* @param href the URL to navigate to
|
|
214
|
-
* @param search the search string
|
|
215
|
-
* @param params the route params object
|
|
216
|
-
*/
|
|
217
160
|
export const setRouterState: (
|
|
218
161
|
href: string,
|
|
219
162
|
search?: string,
|
|
220
163
|
params?: Record<string, string>,
|
|
221
164
|
) => void;
|
|
222
165
|
|
|
223
|
-
export
|
|
224
|
-
children: VanNode[];
|
|
225
|
-
};
|
|
166
|
+
export const microStore: <T extends Record<string, unknown>>(init: T) => T;
|
|
226
167
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
168
|
+
// routeCache.mjs
|
|
169
|
+
export const cacheRoute: (key: ImportFn, value: ComponentModule) => void;
|
|
170
|
+
|
|
171
|
+
export const getCachedRoute: (key: ImportFn) => ComponentModule | undefined;
|
|
172
|
+
|
|
173
|
+
export const fixRouteUrl: (url: string) => string;
|
|
174
|
+
|
|
175
|
+
// unwrap.mjs
|
|
176
|
+
export type UnwrapResult = { children: VanNode[] };
|
|
233
177
|
|
|
234
178
|
export const unwrap: (
|
|
235
179
|
source:
|
|
@@ -257,42 +201,29 @@ export type ComponentModule = {
|
|
|
257
201
|
route?: Pick<RouteEntry, "load" | "preload">;
|
|
258
202
|
};
|
|
259
203
|
|
|
260
|
-
export type
|
|
261
|
-
Page: ComponentFn;
|
|
204
|
+
export type LazyComponent = Promise<{
|
|
262
205
|
default?: ComponentFn;
|
|
206
|
+
Page?: ComponentFn;
|
|
263
207
|
route?: Pick<RouteEntry, "load" | "preload">;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
export type LazyComponent = Promise<DynamicModule>;
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Fixes the URL of a route.
|
|
270
|
-
* @param url
|
|
271
|
-
*/
|
|
272
|
-
export const fixRouteUrl: (url: string) => string;
|
|
208
|
+
}>;
|
|
273
209
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Return a route cache.
|
|
283
|
-
* @param key the cache route key
|
|
284
|
-
*/
|
|
285
|
-
export const getCached: (key: typeof importFn) => ComponentModule | undefined;
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Execute lifecycle methods preload and / or load
|
|
289
|
-
*/
|
|
290
|
-
export const executeLifecycle: (
|
|
291
|
-
{ route }: ComponentModule,
|
|
292
|
-
params: Record<string, string> | undefined,
|
|
293
|
-
) => Promise<boolean>;
|
|
210
|
+
// dataCache.mjs
|
|
211
|
+
export type CacheEntry<T = unknown> = {
|
|
212
|
+
data: T;
|
|
213
|
+
error: Error | null;
|
|
214
|
+
timestamp: number;
|
|
215
|
+
};
|
|
294
216
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
217
|
+
export const dataCache: {
|
|
218
|
+
get<T>(pathname: string, key: string): CacheEntry<T> | undefined;
|
|
219
|
+
set<T>(pathname: string, key: string, entry: Partial<CacheEntry<T>>): void;
|
|
220
|
+
has(pathname: string, key?: string): boolean;
|
|
221
|
+
getRoute(pathname: string): Record<string, CacheEntry> | undefined;
|
|
222
|
+
del(pathname: string, key?: string): boolean;
|
|
223
|
+
clear(): void;
|
|
224
|
+
touch(pathname: string): void;
|
|
225
|
+
toJSON(): Record<string, Record<string, CacheEntry>>;
|
|
226
|
+
hydrateFromJSON(json: Record<string, Record<string, CacheEntry>>): void;
|
|
227
|
+
size(): number;
|
|
228
|
+
setMaxRoutes(n: number): void;
|
|
229
|
+
};
|
package/server/global.d.ts
CHANGED
|
@@ -47,4 +47,26 @@ declare module "@vanjs/server" {
|
|
|
47
47
|
* @returns HTML string
|
|
48
48
|
*/
|
|
49
49
|
export const renderToString: (source: Source) => Promise<string>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* A function that generates a <script> for initial hydration data.
|
|
53
|
+
* Serializes the full path-keyed data cache into window.__DATA_CACHE
|
|
54
|
+
* @returns HTML string
|
|
55
|
+
*/
|
|
56
|
+
export const getDataPreload: () => string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface Window {
|
|
60
|
+
__DATA_CACHE?: Record<
|
|
61
|
+
string,
|
|
62
|
+
Record<
|
|
63
|
+
string,
|
|
64
|
+
{
|
|
65
|
+
data: unknown;
|
|
66
|
+
status: string;
|
|
67
|
+
timestamp: number;
|
|
68
|
+
error: { message: string } | null;
|
|
69
|
+
}
|
|
70
|
+
>
|
|
71
|
+
>;
|
|
50
72
|
}
|
package/server/index.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { basename } from "node:path";
|
|
2
|
+
// import { routerState } from "../router/index.mjs";
|
|
3
|
+
import * as dataCache from "../router/dataCache.mjs";
|
|
2
4
|
export * from "../plugin/helpers.mjs";
|
|
3
5
|
|
|
4
6
|
/**
|
|
@@ -8,6 +10,7 @@ export const renderToString = async (inputSource) => {
|
|
|
8
10
|
const source = typeof inputSource === "function"
|
|
9
11
|
? inputSource()
|
|
10
12
|
: inputSource;
|
|
13
|
+
|
|
11
14
|
if (typeof source === "number") {
|
|
12
15
|
return String(source);
|
|
13
16
|
}
|
|
@@ -31,8 +34,8 @@ export const renderToString = async (inputSource) => {
|
|
|
31
34
|
}
|
|
32
35
|
return elements.join("");
|
|
33
36
|
}
|
|
34
|
-
// return String(source)
|
|
35
37
|
|
|
38
|
+
// return String(source)
|
|
36
39
|
// no source provided
|
|
37
40
|
// @ts-ignore - this is server side code
|
|
38
41
|
console.warn("Render error! Source not recognized: " + source);
|
|
@@ -49,17 +52,17 @@ function renderPreloadLink(file) {
|
|
|
49
52
|
} else if (file.endsWith(".css")) {
|
|
50
53
|
return `<link rel="preload" href="${file}" as="style" crossorigin>`;
|
|
51
54
|
} else if (file.endsWith(".woff")) {
|
|
52
|
-
return `
|
|
55
|
+
return ` <link rel="preload" href="${file}" as="font" type="font/woff" crossorigin>`;
|
|
53
56
|
} else if (file.endsWith(".woff2")) {
|
|
54
|
-
return `
|
|
57
|
+
return ` <link rel="preload" href="${file}" as="font" type="font/woff2" crossorigin>`;
|
|
55
58
|
} else if (file.endsWith(".gif")) {
|
|
56
|
-
return
|
|
59
|
+
return `<link rel="preload" href="${file}" as="image" type="image/gif">`;
|
|
57
60
|
} else if (file.endsWith(".jpg") || file.endsWith(".jpeg")) {
|
|
58
|
-
return
|
|
61
|
+
return `<link rel="preload" href="${file}" as="image" type="image/jpeg">`;
|
|
59
62
|
} else if (file.endsWith(".png")) {
|
|
60
|
-
return
|
|
63
|
+
return `<link rel="preload" href="${file}" as="image" type="image/png">`;
|
|
61
64
|
} else if (file.endsWith(".webp")) {
|
|
62
|
-
return
|
|
65
|
+
return `<link rel="preload" href="${file}" as="image" type="image/webp">`;
|
|
63
66
|
} else {
|
|
64
67
|
// @ts-ignore - this is server side code
|
|
65
68
|
console.warn("Render error! File format not recognized: " + file);
|
|
@@ -90,13 +93,11 @@ export function renderPreloadLinks(modules, manifest) {
|
|
|
90
93
|
// Second pass: generate preload links
|
|
91
94
|
modules.forEach((id) => {
|
|
92
95
|
const files = manifest[id];
|
|
93
|
-
|
|
94
96
|
// istanbul ignore else
|
|
95
97
|
if (files?.length) {
|
|
96
98
|
files.forEach((file) => {
|
|
97
99
|
// Skip if we've seen this file or if it's an asset from an ignored path
|
|
98
100
|
if (seen.has(file) || ignoredAssets.has(file)) return;
|
|
99
|
-
|
|
100
101
|
seen.add(file);
|
|
101
102
|
const filename = basename(file);
|
|
102
103
|
|
|
@@ -111,7 +112,6 @@ export function renderPreloadLinks(modules, manifest) {
|
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
|
-
|
|
115
115
|
links += renderPreloadLink(file);
|
|
116
116
|
});
|
|
117
117
|
}
|
|
@@ -119,3 +119,19 @@ export function renderPreloadLinks(modules, manifest) {
|
|
|
119
119
|
|
|
120
120
|
return links;
|
|
121
121
|
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Serialize route data for client hydration.
|
|
125
|
+
* Uses the new __DATA_CACHE format with path-keyed cache entries.
|
|
126
|
+
* @returns {string}
|
|
127
|
+
*/
|
|
128
|
+
export const getDataPreload = () => {
|
|
129
|
+
const cacheJSON = dataCache.toJSON();
|
|
130
|
+
const cacheEntries = Object.keys(cacheJSON);
|
|
131
|
+
|
|
132
|
+
if (cacheEntries.length > 0) {
|
|
133
|
+
const json = JSON.stringify(cacheJSON);
|
|
134
|
+
return `<script id="data-cache">window.__DATA_CACHE=${json}</script>`;
|
|
135
|
+
}
|
|
136
|
+
return "";
|
|
137
|
+
};
|
package/tsconfig.json
CHANGED
|
@@ -27,8 +27,6 @@
|
|
|
27
27
|
"jsxImportSource": "@vanjs/jsx"
|
|
28
28
|
},
|
|
29
29
|
"include": [
|
|
30
|
-
"./tests/*.ts",
|
|
31
|
-
"./tests/*.tsx",
|
|
32
30
|
"./plugin/*.ts",
|
|
33
31
|
"./jsx/*.ts",
|
|
34
32
|
"./setup/*.ts",
|
|
@@ -36,7 +34,6 @@
|
|
|
36
34
|
"./meta/*.ts",
|
|
37
35
|
"./server/*.ts",
|
|
38
36
|
"./client/*.ts",
|
|
39
|
-
"./tests/vite-env.d.ts"
|
|
40
37
|
],
|
|
41
38
|
"exclude": ["node_modules", "experiments", "coverage"],
|
|
42
39
|
}
|