vite-plugin-vanjs 0.0.8 → 0.0.10
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 +16 -17
- package/jsx/jsx.mjs +6 -1
- package/package.json +8 -7
- package/router/a.mjs +1 -1
- package/router/global.d.ts +6 -1
- package/router/lazy.mjs +1 -1
- package/router/router.mjs +95 -9
- package/router/routes.mjs +8 -3
- package/router/types.d.ts +4 -1
package/README.md
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
[](https://www.typescriptlang.org/)
|
|
8
8
|
[](https://github.com/vanjs-org/van)
|
|
9
9
|
[](https://github.com/vanjs-org/mini-van-plate)
|
|
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). The plugin comes with a set of modules to simplify 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;
|
|
@@ -20,6 +20,9 @@ A mini meta-framework for [VanJS](https://vanjs.org/) developed around the aweso
|
|
|
20
20
|
|
|
21
21
|
The plugin will automatically load the appropriate Van or VanX objects depending on the client/server environment with zero configuration needed. It uses the `mini-van-plate/shared` module to register the required objects in an isomorphic enviroment.
|
|
22
22
|
|
|
23
|
+
Also in _development_ mode, the plugin will load the `van.debug.js` module to help you better troubleshoot your VanJS application.
|
|
24
|
+
|
|
25
|
+
|
|
23
26
|
### Notes
|
|
24
27
|
* The plugin uses `van-ext` along with `mini-van-plate` so you can have everything ready from the start.
|
|
25
28
|
|
|
@@ -31,19 +34,19 @@ The plugin will automatically load the appropriate Van or VanX objects depending
|
|
|
31
34
|
1) Install the plugin:
|
|
32
35
|
|
|
33
36
|
```bash
|
|
34
|
-
npm install vite-plugin-vanjs
|
|
37
|
+
npm install vite-plugin-vanjs@latest
|
|
35
38
|
```
|
|
36
39
|
|
|
37
40
|
```bash
|
|
38
|
-
pnpm add vite-plugin-vanjs
|
|
41
|
+
pnpm add vite-plugin-vanjs@latest
|
|
39
42
|
```
|
|
40
43
|
|
|
41
44
|
```bash
|
|
42
|
-
deno add npm:vite-plugin-vanjs
|
|
45
|
+
deno add npm:vite-plugin-vanjs@latest
|
|
43
46
|
```
|
|
44
47
|
|
|
45
48
|
```bash
|
|
46
|
-
bun
|
|
49
|
+
bun add vite-plugin-vanjs@latest
|
|
47
50
|
```
|
|
48
51
|
|
|
49
52
|
|
|
@@ -127,12 +130,14 @@ Route({ path: '*', component: () => van.tags.div('404 - Page Not Found') });
|
|
|
127
130
|
|
|
128
131
|
function App() {
|
|
129
132
|
// the Router is only an outlet
|
|
130
|
-
|
|
133
|
+
return Router();
|
|
131
134
|
}
|
|
132
135
|
|
|
133
|
-
// render
|
|
136
|
+
// render the app
|
|
134
137
|
van.add(document.body, App());
|
|
135
138
|
```
|
|
139
|
+
**IMPORTANT** - using lazy components for the main route (`"/"`) is not allowed. This is to prevent hydration waterfalls, especially for SSR apps.
|
|
140
|
+
|
|
136
141
|
|
|
137
142
|
Here's how a page should look like, pay attention to the comments:
|
|
138
143
|
```ts
|
|
@@ -176,23 +181,17 @@ The **vite-plugin-vanjs** plugin provides metadata management via the exported `
|
|
|
176
181
|
|
|
177
182
|
Depending on the type of application, it's generally very easy to setup the system to work properly, we only need to make sure that we execute functions in a specific order:
|
|
178
183
|
|
|
179
|
-
* first we
|
|
180
|
-
*
|
|
181
|
-
* lastly, on other pages, we define tags that override both the existing and the default tags.
|
|
184
|
+
* first we define a set of default tags to be used by both client and server (if using an SSR template) on all pages that don't come with any metadata tags;
|
|
185
|
+
* next, on other pages, we define tags that override both the existing and the default tags.
|
|
182
186
|
|
|
183
187
|
Here's a quick example, first let's start again with the `app.ts`:
|
|
184
188
|
```ts
|
|
185
189
|
import van from 'vanjs-core'
|
|
186
|
-
import { Style, Title,
|
|
190
|
+
import { Style, Title, Link, Meta } from '@vanjs/meta'
|
|
187
191
|
|
|
188
192
|
function App() {
|
|
189
193
|
const { div, h1, p } van.tags;
|
|
190
194
|
|
|
191
|
-
// when app is first time executed
|
|
192
|
-
// we need to register tags coming
|
|
193
|
-
// from the index.html template
|
|
194
|
-
initializeHeadTags();
|
|
195
|
-
|
|
196
195
|
// a good practice is to define some default tags
|
|
197
196
|
// they are used on pages where no tags are set
|
|
198
197
|
Title("VanJS + Vite App");
|
package/jsx/jsx.mjs
CHANGED
|
@@ -2,7 +2,12 @@ import van from "../setup/van.mjs";
|
|
|
2
2
|
import setup from "../setup/index.mjs";
|
|
3
3
|
import { setAttribute, styleToString } from "../client/index.mjs";
|
|
4
4
|
|
|
5
|
-
export const jsx = (jsxTag, { children, ref, style, ...
|
|
5
|
+
export const jsx = (jsxTag, { children, ref, style, ...rest }) => {
|
|
6
|
+
// filter props with undefined values
|
|
7
|
+
const props = Object.fromEntries(
|
|
8
|
+
Object.entries(rest).filter(([_, val]) => val !== undefined),
|
|
9
|
+
);
|
|
10
|
+
|
|
6
11
|
if (typeof jsxTag === "string") {
|
|
7
12
|
const newElement = van.tags[jsxTag](props, children);
|
|
8
13
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-vanjs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"author": "thednp",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "A mini meta-framework for VanJS powered by Vite",
|
|
@@ -87,15 +87,16 @@
|
|
|
87
87
|
"vanjs-ext": "^0.6.2"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
-
"@types/node": "^22.
|
|
91
|
-
"@vitest/browser": "^3.
|
|
92
|
-
"@vitest/coverage-istanbul": "^3.
|
|
93
|
-
"@vitest/ui": "^3.
|
|
90
|
+
"@types/node": "^22.14.0",
|
|
91
|
+
"@vitest/browser": "^3.1.1",
|
|
92
|
+
"@vitest/coverage-istanbul": "^3.1.1",
|
|
93
|
+
"@vitest/ui": "^3.1.1",
|
|
94
94
|
"happy-dom": "^16.8.1",
|
|
95
95
|
"typescript": "5.6.2",
|
|
96
|
-
"vite": "^6.2.
|
|
97
|
-
"vitest": "^3.
|
|
96
|
+
"vite": "^6.2.5",
|
|
97
|
+
"vitest": "^3.1.1"
|
|
98
98
|
},
|
|
99
|
+
"packageManager": "pnpm@8.6.12",
|
|
99
100
|
"engines": {
|
|
100
101
|
"node": ">=20",
|
|
101
102
|
"pnpm": ">=8.6.0"
|
package/router/a.mjs
CHANGED
|
@@ -15,7 +15,7 @@ export const A = (
|
|
|
15
15
|
) => {
|
|
16
16
|
/* istanbul ignore next - try again later */
|
|
17
17
|
const props = Object.fromEntries(
|
|
18
|
-
Object.entries(rest || {}).filter(([_, val]) => val),
|
|
18
|
+
Object.entries(rest || {}).filter(([_, val]) => val !== undefined),
|
|
19
19
|
);
|
|
20
20
|
const newProps = {
|
|
21
21
|
href,
|
package/router/global.d.ts
CHANGED
|
@@ -129,7 +129,12 @@ declare module "@vanjs/router" {
|
|
|
129
129
|
|
|
130
130
|
export type RouteProps = {
|
|
131
131
|
path: string;
|
|
132
|
-
component:
|
|
132
|
+
component:
|
|
133
|
+
| (() =>
|
|
134
|
+
| HTMLElementTagNameMap[unknown]
|
|
135
|
+
| HTMLElementTagNameMap[unknown][])
|
|
136
|
+
| VanComponent
|
|
137
|
+
| (() => ComponentModule);
|
|
133
138
|
preload?: (params?: Record<string, string>) => void;
|
|
134
139
|
load?: (params?: Record<string, string>) => void;
|
|
135
140
|
};
|
package/router/lazy.mjs
CHANGED
package/router/router.mjs
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
import van from "vanjs-core";
|
|
2
2
|
import setup from "../setup/index.mjs";
|
|
3
|
-
import { routerState } from "./state.mjs";
|
|
3
|
+
import { routerState, setRouterState } from "./state.mjs";
|
|
4
4
|
import { matchRoute } from "./routes.mjs";
|
|
5
5
|
import { executeLifecycle, unwrap } from "./helpers.mjs";
|
|
6
|
+
import { hydrate } from "../client/index.mjs";
|
|
7
|
+
import { Head, initializeHeadTags } from "@vanjs/meta";
|
|
8
|
+
|
|
9
|
+
let isConnected = false;
|
|
10
|
+
/** @param {Event & {target: globalThis}} e */
|
|
11
|
+
// istanbul ignore next - cannot test
|
|
12
|
+
const popHandler = (e) => {
|
|
13
|
+
const location = e.target.location;
|
|
14
|
+
const oldPath = routerState.pathname._oldVal;
|
|
15
|
+
// istanbul ignore next - cannot test
|
|
16
|
+
if (location.pathname !== oldPath) {
|
|
17
|
+
setRouterState(location.pathname, location.search);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
6
20
|
|
|
7
21
|
export const Router = (initialProps = /* istanbul ignore next */ {}) => {
|
|
8
22
|
const { div, main } = van.tags;
|
|
23
|
+
|
|
9
24
|
/* istanbul ignore next - try again later */
|
|
10
25
|
const props = Object.fromEntries(
|
|
11
|
-
Object.entries(initialProps).filter(([_, val]) => val),
|
|
26
|
+
Object.entries(initialProps).filter(([_, val]) => val !== undefined),
|
|
12
27
|
);
|
|
13
|
-
const wrapper = main(props);
|
|
28
|
+
const wrapper = main({ ...props, "data-root": true });
|
|
14
29
|
const mainLayout = () => {
|
|
15
30
|
const route = matchRoute(routerState.pathname.val);
|
|
16
31
|
/* istanbul ignore else */
|
|
@@ -22,7 +37,9 @@ export const Router = (initialProps = /* istanbul ignore next */ {}) => {
|
|
|
22
37
|
const renderComponent = async () => {
|
|
23
38
|
try {
|
|
24
39
|
const module = await route.component();
|
|
25
|
-
const component = module.component
|
|
40
|
+
const component = typeof module.component === "function"
|
|
41
|
+
? module.component()
|
|
42
|
+
: /* istanbul ignore next */ module.component;
|
|
26
43
|
|
|
27
44
|
await executeLifecycle(module, route.params);
|
|
28
45
|
return van.add(wrapper, unwrap(component).children);
|
|
@@ -37,13 +54,82 @@ export const Router = (initialProps = /* istanbul ignore next */ {}) => {
|
|
|
37
54
|
return renderComponent();
|
|
38
55
|
}
|
|
39
56
|
|
|
57
|
+
const root = document.querySelector("[data-root]");
|
|
58
|
+
// istanbul ignore else - cannot test unmount
|
|
59
|
+
if (isConnected || !root) {
|
|
60
|
+
initializeHeadTags();
|
|
61
|
+
globalThis.addEventListener("popstate", popHandler);
|
|
62
|
+
} else {
|
|
63
|
+
globalThis.removeEventListener("popstate", popHandler);
|
|
64
|
+
}
|
|
65
|
+
|
|
40
66
|
// Client-side lazy component, lifeCycle is already executed on the server
|
|
41
67
|
// or when A component has been clicked in the client
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
68
|
+
if (root) {
|
|
69
|
+
// this case is when root is server side rendered
|
|
70
|
+
const module = route.component();
|
|
71
|
+
const children = () => {
|
|
72
|
+
// istanbul ignore next - cannot test
|
|
73
|
+
const cp = (Array.isArray(module) || module instanceof Element)
|
|
74
|
+
? module
|
|
75
|
+
: typeof module.component === "function"
|
|
76
|
+
? module.component()
|
|
77
|
+
: module.component;
|
|
78
|
+
// istanbul ignore next - cannot test
|
|
79
|
+
const kids = () => cp ? Array.from(unwrap(cp).children) : [];
|
|
80
|
+
const kudos = kids();
|
|
81
|
+
|
|
82
|
+
// istanbul ignore else
|
|
83
|
+
if (document.head) {
|
|
84
|
+
isConnected = true;
|
|
85
|
+
van.hydrate(document.head, (head) => hydrate(head, Head()));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return kudos;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return van.add(wrapper, ...children());
|
|
92
|
+
}
|
|
93
|
+
// this case is when root is for SPA apps
|
|
94
|
+
const csrRoute = van.derive(() => {
|
|
95
|
+
const p = routerState.pathname.val;
|
|
96
|
+
return matchRoute(p);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const children = van.derive(() => {
|
|
100
|
+
const md = csrRoute.val.component();
|
|
101
|
+
// istanbul ignore next - cannot test all cases
|
|
102
|
+
const cp = (Array.isArray(md) || md instanceof Element)
|
|
103
|
+
? md
|
|
104
|
+
: typeof md.component === "function"
|
|
105
|
+
? md.component()
|
|
106
|
+
: md.component;
|
|
107
|
+
return cp
|
|
108
|
+
? Array.from(unwrap(cp).children)
|
|
109
|
+
: /* istanbul ignore next */ [];
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const component = () => {
|
|
113
|
+
const kids = () => children.val;
|
|
114
|
+
const result = () => {
|
|
115
|
+
return van.derive(() =>
|
|
116
|
+
van.hydrate(wrapper, (el) => {
|
|
117
|
+
const kudos = kids();
|
|
118
|
+
isConnected = true;
|
|
119
|
+
// istanbul ignore else
|
|
120
|
+
if (document.head) {
|
|
121
|
+
van.hydrate(document.head, (head) => hydrate(head, Head()));
|
|
122
|
+
}
|
|
123
|
+
return hydrate(el, kudos);
|
|
124
|
+
})
|
|
125
|
+
).val;
|
|
126
|
+
};
|
|
127
|
+
return result();
|
|
128
|
+
};
|
|
129
|
+
const finalResult = component();
|
|
130
|
+
return finalResult
|
|
131
|
+
? /* istanbul ignore next*/ van.add(wrapper, finalResult)
|
|
132
|
+
: wrapper;
|
|
47
133
|
};
|
|
48
134
|
|
|
49
135
|
return mainLayout();
|
package/router/routes.mjs
CHANGED
|
@@ -12,17 +12,22 @@ export const routes = [];
|
|
|
12
12
|
* @param {RouteProps} routeProps
|
|
13
13
|
*/
|
|
14
14
|
export const Route = (routeProps) => {
|
|
15
|
-
const { component, preload, load, ...rest } = routeProps;
|
|
15
|
+
const { path, component, preload, load, ...rest } = routeProps;
|
|
16
|
+
|
|
17
|
+
// istanbul ignore next - no point testing this error
|
|
18
|
+
if (path === "/" && isLazyComponent(component)) {
|
|
19
|
+
throw new Error("Home component must not be a lazy component");
|
|
20
|
+
}
|
|
16
21
|
|
|
17
22
|
// If component has lifecycle methods but isn't lazy, make it lazy
|
|
18
|
-
if (!isLazyComponent(component)) {
|
|
23
|
+
if (!isLazyComponent(component) && path !== "/") {
|
|
19
24
|
const wrappedComponent = lazy(() =>
|
|
20
25
|
Promise.resolve({
|
|
21
26
|
default: component,
|
|
22
27
|
route: { preload, load },
|
|
23
28
|
})
|
|
24
29
|
);
|
|
25
|
-
routes.push({ ...rest, component: wrappedComponent });
|
|
30
|
+
routes.push({ ...rest, path, component: wrappedComponent });
|
|
26
31
|
return;
|
|
27
32
|
}
|
|
28
33
|
|
package/router/types.d.ts
CHANGED
|
@@ -129,7 +129,10 @@ export type RouteEntry = {
|
|
|
129
129
|
|
|
130
130
|
export type RouteProps = {
|
|
131
131
|
path: string;
|
|
132
|
-
component:
|
|
132
|
+
component:
|
|
133
|
+
| (() => HTMLElementTagNameMap[unknown] | HTMLElementTagNameMap[unknown][])
|
|
134
|
+
| VanComponent
|
|
135
|
+
| (() => ComponentModule);
|
|
133
136
|
preload?: (params?: Record<string, string>) => void;
|
|
134
137
|
load?: (params?: Record<string, string>) => void;
|
|
135
138
|
};
|