vite-plugin-vanjs 0.1.4 → 0.1.6
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 +1 -1
- package/client/index.mjs +38 -23
- package/package.json +2 -2
- package/plugin/types.d.ts +4 -7
- package/setup/vanX-ssr.mjs +23 -5
- package/setup/vanX.mjs +2 -5
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://github.com/vanjs-org/van)
|
|
9
9
|
[](https://github.com/vanjs-org/mini-van-plate)
|
|
10
10
|
[](https://www.vitest.dev/)
|
|
11
|
-
[](https://vite.dev)
|
|
12
12
|
|
|
13
13
|
A mini meta-framework for [VanJS](https://vanjs.org/) developed around the awesome [vite](https://vite.dev) and tested with [vitest](https://vitest.dev). The plugin comes with a set of modules to streamline your workflow:
|
|
14
14
|
* ***@vanjs/router*** - one of the most important part of an application which allows you to split code and lazy load page like components with ease, handles both Client Side Rendering (SSR) and Server Side Rendering (CSR) and makes it really easy to work with;
|
package/client/index.mjs
CHANGED
|
@@ -36,8 +36,8 @@ export const styleToString = (style) => {
|
|
|
36
36
|
: /* istanbul ignore next */ "";
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
/** @type {(el1: HTMLElement, el2: HTMLElement | HTMLElement[]) => boolean} */
|
|
40
|
-
export function elementsMatch(el1, el2) {
|
|
39
|
+
/** @type {(el1: HTMLElement, el2: HTMLElement | HTMLElement[], deep?: boolean) => boolean} */
|
|
40
|
+
export function elementsMatch(el1, el2, deep) {
|
|
41
41
|
// Quick initial checks before recursing
|
|
42
42
|
// istanbul ignore else
|
|
43
43
|
if (
|
|
@@ -63,15 +63,25 @@ export function elementsMatch(el1, el2) {
|
|
|
63
63
|
child.querySelector("[data-hk]"))
|
|
64
64
|
);
|
|
65
65
|
|
|
66
|
+
// istanbul ignore next
|
|
66
67
|
if (!hasHydratedChildren) {
|
|
67
68
|
return true; // If no hydrated children, elements match based on initial checks
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
// Only recurse if opted in
|
|
72
|
+
// istanbul ignore next
|
|
73
|
+
return deep
|
|
74
|
+
? childNodes1.every((child, idx) => elementsMatch(child, childNodes2[idx]))
|
|
75
|
+
: true;
|
|
73
76
|
}
|
|
74
77
|
|
|
78
|
+
/** @type {<E extends Element = Element, T extends keyof HTMLElementTagNameMap>(target: E, ...tagNames: T[]) => boolean} */
|
|
79
|
+
const isTag = (target, ...tagNames) => {
|
|
80
|
+
return tagNames.some((tag) =>
|
|
81
|
+
target.tagName.toLowerCase() === tag.toLowerCase()
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
75
85
|
function createHydrationContext() {
|
|
76
86
|
/** @type {WeakMap<Element, Element>} */
|
|
77
87
|
const parentCache = new WeakMap();
|
|
@@ -106,13 +116,18 @@ function createHydrationContext() {
|
|
|
106
116
|
return parent;
|
|
107
117
|
}
|
|
108
118
|
|
|
109
|
-
/** @type {(oldDom: HTMLElement, newDom: HTMLElement) => HTMLElement} */
|
|
119
|
+
/** @type {(oldDom: HTMLElement, newDom: HTMLElement | HTMLElement[]) => HTMLElement} */
|
|
110
120
|
function diffAndHydrate(oldDom, newDom) {
|
|
111
121
|
// SPA mode
|
|
112
122
|
// istanbul ignore else
|
|
113
123
|
if (!oldDom.children.length && !elementsMatch(oldDom, newDom)) {
|
|
114
124
|
return oldDom.replaceChildren(...unwrap(newDom).children);
|
|
115
125
|
}
|
|
126
|
+
// istanbul ignore else
|
|
127
|
+
if (newDom instanceof Array) {
|
|
128
|
+
oldDom.replaceChildren(...unwrap(newDom).children);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
116
131
|
|
|
117
132
|
// SSR Mode
|
|
118
133
|
/** @type {Set<HTMLElement>} */
|
|
@@ -175,12 +190,8 @@ export const hydrate = (target, content) => {
|
|
|
175
190
|
const wrapper = unwrap(content);
|
|
176
191
|
const currentChildren = Array.from(target.children);
|
|
177
192
|
const newChildren = Array.from(wrapper.children);
|
|
178
|
-
const isStyleLink = (tag) =>
|
|
179
|
-
[HTMLStyleElement, HTMLLinkElement].some((e) => tag instanceof e);
|
|
180
|
-
const isStyle = (tag) => tag instanceof HTMLStyleElement;
|
|
181
|
-
const isLink = (tag) => tag instanceof HTMLLinkElement;
|
|
182
193
|
|
|
183
|
-
if (target
|
|
194
|
+
if (isTag(target, "head")) {
|
|
184
195
|
// Keep current tags on first hydration
|
|
185
196
|
if (!target.hasAttribute("data-h")) {
|
|
186
197
|
target.setAttribute("data-h", "");
|
|
@@ -188,14 +199,18 @@ export const hydrate = (target, content) => {
|
|
|
188
199
|
}
|
|
189
200
|
|
|
190
201
|
// Handle non-style/link tags first
|
|
191
|
-
const regularTags = newChildren.filter((child) =>
|
|
202
|
+
const regularTags = newChildren.filter((child) =>
|
|
203
|
+
!isTag(child, "style", "link")
|
|
204
|
+
);
|
|
192
205
|
|
|
193
206
|
// Handle style/link tags separately
|
|
194
|
-
const styleTags = newChildren.filter((child) =>
|
|
207
|
+
const styleTags = newChildren.filter((child) =>
|
|
208
|
+
isTag(child, "style", "link")
|
|
209
|
+
);
|
|
195
210
|
|
|
196
211
|
// Create maps for existing tags
|
|
197
212
|
const existingStyles = new Map(
|
|
198
|
-
currentChildren.filter(
|
|
213
|
+
currentChildren.filter((child) => isTag(child, "style", "link"))
|
|
199
214
|
.map((child) => [getTagKey(child), child]),
|
|
200
215
|
);
|
|
201
216
|
|
|
@@ -219,29 +234,29 @@ export const hydrate = (target, content) => {
|
|
|
219
234
|
|
|
220
235
|
// Skip if tag already exists with same content+id/href
|
|
221
236
|
if (existing) {
|
|
222
|
-
|
|
223
|
-
if (
|
|
237
|
+
// istanbul ignore next - try again later
|
|
238
|
+
if (isTag(existing, "style") && isTag(newChild, "style")) {
|
|
224
239
|
if (
|
|
225
240
|
existing.textContent === newChild.textContent &&
|
|
226
241
|
existing.id === newChild.id
|
|
227
242
|
) return;
|
|
228
243
|
}
|
|
229
|
-
|
|
230
|
-
if (
|
|
244
|
+
// istanbul ignore next - try again later
|
|
245
|
+
if (isTag(existing, "link") && isTag(newChild, "link")) {
|
|
231
246
|
if (existing.href === newChild.href) return;
|
|
232
247
|
}
|
|
233
248
|
}
|
|
234
249
|
|
|
235
250
|
// For link tags, add with disabled state first
|
|
236
|
-
|
|
237
|
-
if (
|
|
251
|
+
// istanbul ignore else - try again later
|
|
252
|
+
if (isTag(newChild, "link")) {
|
|
238
253
|
const temp = newChild.cloneNode();
|
|
239
254
|
temp.disabled = true;
|
|
240
255
|
|
|
241
256
|
const originalRel = temp.rel;
|
|
242
257
|
temp.rel = "preload";
|
|
243
258
|
temp.as = "style";
|
|
244
|
-
|
|
259
|
+
// istanbul ignore next
|
|
245
260
|
temp.onload = () => {
|
|
246
261
|
temp.rel = originalRel;
|
|
247
262
|
temp.removeAttribute("as");
|
|
@@ -253,9 +268,9 @@ export const hydrate = (target, content) => {
|
|
|
253
268
|
|
|
254
269
|
target.appendChild(temp);
|
|
255
270
|
} // For style tags, add new one first
|
|
256
|
-
else if (
|
|
271
|
+
else if (isTag(newChild, "style")) {
|
|
257
272
|
target.appendChild(newChild);
|
|
258
|
-
|
|
273
|
+
// istanbul ignore next - try again later
|
|
259
274
|
if (existing && existing.parentNode === target) {
|
|
260
275
|
// Remove old one in next frame
|
|
261
276
|
existing.remove();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-vanjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"author": "thednp",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "A mini meta-framework for VanJS powered by Vite",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"@vitest/ui": "^3.1.2",
|
|
94
94
|
"happy-dom": "^16.8.1",
|
|
95
95
|
"typescript": "5.6.2",
|
|
96
|
-
"vite": "^6.3.
|
|
96
|
+
"vite": "^6.3.4",
|
|
97
97
|
"vitest": "^3.1.2"
|
|
98
98
|
},
|
|
99
99
|
"packageManager": "pnpm@8.6.12",
|
package/plugin/types.d.ts
CHANGED
|
@@ -6,18 +6,15 @@ export * from "../meta/types";
|
|
|
6
6
|
export * from "../server/types";
|
|
7
7
|
export * from "../client/types";
|
|
8
8
|
export * from "../parser/types";
|
|
9
|
-
import type {
|
|
9
|
+
import type { PluginOption } from "vite";
|
|
10
10
|
|
|
11
11
|
export type VanJSPluginOptions = {
|
|
12
12
|
routesDir: string;
|
|
13
13
|
extensions: string[];
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
) =>
|
|
19
|
-
|
|
20
|
-
// This is what your plugin actually returns, so declare it as a Plugin type
|
|
21
|
-
declare const VitePluginVanJS: VanJSPlugin;
|
|
16
|
+
export declare const VitePluginVanJS: (
|
|
17
|
+
config?: VitePluginVanJS,
|
|
18
|
+
) => PluginOption<VanJSPluginOptions>;
|
|
22
19
|
|
|
23
20
|
export default VitePluginVanJS;
|
package/setup/vanX-ssr.mjs
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
import { dummyVanX, registerEnv } from "mini-van-plate/shared";
|
|
2
2
|
|
|
3
|
+
const {
|
|
4
|
+
calc,
|
|
5
|
+
compact,
|
|
6
|
+
list,
|
|
7
|
+
noreactive,
|
|
8
|
+
raw,
|
|
9
|
+
reactive,
|
|
10
|
+
replace,
|
|
11
|
+
stateFields,
|
|
12
|
+
} = dummyVanX;
|
|
13
|
+
|
|
3
14
|
const vanX = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
15
|
+
calc,
|
|
16
|
+
compact,
|
|
17
|
+
list,
|
|
18
|
+
noreactive,
|
|
19
|
+
raw,
|
|
20
|
+
reactive,
|
|
21
|
+
replace,
|
|
22
|
+
stateFields,
|
|
8
23
|
};
|
|
9
24
|
|
|
10
25
|
registerEnv({ vanX });
|
|
11
26
|
|
|
12
|
-
export
|
|
27
|
+
export { calc, compact, list, noreactive, raw, reactive, replace, stateFields };
|
|
28
|
+
|
|
29
|
+
export { vanX as default };
|
|
30
|
+
export {};
|
package/setup/vanX.mjs
CHANGED
|
@@ -20,14 +20,11 @@ const vanX = {
|
|
|
20
20
|
list,
|
|
21
21
|
replace,
|
|
22
22
|
compact,
|
|
23
|
-
// Define default as part of the initial object
|
|
24
|
-
get default() {
|
|
25
|
-
return vanX;
|
|
26
|
-
},
|
|
27
23
|
};
|
|
28
24
|
|
|
29
25
|
// Export named exports
|
|
30
26
|
export { calc, compact, list, noreactive, raw, reactive, replace, stateFields };
|
|
31
27
|
|
|
32
28
|
// Export as default
|
|
33
|
-
export default
|
|
29
|
+
export { vanX as default };
|
|
30
|
+
export {};
|