@void/vue 0.26.0 → 0.27.0
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 +7 -5
- package/dist/index.mjs +1 -1
- package/dist/plugin.d.mts +7 -0
- package/dist/plugin.mjs +23 -29
- package/dist/runtime/index.mjs +1 -1
- package/dist/{runtime-DU7JTkNy.mjs → runtime-lPB1mgy1.mjs} +4 -58
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @void/vue
|
|
2
2
|
|
|
3
|
-
Build server-rendered
|
|
3
|
+
Vue adapter for [Void](https://void.cloud). Build server-rendered pages with typed server loaders, forms, layouts, and interactive islands.
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
For a new app, run `npx void init` and choose Vue. To add the adapter to an existing Void app:
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
10
|
npm install @void/vue
|
|
@@ -13,15 +13,17 @@ npm install @void/vue
|
|
|
13
13
|
Add the adapter to your Vite config. It includes the framework's Vite plugin:
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
+
import { voidVue } from '@void/vue/plugin';
|
|
16
17
|
import { defineConfig } from 'vite';
|
|
17
18
|
import { voidPlugin } from 'void';
|
|
18
|
-
import { voidVue } from '@void/vue/plugin';
|
|
19
19
|
|
|
20
20
|
export default defineConfig({
|
|
21
21
|
plugins: [voidPlugin(), voidVue()],
|
|
22
22
|
});
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
## Documentation
|
|
26
|
+
|
|
27
|
+
Follow [Pages Routing](https://void.cloud/guide/pages-routing/overview) to add pages, then use [loaders](https://void.cloud/guide/pages-routing/loaders), [forms](https://void.cloud/guide/pages-routing/actions-and-forms), and [layouts](https://void.cloud/guide/pages-routing/layouts). See the [adapter API reference](https://void.cloud/reference/api/pages) for plugin options and runtime helpers.
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
Read the [Void documentation](https://void.cloud) online or use the Markdown guides and references in `node_modules/void/docs/`, included with the `void` package.
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as useForm, c as useRouter, i as useNavigation, l as Link, n as setActionRouter, o as useShared, r as useIslandForm, s as useParams, t as action, u as Form } from "./runtime-
|
|
1
|
+
import { a as useForm, c as useRouter, i as useNavigation, l as Link, n as setActionRouter, o as useShared, r as useIslandForm, s as useParams, t as action, u as Form } from "./runtime-lPB1mgy1.mjs";
|
|
2
2
|
export { Form, Link, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
|
package/dist/plugin.d.mts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import vue from "@vitejs/plugin-vue";
|
|
2
2
|
import { Plugin } from "vite";
|
|
3
|
+
//#region src/plugin-pages.d.ts
|
|
4
|
+
type PrefetchConfig = {
|
|
5
|
+
hoverDelay?: number;
|
|
6
|
+
cacheFor?: number | string | [string, string];
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
3
9
|
//#region src/plugin.d.ts
|
|
4
10
|
export type VoidVueOptions = Readonly<{
|
|
5
11
|
vue?: Parameters<typeof vue>[0];
|
|
6
12
|
viewTransitions?: boolean;
|
|
13
|
+
prefetch?: PrefetchConfig;
|
|
7
14
|
}>;
|
|
8
15
|
export declare function voidVue(options?: VoidVueOptions): Array<Plugin>;
|
|
9
16
|
//#endregion
|
package/dist/plugin.mjs
CHANGED
|
@@ -74,9 +74,23 @@ function islandsPlugin(pagesDir, options) {
|
|
|
74
74
|
let isDev = false;
|
|
75
75
|
let viteRoot = "";
|
|
76
76
|
let resolvedConfig = null;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
/** Resolve an island import and record it in the client manifest. */
|
|
78
|
+
function registerIsland(spec, importerDir, hydrate) {
|
|
79
|
+
const absPath = resolveSpecifier(spec, importerDir, COMPONENT_EXTENSIONS);
|
|
80
|
+
if (!absPath) return {
|
|
81
|
+
absPath,
|
|
82
|
+
islandId: spec
|
|
83
|
+
};
|
|
84
|
+
const islandId = normalizePath(relative(root, absPath)).replace(/\.[^.]+$/, "");
|
|
85
|
+
islandManifest.set(islandId, {
|
|
86
|
+
componentPath: absPath,
|
|
87
|
+
islandId,
|
|
88
|
+
hydrate
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
absPath,
|
|
92
|
+
islandId
|
|
93
|
+
};
|
|
80
94
|
}
|
|
81
95
|
return [{
|
|
82
96
|
name: "void-vue:islands",
|
|
@@ -113,19 +127,7 @@ function islandsPlugin(pagesDir, options) {
|
|
|
113
127
|
const filePath = resolve(pagesDir, entry.filePath);
|
|
114
128
|
const code = readFileSync(filePath, "utf-8");
|
|
115
129
|
const importerDir = dirname(filePath);
|
|
116
|
-
for (const islandImport of findIslandImports(code, filePath))
|
|
117
|
-
const spec = islandImport.specifier;
|
|
118
|
-
const strategy = islandImport.hydrate;
|
|
119
|
-
const absPath = resolveSpecifier(spec, importerDir, COMPONENT_EXTENSIONS);
|
|
120
|
-
if (absPath) {
|
|
121
|
-
const islandId = normalizePath(relative(root, absPath)).replace(/\.[^.]+$/, "");
|
|
122
|
-
islandManifest.set(islandId, {
|
|
123
|
-
componentPath: absPath,
|
|
124
|
-
islandId,
|
|
125
|
-
hydrate: strategy
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
130
|
+
for (const islandImport of findIslandImports(code, filePath)) registerIsland(islandImport.specifier, importerDir, islandImport.hydrate);
|
|
129
131
|
}
|
|
130
132
|
for (const page of pageScan.pages) {
|
|
131
133
|
if (!page.island) continue;
|
|
@@ -156,7 +158,7 @@ function islandsPlugin(pagesDir, options) {
|
|
|
156
158
|
if (!pageScan) return "export function renderIslandPage() { throw new Error('No pages found'); }";
|
|
157
159
|
const mdPlugin = resolvedConfig?.plugins?.find((plugin) => plugin.name === "void-md");
|
|
158
160
|
const mdScriptIds = new Set(mdPlugin?.api?.getClientScripts?.()?.keys() ?? []);
|
|
159
|
-
const needsJS = computePagesNeedingClientJS
|
|
161
|
+
const needsJS = computePagesNeedingClientJS(pageScan, pagesDir, resolvedConfig);
|
|
160
162
|
return generateIslandRenderer(pageScan, pagesDir, mdScriptIds, needsJS);
|
|
161
163
|
}
|
|
162
164
|
if (id === "\0" + ISLANDS_CLIENT_ENTRY_ID) {
|
|
@@ -183,16 +185,7 @@ function islandsPlugin(pagesDir, options) {
|
|
|
183
185
|
const strategy = islandImport.hydrate;
|
|
184
186
|
const spec = islandImport.specifier;
|
|
185
187
|
const rawName = `_raw_island_${idx++}`;
|
|
186
|
-
const
|
|
187
|
-
if (absPath) {
|
|
188
|
-
const islandId = normalizePath(relative(root, absPath)).replace(/\.[^.]+$/, "");
|
|
189
|
-
islandManifest.set(islandId, {
|
|
190
|
-
componentPath: absPath,
|
|
191
|
-
islandId,
|
|
192
|
-
hydrate: strategy
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
const islandId = absPath ? normalizePath(relative(root, absPath)).replace(/\.[^.]+$/, "") : spec;
|
|
188
|
+
const { islandId } = registerIsland(spec, importerDir, strategy);
|
|
196
189
|
const replacement = `import ${rawName} from ${specRaw}`;
|
|
197
190
|
edits.push({
|
|
198
191
|
start: islandImport.start,
|
|
@@ -618,7 +611,7 @@ currentLayouts.value = initialLayouts;
|
|
|
618
611
|
|
|
619
612
|
const appEl = document.getElementById("app");
|
|
620
613
|
if (!appEl) throw new Error("pages: Missing #app element for Void Vue pages hydration.");
|
|
621
|
-
const createVoidApp = appEl
|
|
614
|
+
const createVoidApp = appEl.getAttribute("data-void-ssr") === "false" ? createApp : createSSRApp;
|
|
622
615
|
const app = createVoidApp({
|
|
623
616
|
setup() {
|
|
624
617
|
provide("__void_shared", shared);
|
|
@@ -656,7 +649,8 @@ function voidVue(options) {
|
|
|
656
649
|
vue(options?.vue),
|
|
657
650
|
...pagesPlugin(pagesDir, {
|
|
658
651
|
root,
|
|
659
|
-
viewTransitions: options?.viewTransitions
|
|
652
|
+
viewTransitions: options?.viewTransitions,
|
|
653
|
+
prefetch: options?.prefetch
|
|
660
654
|
}),
|
|
661
655
|
...islandsPlugin(pagesDir, { root })
|
|
662
656
|
];
|
package/dist/runtime/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as useForm, c as useRouter, i as useNavigation, l as Link, n as setActionRouter, o as useShared, r as useIslandForm, s as useParams, t as action, u as Form } from "../runtime-
|
|
1
|
+
import { a as useForm, c as useRouter, i as useNavigation, l as Link, n as setActionRouter, o as useShared, r as useIslandForm, s as useParams, t as action, u as Form } from "../runtime-lPB1mgy1.mjs";
|
|
2
2
|
export { Form, Link, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VoidActionError, categorizeActionError, createActionClient, formErrorMessage, formRetryMessage, formSubmissionBlocked, idleNavigationState, isAbortError, isEqualFormValue, scheduleFormRetry, ssrProxy, submitAction } from "void/pages-client";
|
|
1
|
+
import { VoidActionError, categorizeActionError, createActionClient, formErrorMessage, formRetryMessage, formSubmissionBlocked, getValidationErrors, idleNavigationState, interpolateRouteParams, isAbortError, isEqualFormValue, isModifiedEvent, mergeDataIntoHref, scheduleFormRetry, ssrProxy, submitAction } from "void/pages-client";
|
|
2
2
|
import { computed, defineComponent, h, inject, onMounted, onUnmounted, reactive, ref, watch } from "vue";
|
|
3
3
|
//#region src/runtime/form.ts
|
|
4
4
|
const Form = defineComponent({
|
|
@@ -44,45 +44,9 @@ const Form = defineComponent({
|
|
|
44
44
|
});
|
|
45
45
|
//#endregion
|
|
46
46
|
//#region src/runtime/link.ts
|
|
47
|
-
function appendQueryValue(params, key, value) {
|
|
48
|
-
if (value === null || value === void 0) return false;
|
|
49
|
-
if (value instanceof Date) {
|
|
50
|
-
params.append(key, value.toISOString());
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
if (Array.isArray(value)) {
|
|
54
|
-
let appended = false;
|
|
55
|
-
for (const item of value) appended = appendQueryValue(params, key, item) || appended;
|
|
56
|
-
return appended;
|
|
57
|
-
}
|
|
58
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
59
|
-
params.append(key, String(value));
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
throw new Error(`Link: GET data only supports primitive values and arrays. Remove nested data for '${key}'.`);
|
|
63
|
-
}
|
|
64
|
-
function mergeDataIntoHref(href, data) {
|
|
65
|
-
if (!data) return href;
|
|
66
|
-
const hashIndex = href.indexOf("#");
|
|
67
|
-
const beforeHash = hashIndex === -1 ? href : href.slice(0, hashIndex);
|
|
68
|
-
const hash = hashIndex === -1 ? "" : href.slice(hashIndex);
|
|
69
|
-
const searchIndex = beforeHash.indexOf("?");
|
|
70
|
-
const path = searchIndex === -1 ? beforeHash : beforeHash.slice(0, searchIndex);
|
|
71
|
-
const search = searchIndex === -1 ? "" : beforeHash.slice(searchIndex + 1);
|
|
72
|
-
const params = new URLSearchParams(search);
|
|
73
|
-
let appended = false;
|
|
74
|
-
for (const [key, value] of Object.entries(data)) appended = appendQueryValue(params, key, value) || appended;
|
|
75
|
-
if (!appended) return href;
|
|
76
|
-
const query = params.toString();
|
|
77
|
-
return `${path}${query ? `?${query}` : ""}${hash}`;
|
|
78
|
-
}
|
|
79
47
|
function hasPrefetch(prefetch) {
|
|
80
48
|
return prefetch !== false;
|
|
81
49
|
}
|
|
82
|
-
function isModifiedEvent(e) {
|
|
83
|
-
const target = e.currentTarget.getAttribute("target");
|
|
84
|
-
return target !== null && target !== "_self" || e.ctrlKey || e.metaKey || e.shiftKey || e.altKey || e.button !== 0;
|
|
85
|
-
}
|
|
86
50
|
function callHandler(handler, event) {
|
|
87
51
|
if (Array.isArray(handler)) {
|
|
88
52
|
for (const fn of handler) if (typeof fn === "function") fn(event);
|
|
@@ -280,22 +244,8 @@ function useShared() {
|
|
|
280
244
|
}
|
|
281
245
|
//#endregion
|
|
282
246
|
//#region src/runtime/use-form.ts
|
|
283
|
-
function getValidationErrors$1(error) {
|
|
284
|
-
const body = error.body;
|
|
285
|
-
if (body && typeof body === "object" && "errors" in body && body.errors && typeof body.errors === "object" && !Array.isArray(body.errors)) return body.errors;
|
|
286
|
-
return null;
|
|
287
|
-
}
|
|
288
247
|
function useForm(url, defaults, options) {
|
|
289
|
-
let resolvedUrl = url;
|
|
290
248
|
const formDefaults = defaults;
|
|
291
|
-
let actionQuery = "";
|
|
292
|
-
const qIdx = resolvedUrl.indexOf("?");
|
|
293
|
-
if (qIdx !== -1) {
|
|
294
|
-
actionQuery = resolvedUrl.slice(qIdx);
|
|
295
|
-
resolvedUrl = resolvedUrl.slice(0, qIdx);
|
|
296
|
-
}
|
|
297
|
-
if (options?.params) for (const [key, value] of Object.entries(options.params)) resolvedUrl = resolvedUrl.replace(`:${key}`, encodeURIComponent(value));
|
|
298
|
-
resolvedUrl = resolvedUrl + actionQuery;
|
|
299
249
|
const router = inject("__void_router", null);
|
|
300
250
|
const data = reactive({ ...formDefaults });
|
|
301
251
|
const errors = reactive({});
|
|
@@ -329,13 +279,13 @@ function useForm(url, defaults, options) {
|
|
|
329
279
|
clearError();
|
|
330
280
|
try {
|
|
331
281
|
if (!router) throw new Error("useForm(): requires the Void Router.");
|
|
332
|
-
const result = await submitAction(router,
|
|
282
|
+
const result = await submitAction(router, interpolateRouteParams(url, options?.params), {
|
|
333
283
|
method,
|
|
334
284
|
data: { ...data },
|
|
335
285
|
...opts
|
|
336
286
|
});
|
|
337
287
|
if (!result.ok) {
|
|
338
|
-
const validationErrors = getValidationErrors
|
|
288
|
+
const validationErrors = getValidationErrors(result.error.body);
|
|
339
289
|
if (validationErrors) Object.assign(errors, validationErrors);
|
|
340
290
|
else error.value = result.error;
|
|
341
291
|
return;
|
|
@@ -377,10 +327,6 @@ function useNavigation() {
|
|
|
377
327
|
}
|
|
378
328
|
//#endregion
|
|
379
329
|
//#region src/runtime/use-island-form.ts
|
|
380
|
-
function getValidationErrors(body) {
|
|
381
|
-
if (body && typeof body === "object" && "errors" in body && body.errors && typeof body.errors === "object" && !Array.isArray(body.errors)) return body.errors;
|
|
382
|
-
return null;
|
|
383
|
-
}
|
|
384
330
|
async function readActionErrorBody(response) {
|
|
385
331
|
const contentType = response.headers.get("content-type") || "";
|
|
386
332
|
try {
|
|
@@ -443,7 +389,7 @@ function useIslandForm(defaults) {
|
|
|
443
389
|
recentlySuccessful.value = false;
|
|
444
390
|
}, 2e3);
|
|
445
391
|
window.location.reload();
|
|
446
|
-
} else
|
|
392
|
+
} else {
|
|
447
393
|
const body = await readActionErrorBody(response);
|
|
448
394
|
const actionError = new VoidActionError({
|
|
449
395
|
body,
|
package/package.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@void/vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
|
+
"description": "Vue pages, server rendering, forms, and navigation for Void.",
|
|
5
|
+
"homepage": "https://void.cloud",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/voidzero-dev/void/issues"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
4
10
|
"repository": {
|
|
5
11
|
"type": "git",
|
|
6
12
|
"url": "git+https://github.com/voidzero-dev/void.git",
|
|
@@ -33,14 +39,14 @@
|
|
|
33
39
|
"devDependencies": {
|
|
34
40
|
"@types/node": "^26.6.4",
|
|
35
41
|
"pathslash": "^0.1.0",
|
|
36
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@1.
|
|
37
|
-
"vite-plus": "1.
|
|
38
|
-
"void": "0.
|
|
42
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.1.0",
|
|
43
|
+
"vite-plus": "1.1.0",
|
|
44
|
+
"void": "0.27.0",
|
|
39
45
|
"vue": "^3.5.43"
|
|
40
46
|
},
|
|
41
47
|
"peerDependencies": {
|
|
42
48
|
"vite": "^8.0.0",
|
|
43
|
-
"void": "0.
|
|
49
|
+
"void": "0.27.0",
|
|
44
50
|
"vue": "^3.5.0"
|
|
45
51
|
},
|
|
46
52
|
"scripts": {
|