vite-plugin-vanjs 0.0.2 → 0.0.4

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.
Files changed (49) hide show
  1. package/README.md +147 -21
  2. package/client/global.d.ts +41 -0
  3. package/client/index.mjs +48 -0
  4. package/client/package.json +18 -0
  5. package/client/types.d.ts +34 -0
  6. package/jsx/fragment.d.ts +0 -1
  7. package/jsx/global.d.ts +4 -3
  8. package/jsx/index.mjs +3 -3
  9. package/jsx/jsx-dev-runtime.mjs +1 -1
  10. package/jsx/jsx-runtime.mjs +1 -1
  11. package/jsx/jsx.d.ts +18 -10
  12. package/jsx/jsx.mjs +3 -2
  13. package/jsx/package.json +1 -1
  14. package/jsx/types.d.ts +16 -0
  15. package/meta/Head.mjs +81 -0
  16. package/meta/global.d.ts +60 -0
  17. package/meta/helpers.mjs +52 -0
  18. package/meta/index.mjs +3 -0
  19. package/meta/package.json +18 -0
  20. package/meta/tags.mjs +57 -0
  21. package/meta/types.d.ts +36 -0
  22. package/package.json +45 -13
  23. package/router/a.mjs +50 -0
  24. package/router/cache.mjs +14 -0
  25. package/router/global.d.ts +162 -0
  26. package/router/helpers.mjs +198 -0
  27. package/router/index.mjs +6 -0
  28. package/router/lazy.mjs +60 -0
  29. package/router/package.json +19 -0
  30. package/router/router.mjs +43 -0
  31. package/router/routes.mjs +51 -0
  32. package/router/state.mjs +27 -0
  33. package/router/types.d.ts +156 -0
  34. package/server/global.d.ts +49 -0
  35. package/server/index.mjs +97 -0
  36. package/server/package.json +20 -0
  37. package/server/types.d.ts +38 -0
  38. package/setup/global.d.ts +33 -4
  39. package/setup/index.mjs +4 -1
  40. package/setup/package.json +2 -2
  41. package/setup/van.d.ts +1 -0
  42. package/setup/vanX.d.ts +1 -0
  43. package/setup/vanX.mjs +13 -1
  44. package/src/index.mjs +36 -1
  45. package/src/types.d.ts +29 -4
  46. package/tsconfig.json +14 -2
  47. package/jsx/index.d.ts +0 -16
  48. package/jsx/utils.mjs +0 -24
  49. /package/setup/{index.d.ts → types.d.ts} +0 -0
@@ -0,0 +1,60 @@
1
+ declare module "@vanjs/meta" {
2
+ import { type PropsWithKnownKeys } from "vanjs-core";
3
+ import type {
4
+ Element as VanElement,
5
+ TagFunc,
6
+ } from "mini-van-plate/van-plate";
7
+
8
+ export const createHeadTags: () => Map<
9
+ string,
10
+ SupportedTags | TagFunc
11
+ >;
12
+ export const getHeadTags: () => Map<
13
+ string,
14
+ SupportedTags | TagFunc
15
+ >;
16
+ export type ResetTags = () => void;
17
+ export type InitializeTags = () => void;
18
+
19
+ export type SupportedTags =
20
+ | HTMLTitleElement
21
+ | HTMLMetaElement
22
+ | HTMLScriptElement
23
+ | HTMLLinkElement
24
+ | HTMLStyleElement;
25
+
26
+ export type TagProps = PropsWithKnownKeys<SupportedTags>;
27
+
28
+ export type HeadTags = SupportedTags[] | TagFunc[];
29
+
30
+ export type AddMeta = (tag?: TagProps) => void;
31
+
32
+ // export declare const Head: () => () => TagFunc[];
33
+ export declare const Head: () => () => SupportedTags[];
34
+ export const Title: (
35
+ props: PropsWithKnownKeys<HTMLTitleElement>,
36
+ content?: string,
37
+ ) => null;
38
+ export const Meta: (props: PropsWithKnownKeys<HTMLMetaElement>) => null;
39
+ export const Style: (
40
+ props: PropsWithKnownKeys<HTMLStyleElement>,
41
+ content?: string,
42
+ ) => null;
43
+ export const Link: (props: PropsWithKnownKeys<HTMLLinkElement>) => null;
44
+ export const Script: (
45
+ props: PropsWithKnownKeys<HTMLScriptElement>,
46
+ content?: string,
47
+ ) => null;
48
+
49
+ export type ParseAttributes = (
50
+ attributeString: string,
51
+ ) => Record<string, string>;
52
+
53
+ export type GetTagAttribute = (tag: TagProps) => string;
54
+
55
+ export type GetTagKey = (tag: TagProps) => string;
56
+
57
+ export const initializeHeadTags: InitializeTags;
58
+ export const resetHeadTags: ResetTags;
59
+ export const addMeta: AddMeta;
60
+ }
@@ -0,0 +1,52 @@
1
+ import setup from "@vanjs/setup";
2
+
3
+ /** @type {import('./types.d.ts').ParseAttributes} */
4
+ export const parseAttributes = (attributeString) => {
5
+ /** @type {Record<string, string>} */
6
+ const attributes = {};
7
+ const attributeRegex = /([a-zA-Z0-9_-]+)(?:="([^"]*?)")?/g;
8
+ let match;
9
+
10
+ while ((match = attributeRegex.exec(attributeString)) !== null) {
11
+ const name = match[1];
12
+ const value = match[2] || /* istanbul ignore next */ "";
13
+ attributes[name] = value;
14
+ }
15
+
16
+ return attributes;
17
+ };
18
+
19
+ /** @type {typeof import('./types.d.ts').getTagAttribute} */
20
+ const getTagAttribute = (tag) => {
21
+ const attributes = [
22
+ "name",
23
+ "property",
24
+ "charset",
25
+ "viewport",
26
+ "media",
27
+ "http-equiv",
28
+ "rel",
29
+ "src",
30
+ "href",
31
+ "id",
32
+ ];
33
+
34
+ for (const attr of attributes) {
35
+ const value = setup.isServer ? tag[attr] : tag.getAttribute(attr);
36
+
37
+ if (value) return value;
38
+ }
39
+ return "";
40
+ };
41
+
42
+ /** @type {import('./types.d.ts').GetTagKey} */
43
+ export const getTagKey = (tag) => {
44
+ const normalizedTag = setup.isServer
45
+ ? { tagName: tag.name.toUpperCase(), ...parseAttributes(tag.propsStr) }
46
+ : tag;
47
+
48
+ return normalizedTag.tagName +
49
+ (normalizedTag.tagName !== "TITLE"
50
+ ? `.${getTagAttribute(normalizedTag)}`
51
+ : "");
52
+ };
package/meta/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./Head";
2
+ export * from "./tags";
3
+ export * from "./helpers";
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "meta",
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
+ },
17
+ "sideEffects": false
18
+ }
package/meta/tags.mjs ADDED
@@ -0,0 +1,57 @@
1
+ import van from "vanjs-core";
2
+ import { addMeta } from "./Head";
3
+
4
+ /** @typedef {import("vanjs-core").PropsWithKnownKeys} PropsWithKnownKeys */
5
+ /** @typedef {import("./types.d.ts").TagProps} TagProps */
6
+
7
+ /**
8
+ * Add a new title tag
9
+ * @type {(props: PropsWithKnownKeys<HTMLTitleElement>, content?: string) => null}
10
+ */
11
+ export const Title = (props, content) => {
12
+ const { title } = van.tags;
13
+ addMeta(title(props, content));
14
+ return null;
15
+ };
16
+
17
+ /**
18
+ * Add a new meta tag
19
+ * @type {(props: PropsWithKnownKeys<HTMLMetaElement>) => null}
20
+ */
21
+ export const Meta = (props) => {
22
+ const { meta } = van.tags;
23
+ addMeta(meta(props));
24
+ return null;
25
+ };
26
+
27
+ /**
28
+ * Add a new link tag
29
+ * @type {(props: PropsWithKnownKeys<HTMLLinkElement>) => null}
30
+ */
31
+ export const Link = (props) => {
32
+ const { link } = van.tags;
33
+ addMeta(link(props));
34
+ return null;
35
+ };
36
+
37
+ /**
38
+ * Add a new script tag
39
+ * @type {(props: PropsWithKnownKeys<HTMLScriptElement>, content?: string) => null}
40
+ */
41
+ export const Script = (props, content) => {
42
+ const { script } = van.tags;
43
+ // const realContent = content ? content.toString() : props;
44
+ // const realProps = content ? props : props;
45
+ addMeta(script(props, content));
46
+ return null;
47
+ };
48
+
49
+ /**
50
+ * Add a new style tag
51
+ * @type {(props: PropsWithKnownKeys<HTMLStyleElement>, content: string) => null}
52
+ */
53
+ export const Style = (props, content) => {
54
+ const { style } = van.tags;
55
+ addMeta(style(props, content));
56
+ return null;
57
+ };
@@ -0,0 +1,36 @@
1
+ /// <reference path="global.d.ts" />
2
+ import { type PropsWithKnownKeys } from "vanjs-core";
3
+ import { type TagFunc } from "mini-van-plate/van-plate";
4
+
5
+ export const createHeadTags: () => Map<
6
+ string,
7
+ SupportedTags | TagFunc<SupportedTags>
8
+ >;
9
+
10
+ export const getHeadTags = () =>
11
+ Map<string, SupportedTags | TagFunc<SupportedTags>>;
12
+ export const resetHeadTags: () => void;
13
+ export const initializeHeadTags: () => void;
14
+
15
+ export type SupportedTags =
16
+ | HTMLTitleElement
17
+ | HTMLMetaElement
18
+ | HTMLScriptElement
19
+ | HTMLLinkElement
20
+ | HTMLStyleElement;
21
+
22
+ export type TagProps = SupportedTags | PropsWithKnownKeys<SupportedTags>;
23
+
24
+ export type HeadTags = SupportedTags[] | TagFunc<SupportedTags>[];
25
+
26
+ export type AddMeta = (tag: string | TagProps) => null;
27
+
28
+ export declare const Head: () => HeadTags;
29
+
30
+ export type ParseAttributes = (
31
+ attributeString: string,
32
+ ) => Record<string, string>;
33
+
34
+ export const getTagAttribute: (tag: TagProps) => string;
35
+
36
+ export const getTagKey: (tag: TagProps) => string;
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "vite-plugin-vanjs",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "author": "thednp",
5
5
  "license": "MIT",
6
- "description": "A Vite plugin for VanJS to enable JSX transformation and simplify aplication development.",
6
+ "description": "A mini meta-framework for VanJS powered by Vite",
7
7
  "repository": "https://github.com/thednp/vite-plugin-vanjs",
8
8
  "type": "module",
9
9
  "sideEffects": false,
@@ -13,6 +13,10 @@
13
13
  "files": [
14
14
  "src",
15
15
  "setup",
16
+ "router",
17
+ "meta",
18
+ "client",
19
+ "server",
16
20
  "jsx",
17
21
  "tsconfig.json",
18
22
  "package.json",
@@ -25,6 +29,8 @@
25
29
  "vanjs",
26
30
  "vite",
27
31
  "plugin",
32
+ "router",
33
+ "meta",
28
34
  "ssr",
29
35
  "ssg",
30
36
  "jsx"
@@ -36,12 +42,27 @@
36
42
  "default": "./src/index.mjs"
37
43
  },
38
44
  "./setup": {
39
- "types": "./setup/index.d.ts",
40
- "import": "./setup/index.mjs",
41
- "require": "./setup/index.cjs"
45
+ "types": "./setup/types.d.ts",
46
+ "import": "./setup/index.mjs"
47
+ },
48
+ "./router": {
49
+ "types": "./router/types.d.ts",
50
+ "import": "./router/index.mjs"
51
+ },
52
+ "./meta": {
53
+ "types": "./meta/types.d.ts",
54
+ "import": "./meta/index.mjs"
55
+ },
56
+ "./server": {
57
+ "types": "./server/types.d.ts",
58
+ "import": "./server/index.mjs"
59
+ },
60
+ "./client": {
61
+ "types": "./client/types.d.ts",
62
+ "import": "./client/index.mjs"
42
63
  },
43
64
  "./jsx": {
44
- "types": "./jsx/index.d.ts",
65
+ "types": "./jsx/types.d.ts",
45
66
  "import": "./jsx/index.mjs"
46
67
  },
47
68
  "./jsx-runtime": {
@@ -61,20 +82,31 @@
61
82
  },
62
83
  "dependencies": {
63
84
  "csstype": "^3.1.3",
64
- "mini-van-plate": "^0.6.1",
65
- "vanjs-core": "^1.5.2",
85
+ "mini-van-plate": "^0.6.3",
86
+ "vanjs-core": "^1.5.3",
66
87
  "vanjs-ext": "^0.6.2"
67
88
  },
68
89
  "devDependencies": {
90
+ "@vitest/browser": "^3.0.4",
91
+ "@vitest/coverage-istanbul": "^3.0.4",
92
+ "@vitest/ui": "^3.0.4",
93
+ "happy-dom": "^16.7.3",
69
94
  "typescript": "5.6.2",
70
- "vite": "^6.0.5"
95
+ "vite": "^6.0.11",
96
+ "vitest": "^3.0.4"
97
+ },
98
+ "engines": {
99
+ "node": ">=20",
100
+ "pnpm": ">=8.6.0"
71
101
  },
72
102
  "scripts": {
73
- "badges": "npx -p dependency-version-badge update-badge vanjs-core mini-van-plate typescript vite",
74
- "format": "deno fmt src setup jsx",
103
+ "test": "vitest --config vitest.config.mts",
104
+ "test-ui": "vitest --config vitest.config.mts --ui=true",
105
+ "badges": "npx -p dependency-version-badge update-badge vanjs-core mini-van-plate typescript vitest vite",
106
+ "format": "deno fmt src meta router setup client server jsx",
75
107
  "lint": "pnpm lint:ts && pnpm check:ts",
76
- "lint:ts": "deno lint src",
77
- "fix:ts": "deno lint src --fix",
108
+ "lint:ts": "deno lint src meta router setup client server jsx",
109
+ "fix:ts": "deno lint src meta router setup client server jsx --fix",
78
110
  "check:ts": "tsc -noEmit"
79
111
  }
80
112
  }
package/router/a.mjs ADDED
@@ -0,0 +1,50 @@
1
+ // router/a.mjs
2
+ import van from "vanjs-core";
3
+ import setup from "../setup/index";
4
+ import { matchRoute } from "./routes";
5
+ import { executeLifecycle, isCurrentPage, navigate } from "./helpers";
6
+
7
+ /**
8
+ * @param {Partial<HTMLAnchorElement>} props
9
+ * @param {...(Element | Node)[]} children
10
+ * @returns {HTMLAnchorElement}
11
+ */
12
+ export const A = (props, ...children) => {
13
+ const { href, ...rest } = props;
14
+ const newProps = {
15
+ href,
16
+ ...rest,
17
+ };
18
+
19
+ van.derive(() => {
20
+ if (isCurrentPage(href)) {
21
+ newProps["aria-current"] = "page";
22
+ }
23
+ });
24
+
25
+ const anchor = van.tags.a(newProps, ...children);
26
+ /* istanbul ignore else */
27
+ if (!setup.isServer) {
28
+ anchor.addEventListener("click", async (e) => {
29
+ e.preventDefault();
30
+ /* istanbul ignore next */
31
+ if (isCurrentPage(href)) return;
32
+
33
+ const route = matchRoute(href);
34
+ const module = await route.component();
35
+ await executeLifecycle(module, route.params);
36
+
37
+ navigate(href);
38
+ });
39
+
40
+ anchor.addEventListener("mouseenter", () => {
41
+ const route = matchRoute(href);
42
+
43
+ /* istanbul ignore else */
44
+ if (route?.component) {
45
+ route.component();
46
+ }
47
+ });
48
+ }
49
+ return anchor;
50
+ };
@@ -0,0 +1,14 @@
1
+ /** @typedef {import("./types").ComponentModule} ComponentModule */
2
+ /** @typedef {import("./types").GetCachedRoute} GetCachedRoute */
3
+ /** @typedef {import("./types").CacheRoute} CacheRoute */
4
+
5
+ /** @type {Map<string, ComponentModule>} */
6
+ const routeCache = new Map();
7
+
8
+ /** @type {GetCachedRoute} */
9
+ export const getCached = (key) => routeCache.get(key);
10
+
11
+ /** @type {CacheRoute} */
12
+ export const cache = (key, value) => {
13
+ routeCache.set(key, value);
14
+ };
@@ -0,0 +1,162 @@
1
+ declare module "@vanjs/router" {
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: (
55
+ href: string,
56
+ options?: { replace?: boolean },
57
+ ) => void;
58
+
59
+ /**
60
+ * A client only helper function that reloads the current page.
61
+ */
62
+ export const reload: () => void;
63
+
64
+ /**
65
+ * A helper function that redirects the user to the specified href.
66
+ * When called in the server, it will return a function that will redirect the user
67
+ * to the specified href when called.
68
+ * @param {string | undefined} href the URL to redirect to
69
+ */
70
+ export const redirect: (href?: string) => void | (() => void);
71
+
72
+ export type VanComponent = () => VanNode | VanNode[];
73
+
74
+ // routes.mjs
75
+ export type RouteEntry = {
76
+ path: string;
77
+ component: Promise<ComponentModule>;
78
+ preload?: (params?: Record<string, string>) => void;
79
+ load?: (params?: Record<string, string>) => void;
80
+ };
81
+
82
+ export type RouteProps = {
83
+ path: string;
84
+ component: VanComponent | (() => ComponentModule);
85
+ preload?: (params?: Record<string, string>) => void;
86
+ load?: (params?: Record<string, string>) => void;
87
+ };
88
+ export const routes: RouteEntry[];
89
+
90
+ /**
91
+ * Registers a new route in the router state.
92
+ * @param route the route to register
93
+ *
94
+ * @example
95
+ * import { Route, lazy } from '@vanjs/router';
96
+ * import Home from './pages/Home';
97
+ * import NotFound from './pages/NotFound';
98
+ *
99
+ * Route({ path: '/', component: Home });
100
+ * Route({ path: '/about', component: lazy(() => import("./pages/About.ts")) });
101
+ * Route({ path: '*', component: NotFound });
102
+ */
103
+ export const Route: (route: RouteProps) => void;
104
+
105
+ // state.mjs
106
+ export type RouterState = {
107
+ pathname: string;
108
+ searchParams: URLSearchParams;
109
+ params: Record<string, string>;
110
+ };
111
+ /**
112
+ * A reactive object that holds the current router state.
113
+ * This state is maintained by both server and client.
114
+ */
115
+ export const routerState: {
116
+ pathname: van.state<RouterState.pathname>;
117
+ searchParams: van.state<RouterState.searchParams>;
118
+ params?: van.state<RouterState.params>;
119
+ };
120
+
121
+ /**
122
+ * Sets the router state to the specified href.
123
+ * @param href the URL to navigate to
124
+ * @param search the search string
125
+ * @param params the route params object
126
+ */
127
+ export const setRouterState: (
128
+ href: string,
129
+ search?: string,
130
+ params?: Record<string, string>,
131
+ ) => void;
132
+
133
+ /**
134
+ * Merge the children of an Element or an array of elements with an optional array of children
135
+ * into the childen of a single HTMLFragmentElement element.
136
+ * @param source
137
+ * @param {...VanNode[]} children
138
+ */
139
+ export const unwrap: (
140
+ source: VanNode | VanNode[] | (() => VanNode | VanNode[]),
141
+ ...children: VanNode[]
142
+ ) => VanNode;
143
+
144
+ export type ComponentModule = {
145
+ component: VanComponent;
146
+ route: Pick<RouteEntry, "load" | "preload">;
147
+ };
148
+
149
+ export type DynamicModule = {
150
+ Page: VanComponent;
151
+ default?: VanComponent;
152
+ route?: Pick<RouteEntry, "load" | "preload">;
153
+ };
154
+
155
+ export type LazyComponent = Promise<DynamicModule>;
156
+
157
+ /**
158
+ * Registers a lazy component.
159
+ * @param importFn
160
+ */
161
+ export const lazy: (importFn: () => LazyComponent) => () => ComponentModule;
162
+ }