vite-plugin-vanjs 0.0.3 → 0.0.5
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 +143 -15
- package/client/global.d.ts +41 -0
- package/client/index.mjs +48 -0
- package/client/package.json +18 -0
- package/client/types.d.ts +34 -0
- package/jsx/global.d.ts +4 -3
- package/jsx/jsx.d.ts +18 -10
- package/jsx/jsx.mjs +3 -2
- package/jsx/package.json +1 -1
- package/jsx/types.d.ts +16 -0
- package/meta/Head.mjs +81 -0
- package/meta/global.d.ts +60 -0
- package/meta/helpers.mjs +52 -0
- package/meta/index.mjs +3 -0
- package/meta/package.json +18 -0
- package/meta/tags.mjs +57 -0
- package/meta/types.d.ts +36 -0
- package/package.json +45 -13
- package/router/a.mjs +50 -0
- package/router/cache.mjs +14 -0
- package/router/global.d.ts +162 -0
- package/router/helpers.mjs +198 -0
- package/router/index.mjs +7 -0
- package/router/lazy.mjs +60 -0
- package/router/package.json +19 -0
- package/router/router.mjs +43 -0
- package/router/routes.mjs +51 -0
- package/router/state.mjs +27 -0
- package/router/types.d.ts +156 -0
- package/server/global.d.ts +49 -0
- package/server/index.mjs +97 -0
- package/server/package.json +20 -0
- package/server/types.d.ts +38 -0
- package/setup/package.json +2 -2
- package/setup/van.d.ts +1 -0
- package/setup/vanX.d.ts +1 -0
- package/setup/vanX.mjs +1 -1
- package/src/index.mjs +10 -10
- package/src/types.d.ts +28 -4
- package/tsconfig.json +14 -2
- package/jsx/index.d.ts +0 -16
- package/jsx/utils.mjs +0 -24
- /package/setup/{index.d.ts → types.d.ts} +0 -0
package/router/index.mjs
ADDED
package/router/lazy.mjs
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import setup from "@vanjs/setup";
|
|
2
|
+
import van from "vanjs-core";
|
|
3
|
+
import { cache, getCached } from "./cache.mjs";
|
|
4
|
+
|
|
5
|
+
/** @typedef {import('./types').VanNode} VanNode */
|
|
6
|
+
/** @typedef {import('./types').ComponentModule} ComponentModule */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Registers a lazy component.
|
|
10
|
+
* @param {Promise<VanNode>} importFn
|
|
11
|
+
* @returns {ComponentModule | Promise<ComponentModule>}
|
|
12
|
+
*/
|
|
13
|
+
export const lazy = (importFn) => {
|
|
14
|
+
if (setup.isServer) {
|
|
15
|
+
return async () => {
|
|
16
|
+
const cached = getCached(importFn);
|
|
17
|
+
/* istanbul ignore next */
|
|
18
|
+
if (cached) {
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
const module = await importFn();
|
|
22
|
+
const component = module.Page || module.default;
|
|
23
|
+
const result = { component, route: module.route };
|
|
24
|
+
|
|
25
|
+
cache(importFn, result);
|
|
26
|
+
return result;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let initialized = false;
|
|
31
|
+
const component = van.state(() => "");
|
|
32
|
+
const route = van.state({});
|
|
33
|
+
|
|
34
|
+
const load = () => {
|
|
35
|
+
if (initialized) return;
|
|
36
|
+
|
|
37
|
+
const cached = getCached(importFn);
|
|
38
|
+
/* istanbul ignore next */
|
|
39
|
+
if (cached) {
|
|
40
|
+
component.val = cached.component;
|
|
41
|
+
route.val = cached.route;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
initialized = true;
|
|
46
|
+
importFn().then((module) => {
|
|
47
|
+
const comp = module.Page || module.default;
|
|
48
|
+
cache(importFn, { component: comp, route: module.route });
|
|
49
|
+
component.val = comp;
|
|
50
|
+
route.val = module.route;
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const lazyComponent = () => {
|
|
55
|
+
load();
|
|
56
|
+
return { component: component.val(), route: route.val };
|
|
57
|
+
};
|
|
58
|
+
lazyComponent.isLazy = true;
|
|
59
|
+
return lazyComponent;
|
|
60
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "router",
|
|
3
|
+
"main": "./index.mjs",
|
|
4
|
+
"module": "./index.mjs",
|
|
5
|
+
"types": "./types.d.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./types.d.ts",
|
|
10
|
+
"import": "./index.mjs"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"vite-plugin-vanjs": "*",
|
|
15
|
+
"vanjs-core": "*",
|
|
16
|
+
"vanjs-ext": "*"
|
|
17
|
+
},
|
|
18
|
+
"sideEffects": false
|
|
19
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import van from "vanjs-core";
|
|
2
|
+
import setup from "@vanjs/setup";
|
|
3
|
+
import { routerState } from "./state.mjs";
|
|
4
|
+
import { matchRoute } from "./routes.mjs";
|
|
5
|
+
import { executeLifecycle, unwrap } from "./helpers.mjs";
|
|
6
|
+
|
|
7
|
+
export const Router = () => {
|
|
8
|
+
const { div } = van.tags;
|
|
9
|
+
// const meta = defaultMeta();
|
|
10
|
+
|
|
11
|
+
const mainLayout = () => {
|
|
12
|
+
const route = matchRoute(routerState.pathname.val);
|
|
13
|
+
/* istanbul ignore else */
|
|
14
|
+
if (!route) return div("404 - Not Found");
|
|
15
|
+
|
|
16
|
+
routerState.params.val = route.params || {};
|
|
17
|
+
// Server-side or async component: use renderComponent
|
|
18
|
+
if (setup.isServer) {
|
|
19
|
+
const renderComponent = async () => {
|
|
20
|
+
try {
|
|
21
|
+
const module = await route.component();
|
|
22
|
+
const component = module.component();
|
|
23
|
+
await executeLifecycle(module, route.params);
|
|
24
|
+
return unwrap(component).children;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
/* istanbul ignore next */
|
|
27
|
+
console.error("Router error:", error);
|
|
28
|
+
/* istanbul ignore next */
|
|
29
|
+
return div("Error loading page");
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return renderComponent();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const module = route.component();
|
|
37
|
+
// Client-side lazy component, lifeCycle is already executed on the server
|
|
38
|
+
// or when A component has been clicked in the client
|
|
39
|
+
return unwrap(module.component);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return mainLayout();
|
|
43
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// router/routes.mjs
|
|
2
|
+
import { extractParams, isLazyComponent } from "./helpers.mjs";
|
|
3
|
+
import { lazy } from "./lazy.mjs";
|
|
4
|
+
|
|
5
|
+
/** @typedef {import("./types.d.ts").RouteEntry} RouteEntry */
|
|
6
|
+
/** @typedef {import("./types.d.ts").RouteProps} RouteProps */
|
|
7
|
+
|
|
8
|
+
/** @type {RouteEntry[]} */
|
|
9
|
+
export const routes = [];
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {RouteProps} routeProps
|
|
13
|
+
*/
|
|
14
|
+
export const Route = (routeProps) => {
|
|
15
|
+
const { component, preload, load, ...rest } = routeProps;
|
|
16
|
+
|
|
17
|
+
// If component has lifecycle methods but isn't lazy, make it lazy
|
|
18
|
+
if (!isLazyComponent(component)) {
|
|
19
|
+
const wrappedComponent = lazy(() =>
|
|
20
|
+
Promise.resolve({
|
|
21
|
+
default: component,
|
|
22
|
+
route: { preload, load },
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
routes.push({ ...rest, component: wrappedComponent });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Otherwise keep original component
|
|
30
|
+
routes.push(routeProps);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Find a registered route that matches the given path
|
|
35
|
+
* @param {string} path
|
|
36
|
+
* @returns {RouteEntry | null}
|
|
37
|
+
*/
|
|
38
|
+
export const matchRoute = (path) => {
|
|
39
|
+
const exactMatch = routes.find((r) => r.path === path);
|
|
40
|
+
if (exactMatch) return { ...exactMatch, params: {} };
|
|
41
|
+
|
|
42
|
+
for (const route of routes) {
|
|
43
|
+
if (route.path === "*") continue;
|
|
44
|
+
const params = extractParams(route.path, path);
|
|
45
|
+
if (params) {
|
|
46
|
+
return { ...route, params };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return routes.find((r) => r.path === "*") || null;
|
|
51
|
+
};
|
package/router/state.mjs
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// router/state.js
|
|
2
|
+
import van from "vanjs-core";
|
|
3
|
+
import setup from "@vanjs/setup";
|
|
4
|
+
|
|
5
|
+
const initialPath = !setup.isServer ? globalThis.location.pathname : "/";
|
|
6
|
+
const initialSearch = !setup.isServer ? globalThis.location.search : "";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @type {typeof import("./types.d.ts").routerState}
|
|
10
|
+
*/
|
|
11
|
+
export const routerState = {
|
|
12
|
+
pathname: van.state(initialPath),
|
|
13
|
+
searchParams: van.state(new URLSearchParams(initialSearch)),
|
|
14
|
+
params: van.state({}),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @type {typeof import("./types.d.ts").setRouterState}
|
|
19
|
+
*/
|
|
20
|
+
export const setRouterState = (path, search = undefined, params) => {
|
|
21
|
+
const [pathname, searchParams] = path.split("?");
|
|
22
|
+
routerState.pathname.val = pathname;
|
|
23
|
+
routerState.searchParams.val = new URLSearchParams(
|
|
24
|
+
search || searchParams || "",
|
|
25
|
+
);
|
|
26
|
+
routerState.params.val = params || {};
|
|
27
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/// <reference path="global.d.ts" />
|
|
2
|
+
import type { Element } from "mini-van-plate/van-plate";
|
|
3
|
+
import van from "vanjs-core";
|
|
4
|
+
import type { PropsWithKnownKeys } from "vanjs-core";
|
|
5
|
+
|
|
6
|
+
type VanElement = Element & { children: VanNode[] };
|
|
7
|
+
type VanNode = SVGElement | HTMLElement | VanElement;
|
|
8
|
+
|
|
9
|
+
// router.mjs
|
|
10
|
+
/**
|
|
11
|
+
* A virtual component that renders the current route
|
|
12
|
+
* in your VanJS application. It must be used in your main component.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* import { Router } from '@vanjs/router';
|
|
16
|
+
*
|
|
17
|
+
* export const App = () => {
|
|
18
|
+
* return Router(); // or <Router /> for JSX
|
|
19
|
+
* }
|
|
20
|
+
*/
|
|
21
|
+
export const Router: () => VanNode | VanNode[];
|
|
22
|
+
|
|
23
|
+
// a.mjs
|
|
24
|
+
/**
|
|
25
|
+
* A virtual component that creates an anchor element
|
|
26
|
+
* that navigates to the specified href when clicked.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* import { A } from '@vanjs/router';
|
|
30
|
+
* import van from 'vanjs-core';
|
|
31
|
+
*
|
|
32
|
+
* export const Navigation = () => {
|
|
33
|
+
* const { nav } = van.tags
|
|
34
|
+
* return nav(
|
|
35
|
+
* A({ href="/" }, "Home"), // or <A href="/">Home</A> with JSX
|
|
36
|
+
* A({ href="/about" }, "About"), // or <A href="/about">About</A> with JSX
|
|
37
|
+
* // ...other children
|
|
38
|
+
* );
|
|
39
|
+
* }
|
|
40
|
+
*/
|
|
41
|
+
export const A: (
|
|
42
|
+
props: PropsWithKnownKeys<HTMLAnchorProps>,
|
|
43
|
+
...children: (Element | Node | string)[]
|
|
44
|
+
) => HTMLAnchorElement;
|
|
45
|
+
|
|
46
|
+
// helpers.mjs
|
|
47
|
+
/**
|
|
48
|
+
* Navigates to the specified href in the client and sets the router state.
|
|
49
|
+
* Keep in mind that the router handles the search params and hash.
|
|
50
|
+
*
|
|
51
|
+
* @param href the URL to navigate to
|
|
52
|
+
* @param options when true, will replace the current history entry
|
|
53
|
+
*/
|
|
54
|
+
export const navigate: (href: string, options?: { replace?: boolean }) => void;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A client only helper function that reloads the current page.
|
|
58
|
+
*/
|
|
59
|
+
export const reload: () => void;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A helper function that redirects the user to the specified href.
|
|
63
|
+
* When called in the server, it will return a function that will redirect the user
|
|
64
|
+
* to the specified href when called.
|
|
65
|
+
* @param {string | undefined} href the URL to redirect to
|
|
66
|
+
*/
|
|
67
|
+
export const redirect: (href?: string) => void | (() => void);
|
|
68
|
+
|
|
69
|
+
export type VanComponent = () => VanNode | VanNode[];
|
|
70
|
+
|
|
71
|
+
// routes.mjs
|
|
72
|
+
export type RouteEntry = {
|
|
73
|
+
path: string;
|
|
74
|
+
component: Promise<ComponentModule>;
|
|
75
|
+
preload?: (params?: Record<string, string>) => void;
|
|
76
|
+
load?: (params?: Record<string, string>) => void;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export type RouteProps = {
|
|
80
|
+
path: string;
|
|
81
|
+
component: VanComponent | (() => ComponentModule);
|
|
82
|
+
preload?: (params?: Record<string, string>) => void;
|
|
83
|
+
load?: (params?: Record<string, string>) => void;
|
|
84
|
+
};
|
|
85
|
+
export const routes: RouteEntry[];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Registers a new route in the router state.
|
|
89
|
+
* @param route the route to register
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* import { Route, lazy } from '@vanjs/router';
|
|
93
|
+
* import Home from './pages/Home';
|
|
94
|
+
* import NotFound from './pages/NotFound';
|
|
95
|
+
*
|
|
96
|
+
* Route({ path: '/', component: Home });
|
|
97
|
+
* Route({ path: '/about', component: lazy(() => import("./pages/About.ts")) });
|
|
98
|
+
* Route({ path: '*', component: NotFound });
|
|
99
|
+
*/
|
|
100
|
+
export const Route: (route: RouteProps) => void;
|
|
101
|
+
|
|
102
|
+
// state.mjs
|
|
103
|
+
export type RouterState = {
|
|
104
|
+
pathname: string;
|
|
105
|
+
searchParams: URLSearchParams;
|
|
106
|
+
params?: Record<string, string>;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* A reactive object that holds the current router state.
|
|
110
|
+
* This state is maintained by both server and client.
|
|
111
|
+
*/
|
|
112
|
+
export const routerState: {
|
|
113
|
+
pathname: van.state<RouterState.pathname>;
|
|
114
|
+
searchParams: van.state<RouterState.searchParams>;
|
|
115
|
+
params?: van.state<RouterState.params>;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Sets the router state to the specified href.
|
|
120
|
+
* @param href the URL to navigate to
|
|
121
|
+
* @param search the search string
|
|
122
|
+
* @param params the route params object
|
|
123
|
+
*/
|
|
124
|
+
export const setRouterState: (
|
|
125
|
+
href: string,
|
|
126
|
+
search?: string,
|
|
127
|
+
params?: Record<string, string>,
|
|
128
|
+
) => void;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Merge the children of an Element or an array of elements with an optional array of children
|
|
132
|
+
* into the childen of a single HTMLFragmentElement element.
|
|
133
|
+
* @param source
|
|
134
|
+
* @param children
|
|
135
|
+
*/
|
|
136
|
+
export const unwrap: (
|
|
137
|
+
source: VanNode | VanNode[] | (() => VanNode | VanNode[]),
|
|
138
|
+
...children: VanNode[]
|
|
139
|
+
) => VanNode;
|
|
140
|
+
|
|
141
|
+
export type ComponentModule = {
|
|
142
|
+
component: VanComponent;
|
|
143
|
+
route: Pick<RouteEntry, "load" | "preload">;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export type DynamicModule = {
|
|
147
|
+
Page: VanComponent;
|
|
148
|
+
default?: VanComponent;
|
|
149
|
+
route?: Pick<RouteEntry, "load" | "preload">;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export type LazyComponent =
|
|
153
|
+
| Promise<DynamicModule>
|
|
154
|
+
| (() => Promise<DynamicModule>);
|
|
155
|
+
|
|
156
|
+
export const lazy: (importFn: () => LazyComponent) => () => ComponentModule;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
declare module "@vanjs/server" {
|
|
2
|
+
import type { PropsWithKnownKeys } from "vanjs-core";
|
|
3
|
+
import type { SupportedTags } from "@vanjs/meta";
|
|
4
|
+
import type { JSX } from "@vanjs/jsx";
|
|
5
|
+
import type {
|
|
6
|
+
Element as VanElement,
|
|
7
|
+
TagFunc,
|
|
8
|
+
} from "mini-van-plate/van-plate";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A function that takes a list of files and a manifest and returns a string
|
|
12
|
+
* representing the HTML markup for preload links.
|
|
13
|
+
* @param files the list of files
|
|
14
|
+
* @param manifest the vite manifest
|
|
15
|
+
* @returns HTML string
|
|
16
|
+
*/
|
|
17
|
+
export const renderPreloadLinks: (
|
|
18
|
+
files: string[],
|
|
19
|
+
manifest: Record<string, string[]>,
|
|
20
|
+
) => string;
|
|
21
|
+
|
|
22
|
+
type ValidVanNode =
|
|
23
|
+
| boolean
|
|
24
|
+
| number
|
|
25
|
+
| string
|
|
26
|
+
| VanElement
|
|
27
|
+
| TagFunc;
|
|
28
|
+
|
|
29
|
+
type VanComponent = () =>
|
|
30
|
+
| ValidVanNode
|
|
31
|
+
| ValidVanNode[]
|
|
32
|
+
| SupportedTags
|
|
33
|
+
| SupportedTags[];
|
|
34
|
+
export type Source =
|
|
35
|
+
| JSX.Element
|
|
36
|
+
| VanComponent
|
|
37
|
+
| (() => VanComponent)
|
|
38
|
+
| Promise<ValidVanNode>
|
|
39
|
+
| ValidVanNode
|
|
40
|
+
| undefined;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A function that takes a multitude of source types and returns a string
|
|
44
|
+
* representing the HTML output.
|
|
45
|
+
* @param source the source
|
|
46
|
+
* @returns HTML string
|
|
47
|
+
*/
|
|
48
|
+
export const renderToString: (source: Source) => Promise<string>;
|
|
49
|
+
}
|
package/server/index.mjs
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @type {typeof import("./types.d.ts").renderToString}
|
|
5
|
+
*/
|
|
6
|
+
export const renderToString = async (inputSource) => {
|
|
7
|
+
const source = typeof inputSource === "function"
|
|
8
|
+
? inputSource()
|
|
9
|
+
: inputSource;
|
|
10
|
+
if (typeof source === "number") {
|
|
11
|
+
return String(source);
|
|
12
|
+
}
|
|
13
|
+
if (typeof source === "string") {
|
|
14
|
+
return source.trim();
|
|
15
|
+
}
|
|
16
|
+
if (typeof source === "boolean") {
|
|
17
|
+
return String(source);
|
|
18
|
+
}
|
|
19
|
+
if (typeof source === "object" && "render" in source) {
|
|
20
|
+
return source.render();
|
|
21
|
+
}
|
|
22
|
+
if (source instanceof Promise) {
|
|
23
|
+
return renderToString(await source);
|
|
24
|
+
}
|
|
25
|
+
/* istanbul ignore else */
|
|
26
|
+
if (Array.isArray(source)) {
|
|
27
|
+
const elements = [];
|
|
28
|
+
for (const el of source) {
|
|
29
|
+
elements.push(await renderToString(el));
|
|
30
|
+
}
|
|
31
|
+
return elements.join("");
|
|
32
|
+
}
|
|
33
|
+
// return String(source)
|
|
34
|
+
|
|
35
|
+
// no source provided
|
|
36
|
+
// @ts-ignore - this is server side code
|
|
37
|
+
console.warn("Render error! Source not recognized: " + source);
|
|
38
|
+
return "";
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {string} file
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
function renderPreloadLink(file) {
|
|
46
|
+
if (file.endsWith(".js") || file.endsWith(".mjs")) {
|
|
47
|
+
return `<link rel="modulepreload" as="script" crossorigin href="${file}">`;
|
|
48
|
+
} else if (file.endsWith(".css")) {
|
|
49
|
+
return `<link rel="stylesheet" href="${file}">`;
|
|
50
|
+
} else if (file.endsWith(".woff")) {
|
|
51
|
+
return ` <link rel="preload" href="${file}" as="font" type="font/woff" crossorigin>`;
|
|
52
|
+
} else if (file.endsWith(".woff2")) {
|
|
53
|
+
return ` <link rel="preload" href="${file}" as="font" type="font/woff2" crossorigin>`;
|
|
54
|
+
} else if (file.endsWith(".gif")) {
|
|
55
|
+
return ` <link rel="preload" href="${file}" as="image" type="image/gif">`;
|
|
56
|
+
} else if (file.endsWith(".jpg") || file.endsWith(".jpeg")) {
|
|
57
|
+
return ` <link rel="preload" href="${file}" as="image" type="image/jpeg">`;
|
|
58
|
+
} else if (file.endsWith(".png")) {
|
|
59
|
+
return ` <link rel="preload" href="${file}" as="image" type="image/png">`;
|
|
60
|
+
} else if (file.endsWith(".webp")) {
|
|
61
|
+
return ` <link rel="preload" href="${file}" as="image" type="image/webp">`;
|
|
62
|
+
} else {
|
|
63
|
+
// @ts-ignore - this is server side code
|
|
64
|
+
console.warn("Render error! File format not recognized: " + file);
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @type {typeof import("./types.d.ts").renderPreloadLinks}
|
|
71
|
+
*/
|
|
72
|
+
export function renderPreloadLinks(modules, manifest) {
|
|
73
|
+
let links = "";
|
|
74
|
+
const seen = new Set();
|
|
75
|
+
modules.forEach((id) => {
|
|
76
|
+
const files = manifest[id];
|
|
77
|
+
/* istanbul ignore else */
|
|
78
|
+
if (files?.length) {
|
|
79
|
+
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]) {
|
|
87
|
+
links += renderPreloadLink(depFile);
|
|
88
|
+
seen.add(depFile);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
links += renderPreloadLink(file);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return links;
|
|
97
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "server",
|
|
3
|
+
"main": "./index.mjs",
|
|
4
|
+
"module": "./index.mjs",
|
|
5
|
+
"types": "./types.d.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./types.d.ts",
|
|
10
|
+
"import": "./index.mjs"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"vite-plugin-vanjs": "*",
|
|
15
|
+
"mini-van-plate": "*",
|
|
16
|
+
"vanjs-core": "*",
|
|
17
|
+
"vanjs-ext": "*"
|
|
18
|
+
},
|
|
19
|
+
"sideEffects": false
|
|
20
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/// <reference path="global.d.ts" />
|
|
2
|
+
import type { Element as VanElement, TagFunc } from "mini-van-plate/van-plate";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A function that takes a list of files and a manifest and returns a string
|
|
6
|
+
* representing the HTML markup for preload links.
|
|
7
|
+
* @param files the list of files
|
|
8
|
+
* @param manifest the vite manifest
|
|
9
|
+
* @returns HTML string
|
|
10
|
+
*/
|
|
11
|
+
export const renderPreloadLinks: (
|
|
12
|
+
files: string[],
|
|
13
|
+
manifest: Record<string, string[]>,
|
|
14
|
+
) => string;
|
|
15
|
+
|
|
16
|
+
type ValidVanNode =
|
|
17
|
+
| boolean
|
|
18
|
+
| number
|
|
19
|
+
| string
|
|
20
|
+
| VanElement
|
|
21
|
+
| TagFunc;
|
|
22
|
+
|
|
23
|
+
type VanComponent = () => ValidVanNode | ValidVanNode[];
|
|
24
|
+
export type Source =
|
|
25
|
+
| Promise<ValidVanNode>
|
|
26
|
+
| VanComponent
|
|
27
|
+
| (() => VanComponent)
|
|
28
|
+
| ValidVanNode
|
|
29
|
+
| ValidVanNode[]
|
|
30
|
+
| undefined;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A function that takes a multitude of source types and returns a string
|
|
34
|
+
* representing the HTML output.
|
|
35
|
+
* @param source the source
|
|
36
|
+
* @returns HTML string
|
|
37
|
+
*/
|
|
38
|
+
export const renderToString: (source: Source) => Promise<string>;
|
package/setup/package.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"name": "setup",
|
|
3
3
|
"main": "./index.mjs",
|
|
4
4
|
"module": "./index.mjs",
|
|
5
|
-
"types": "./
|
|
5
|
+
"types": "./types.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"types": "./
|
|
9
|
+
"types": "./types.d.ts",
|
|
10
10
|
"import": "./index.mjs"
|
|
11
11
|
},
|
|
12
12
|
"./van": {
|
package/setup/van.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { Van } from "vanjs-core";
|
package/setup/vanX.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "vanjs-ext";
|
package/setup/vanX.mjs
CHANGED
package/src/index.mjs
CHANGED
|
@@ -10,42 +10,42 @@ export default function VitePluginVanJS() {
|
|
|
10
10
|
enforce: "pre",
|
|
11
11
|
config() {
|
|
12
12
|
return {
|
|
13
|
-
build: {
|
|
14
|
-
optimizeDeps: {
|
|
15
|
-
include: ["vanjs-core", "vanjs-ext", "mini-van-plate"],
|
|
16
|
-
},
|
|
17
|
-
dedupe: ["vanjs-core", "vanjs-ext", "mini-van-plate"],
|
|
18
|
-
},
|
|
19
13
|
resolve: {
|
|
20
14
|
alias: {
|
|
21
|
-
"@vanjs/jsx": resolve(__dirname, "../jsx"),
|
|
22
15
|
"@vanjs/setup": resolve(__dirname, "../setup"),
|
|
23
16
|
"@vanjs/van": resolve(__dirname, "../setup/van"),
|
|
24
17
|
"@vanjs/vanX": resolve(__dirname, "../setup/vanX"),
|
|
18
|
+
"@vanjs/client": resolve(__dirname, "../client"),
|
|
19
|
+
"@vanjs/server": resolve(__dirname, "../server"),
|
|
20
|
+
"@vanjs/meta": resolve(__dirname, "../meta"),
|
|
21
|
+
"@vanjs/router": resolve(__dirname, "../router"),
|
|
22
|
+
"@vanjs/jsx": resolve(__dirname, "../jsx"),
|
|
25
23
|
},
|
|
26
24
|
},
|
|
27
25
|
esbuild: {
|
|
28
26
|
jsx: "automatic",
|
|
29
|
-
|
|
30
|
-
jsxFragment: "Fragment",
|
|
27
|
+
jsxImportSource: "@vanjs/jsx",
|
|
31
28
|
},
|
|
32
29
|
};
|
|
33
30
|
},
|
|
34
31
|
transform(code, id) {
|
|
35
|
-
let newCode = code;
|
|
32
|
+
let newCode = String(code);
|
|
36
33
|
|
|
37
34
|
const vanCoreReg = /import\s*.*\s*from\s*['"]vanjs-core['"]/g;
|
|
38
35
|
const vanExtReg = /import\s*.*\s*from\s*['"]vanjs-ext['"]/g;
|
|
39
36
|
const isSetupFile = /vite-plugin-vanjs[\\/]setup/.test(id);
|
|
40
37
|
const isVanXFile = /vanjs-ext[\\/]src[\\/]van-x/.test(id);
|
|
41
38
|
|
|
39
|
+
/* istanbul ignore else */
|
|
42
40
|
if (!isSetupFile && !isVanXFile) {
|
|
41
|
+
/* istanbul ignore next - the plugin works, istanbul isn't instrumenting this part properly */
|
|
43
42
|
if (vanCoreReg.test(newCode)) {
|
|
44
43
|
newCode = newCode.replace(
|
|
45
44
|
vanCoreReg,
|
|
46
45
|
(match) => match.replace("vanjs-core", "@vanjs/van"),
|
|
47
46
|
);
|
|
48
47
|
}
|
|
48
|
+
/* istanbul ignore next - the plugin works, istanbul isn't instrumenting this part properly */
|
|
49
49
|
if (vanExtReg.test(newCode)) {
|
|
50
50
|
newCode = newCode.replace(
|
|
51
51
|
vanExtReg,
|