feature: vor und nachteile

This commit is contained in:
Hikyu
2026-05-31 13:54:31 +02:00
parent 552a947a1c
commit e3dad17446
23270 changed files with 3024794 additions and 200 deletions
+133
View File
@@ -0,0 +1,133 @@
'use strict';
const json = require('klona/json');
function apply(obj, diff) {
if (typeof obj !== typeof diff)
return diff;
if (typeof diff === "object") {
if (Array.isArray(diff))
return diff;
let out;
if (Array.isArray(obj)) {
out = obj;
for (const i in diff)
out[i] = apply(obj[i], diff[i]);
} else {
out = obj;
for (const i in diff)
out[i] = apply(obj[i], diff[i]);
}
return out;
}
return diff;
}
function diff(obj, old) {
if (typeof obj === "object") {
const isArray = Array.isArray(obj);
if (!old || typeof old !== "object" || isArray !== Array.isArray(old))
return obj;
if (isArray) {
let out2;
let i = 0;
const max = Math.min(obj.length, old.length);
for (; i < max; i++) {
const differs = different(obj[i], old[i]);
if (differs)
break;
}
const useArray = old.length === 0;
const offset = obj.length - old.length;
for (let j = obj.length; j-- > i; ) {
const oldJ = j - offset;
if (oldJ >= 0) {
const differs = different(obj[j], old[oldJ]);
if (differs) {
if (!out2)
out2 = useArray ? [] : {};
out2[j] = diff(obj[j], old[oldJ]);
}
} else {
if (!out2)
out2 = useArray ? [] : {};
out2[j] = obj[j];
}
}
return out2;
}
let out;
for (const key in obj) {
if (!(key in old) || obj[key] !== old[key]) {
if (!out)
out = {};
const r = diff(obj[key], old[key]);
if (r !== void 0)
out[key] = r;
}
}
for (const key in old) {
if (obj == null || !(key in obj)) {
if (!out)
out = {};
out[key] = void 0;
}
}
return out;
} else if (obj !== old) {
return obj;
}
}
function different(obj, old) {
for (const key in obj) {
if (old == null || !(key in old) || obj[key] !== old[key])
return true;
}
for (const key in old) {
if (obj == null || !(key in obj))
return true;
}
return false;
}
const UNDEFINED = "__UNDEFINED___";
function stringify(data) {
return JSON.stringify(data, (key, value) => value === void 0 ? UNDEFINED : value);
}
function parse(json) {
return JSON.parse(json, (key, value) => value === UNDEFINED ? void 0 : value);
}
function randId() {
return Math.random().toString(36).replace(/[^a-z]+/g, "").substr(2, 10);
}
function isObject(obj) {
return typeof obj === "object" && obj !== null;
}
function reactiveSet(target, value) {
for (const key of Object.keys(value)) {
if (target[key] !== value[key])
target[key] = value[key];
}
const originalKeys = new Set(Object.keys(target));
Object.keys(value).forEach((i) => originalKeys.delete(i));
for (const key of originalKeys)
delete target[key];
}
function define(target, key, value) {
Object.defineProperty(target, key, {
value,
writable: true,
enumerable: false
});
}
exports.clone = json.klona;
exports.UNDEFINED = UNDEFINED;
exports.apply = apply;
exports.define = define;
exports.diff = diff;
exports.isObject = isObject;
exports.parse = parse;
exports.randId = randId;
exports.reactiveSet = reactiveSet;
exports.stringify = stringify;
@@ -0,0 +1,23 @@
export { klona as clone } from 'klona/json';
/**
* Use this to apply diffs on the main thread.
* newObject = apply(oldObject, patch);
*/
declare function apply(obj: any, diff: any): any;
/**
* Use this to create a "patch" object in the worker thread.
* patch = diff(newObject, oldObject);
*/
declare function diff(obj: any, old: any): any;
declare const UNDEFINED = "__UNDEFINED___";
declare function stringify(data: any): string;
declare function parse(json: string): any;
declare function randId(): string;
declare function isObject(obj: any): boolean;
declare function reactiveSet(target: any, value: any): void;
declare function define(target: any, key: string, value: any): void;
export { UNDEFINED, apply, define, diff, isObject, parse, randId, reactiveSet, stringify };
@@ -0,0 +1,23 @@
export { klona as clone } from 'klona/json';
/**
* Use this to apply diffs on the main thread.
* newObject = apply(oldObject, patch);
*/
declare function apply(obj: any, diff: any): any;
/**
* Use this to create a "patch" object in the worker thread.
* patch = diff(newObject, oldObject);
*/
declare function diff(obj: any, old: any): any;
declare const UNDEFINED = "__UNDEFINED___";
declare function stringify(data: any): string;
declare function parse(json: string): any;
declare function randId(): string;
declare function isObject(obj: any): boolean;
declare function reactiveSet(target: any, value: any): void;
declare function define(target: any, key: string, value: any): void;
export { UNDEFINED, apply, define, diff, isObject, parse, randId, reactiveSet, stringify };
+23
View File
@@ -0,0 +1,23 @@
export { klona as clone } from 'klona/json';
/**
* Use this to apply diffs on the main thread.
* newObject = apply(oldObject, patch);
*/
declare function apply(obj: any, diff: any): any;
/**
* Use this to create a "patch" object in the worker thread.
* patch = diff(newObject, oldObject);
*/
declare function diff(obj: any, old: any): any;
declare const UNDEFINED = "__UNDEFINED___";
declare function stringify(data: any): string;
declare function parse(json: string): any;
declare function randId(): string;
declare function isObject(obj: any): boolean;
declare function reactiveSet(target: any, value: any): void;
declare function define(target: any, key: string, value: any): void;
export { UNDEFINED, apply, define, diff, isObject, parse, randId, reactiveSet, stringify };
+122
View File
@@ -0,0 +1,122 @@
export { klona as clone } from 'klona/json';
function apply(obj, diff) {
if (typeof obj !== typeof diff)
return diff;
if (typeof diff === "object") {
if (Array.isArray(diff))
return diff;
let out;
if (Array.isArray(obj)) {
out = obj;
for (const i in diff)
out[i] = apply(obj[i], diff[i]);
} else {
out = obj;
for (const i in diff)
out[i] = apply(obj[i], diff[i]);
}
return out;
}
return diff;
}
function diff(obj, old) {
if (typeof obj === "object") {
const isArray = Array.isArray(obj);
if (!old || typeof old !== "object" || isArray !== Array.isArray(old))
return obj;
if (isArray) {
let out2;
let i = 0;
const max = Math.min(obj.length, old.length);
for (; i < max; i++) {
const differs = different(obj[i], old[i]);
if (differs)
break;
}
const useArray = old.length === 0;
const offset = obj.length - old.length;
for (let j = obj.length; j-- > i; ) {
const oldJ = j - offset;
if (oldJ >= 0) {
const differs = different(obj[j], old[oldJ]);
if (differs) {
if (!out2)
out2 = useArray ? [] : {};
out2[j] = diff(obj[j], old[oldJ]);
}
} else {
if (!out2)
out2 = useArray ? [] : {};
out2[j] = obj[j];
}
}
return out2;
}
let out;
for (const key in obj) {
if (!(key in old) || obj[key] !== old[key]) {
if (!out)
out = {};
const r = diff(obj[key], old[key]);
if (r !== void 0)
out[key] = r;
}
}
for (const key in old) {
if (obj == null || !(key in obj)) {
if (!out)
out = {};
out[key] = void 0;
}
}
return out;
} else if (obj !== old) {
return obj;
}
}
function different(obj, old) {
for (const key in obj) {
if (old == null || !(key in old) || obj[key] !== old[key])
return true;
}
for (const key in old) {
if (obj == null || !(key in obj))
return true;
}
return false;
}
const UNDEFINED = "__UNDEFINED___";
function stringify(data) {
return JSON.stringify(data, (key, value) => value === void 0 ? UNDEFINED : value);
}
function parse(json) {
return JSON.parse(json, (key, value) => value === UNDEFINED ? void 0 : value);
}
function randId() {
return Math.random().toString(36).replace(/[^a-z]+/g, "").substr(2, 10);
}
function isObject(obj) {
return typeof obj === "object" && obj !== null;
}
function reactiveSet(target, value) {
for (const key of Object.keys(value)) {
if (target[key] !== value[key])
target[key] = value[key];
}
const originalKeys = new Set(Object.keys(target));
Object.keys(value).forEach((i) => originalKeys.delete(i));
for (const key of originalKeys)
delete target[key];
}
function define(target, key, value) {
Object.defineProperty(target, key, {
value,
writable: true,
enumerable: false
});
}
export { UNDEFINED, apply, define, diff, isObject, parse, randId, reactiveSet, stringify };
+242
View File
@@ -0,0 +1,242 @@
'use strict';
const mlly = require('mlly');
const utils = require('@antfu/utils');
const ufo = require('ufo');
const client = require('./client.cjs');
require('klona/json');
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
const URL_PREFIX = ["/@server-ref/", "/@server-reactive/"];
const VIRTUAL_PREFIX = ["server-ref:", "server-reactive:"];
const WS_EVENT = "vue-server-ref";
const PREFIXES = [...URL_PREFIX, ...VIRTUAL_PREFIX];
function getBodyJson(req) {
return new Promise((resolve, reject) => {
let body = "";
req.on("data", (chunk) => body += chunk);
req.on("error", reject);
req.on("end", () => {
try {
resolve(client.parse(body) || {});
} catch (e) {
reject(e);
}
});
});
}
function get(obj, key) {
return key.split(".").reduce((acc, key2) => acc?.[key2], obj);
}
function set(obj, key, value) {
const keys = key.split(".");
let acc = obj;
keys.slice(0, -1).forEach((key2) => {
if (!acc[key2])
acc[key2] = {};
acc = acc[key2];
});
acc[keys[keys.length - 1]] = value;
}
function parseId(id) {
for (const pre of PREFIXES) {
if (id.startsWith(pre)) {
const { pathname: key, search } = ufo.parseURL(id.substr(pre.length));
const query = ufo.parseQuery(search);
return {
key: key.replace(/\//g, "."),
type: pre.includes("ref") ? "ref" : "reactive",
prefix: pre,
diff: "diff" in query
};
}
}
}
function genCode(options, id, clientUrl = "vite-plugin-vue-server-ref/client") {
const { state, defaultValue, clientVue, debug, debounce } = options;
const { key, type, prefix, diff } = id;
const access = type === "ref" ? "data.value" : "data";
return `
import { ${type}, watch } from "${clientVue}"
import { randId, stringify, parse, define, apply,${type === "reactive" ? " reactiveSet," : ""}${diff ? " clone, diff" : ""} } from ${JSON.stringify(clientUrl)}
const data = ${type}(${JSON.stringify(get(state, key) ?? defaultValue(key))})
let onSet = []
let onPatch = []
define(data, '$syncUp', true)
define(data, '$syncDown', true)
define(data, '$paused', false)
define(data, '$onSet', fn => onSet.push(fn))
define(data, '$onPatch', fn => onPatch.push(fn))
const id = randId()
if (import.meta.hot) {
let skipWatch = false
let timer = null
${diff ? "let copy = null" : ""}
function post(payload) {
${debug ? `console.log("[server-ref] [${key}] outgoing", payload)` : ""}
return fetch('${prefix + key}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: stringify(payload)
})
}
${diff ? `
function makeClone() {
copy = clone(${access})
}
function getDiff() {
return diff(${access}, copy)
}
` : ""}
function applyPatch(patch, trigger = true) {
skipWatch = true
if (trigger) {
onPatch.forEach(fn => fn(patch))
${debug ? `console.log("[server-ref] [${key}] patch incoming", patch)` : ""}
}
apply(${access}, patch)
${diff ? "makeClone()" : ""}
skipWatch = false
}
function applySet(newData) {
skipWatch = true
onSet.forEach(fn => fn(newData))
${type === "ref" ? "data.value = newData" : "reactiveSet(data, newData)"}
${debug ? `console.log("[server-ref] [${key}] incoming", newData)` : ""}
${diff ? "makeClone()" : ""}
skipWatch = false
}
${debug ? `console.log("[server-ref] [${key}] ref", data)` : ""}
${debug ? `console.log("[server-ref] [${key}] initial", ${access})` : ""}
import.meta.hot.on("${WS_EVENT}", (payload) => {
if (!data.$syncDown || data.$paused || payload.key !== "${key}" || payload.source === id)
return
if (payload.patch)
applyPatch(payload.patch)
else
applySet(payload.data)
})
define(data, '$patch', async (patch) => {
if (!data.$syncUp || data.$paused)
return false
applyPatch(patch, false)
return post({
source: id,
patch,
timestamp: Date.now(),
})
})
watch(data, (v) => {
if (timer)
clearTimeout(timer)
if (!data.$syncUp || data.$paused || skipWatch)
return
timer = setTimeout(()=>{
post({
source: id,
${diff ? "patch: getDiff()" : `data: ${access}`},
timestamp: Date.now(),
})
}, ${debounce})
}, { flush: 'sync', deep: true })
}
else {
define(data, '$patch', async () => false)
}
export default data
`.replace(/\n\s*\n/gm, "\n");
}
const defaultOptions = {
state: {},
debounce: 10,
debug: false,
defaultValue: () => void 0,
clientVue: "vue",
onChanged: () => {
}
};
function resolveOptions(options) {
return Object.assign({}, defaultOptions, options);
}
function VitePluginServerRef(options = {}) {
const resolved = resolveOptions(options);
const { state } = resolved;
const idMaps = {};
return {
name: "vite-plugin-vue-server-ref",
resolveId(id) {
const idx = VIRTUAL_PREFIX.findIndex((pre) => id.startsWith(pre));
if (idx > -1)
return URL_PREFIX[idx] + id.slice(VIRTUAL_PREFIX[idx].length);
return URL_PREFIX.some((pre) => id.startsWith(pre)) ? id : null;
},
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
if (!req.url || req.method !== "POST")
return next();
const id = parseId(req.url);
if (!id)
return next();
const key = id.key;
const payload = await getBodyJson(req);
for (const id2 of idMaps[key] || []) {
const module = server.moduleGraph.getModuleById(id2);
if (module)
server.moduleGraph.invalidateModule(module);
}
if (payload.patch)
set(state, key, client.apply(get(state, key), payload.patch));
else
set(state, key, payload.data);
server.ws.send({
type: "custom",
event: WS_EVENT,
data: { ...payload, key }
});
options.onChanged?.(key, get(state, key), payload.patch, payload.timestamp);
res.write("");
res.end();
});
},
async load(id) {
const res = parseId(id);
if (!res)
return;
if (!idMaps[res.key])
idMaps[res.key] = /* @__PURE__ */ new Set();
idMaps[res.key].add(id);
return genCode(
resolved,
res,
toAtFS(await mlly.resolvePath("vite-plugin-vue-server-ref/client", { url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }))
);
}
};
}
function toAtFS(path) {
return `/@fs${utils.ensurePrefix("/", utils.slash(path))}`;
}
module.exports = VitePluginServerRef;
+45
View File
@@ -0,0 +1,45 @@
import { Plugin } from 'vite';
import { Ref } from 'vue';
interface ServerRefOptions<T extends Record<string, unknown>> {
state?: T;
/**
* Milliseconds to debounce the server ref updates.
*
* @default 10
*/
debounce?: number;
/**
* Default value for the client when the data is not presented.
*
* @default () => undefined
*/
defaultValue?: (key: string) => unknown;
/**
* Log info on the client
*/
debug?: boolean;
/**
* The vue entry name for the generated client code.
*
* @default 'vue'
*/
clientVue?: string;
/**
* Callback on server data change
*/
onChanged?: <K extends keyof T>(name: K, data: T[K], patch: Partial<T[K]> | undefined, timestamp: number) => void;
}
interface ServerRefExtend<T> {
$syncDown: boolean;
$syncUp: boolean;
$onChange(fn: (data: T) => void): void;
$onPatch(fn: (patch: Partial<T>) => void): void;
$patch(patch: Partial<T>): Promise<boolean>;
}
type ServerRef<T> = Ref<T> & ServerRefExtend<T>;
type ServerReactive<T> = T & ServerRefExtend<T>;
declare function VitePluginServerRef(options?: ServerRefOptions<any>): Plugin;
export { type ServerReactive, type ServerRef, type ServerRefExtend, type ServerRefOptions, VitePluginServerRef as default };
+45
View File
@@ -0,0 +1,45 @@
import { Plugin } from 'vite';
import { Ref } from 'vue';
interface ServerRefOptions<T extends Record<string, unknown>> {
state?: T;
/**
* Milliseconds to debounce the server ref updates.
*
* @default 10
*/
debounce?: number;
/**
* Default value for the client when the data is not presented.
*
* @default () => undefined
*/
defaultValue?: (key: string) => unknown;
/**
* Log info on the client
*/
debug?: boolean;
/**
* The vue entry name for the generated client code.
*
* @default 'vue'
*/
clientVue?: string;
/**
* Callback on server data change
*/
onChanged?: <K extends keyof T>(name: K, data: T[K], patch: Partial<T[K]> | undefined, timestamp: number) => void;
}
interface ServerRefExtend<T> {
$syncDown: boolean;
$syncUp: boolean;
$onChange(fn: (data: T) => void): void;
$onPatch(fn: (patch: Partial<T>) => void): void;
$patch(patch: Partial<T>): Promise<boolean>;
}
type ServerRef<T> = Ref<T> & ServerRefExtend<T>;
type ServerReactive<T> = T & ServerRefExtend<T>;
declare function VitePluginServerRef(options?: ServerRefOptions<any>): Plugin;
export { type ServerReactive, type ServerRef, type ServerRefExtend, type ServerRefOptions, VitePluginServerRef as default };
+45
View File
@@ -0,0 +1,45 @@
import { Plugin } from 'vite';
import { Ref } from 'vue';
interface ServerRefOptions<T extends Record<string, unknown>> {
state?: T;
/**
* Milliseconds to debounce the server ref updates.
*
* @default 10
*/
debounce?: number;
/**
* Default value for the client when the data is not presented.
*
* @default () => undefined
*/
defaultValue?: (key: string) => unknown;
/**
* Log info on the client
*/
debug?: boolean;
/**
* The vue entry name for the generated client code.
*
* @default 'vue'
*/
clientVue?: string;
/**
* Callback on server data change
*/
onChanged?: <K extends keyof T>(name: K, data: T[K], patch: Partial<T[K]> | undefined, timestamp: number) => void;
}
interface ServerRefExtend<T> {
$syncDown: boolean;
$syncUp: boolean;
$onChange(fn: (data: T) => void): void;
$onPatch(fn: (patch: Partial<T>) => void): void;
$patch(patch: Partial<T>): Promise<boolean>;
}
type ServerRef<T> = Ref<T> & ServerRefExtend<T>;
type ServerReactive<T> = T & ServerRefExtend<T>;
declare function VitePluginServerRef(options?: ServerRefOptions<any>): Plugin;
export { type ServerReactive, type ServerRef, type ServerRefExtend, type ServerRefOptions, VitePluginServerRef as default };
+239
View File
@@ -0,0 +1,239 @@
import { resolvePath } from 'mlly';
import { ensurePrefix, slash } from '@antfu/utils';
import { parseURL, parseQuery } from 'ufo';
import { parse, apply } from './client.mjs';
import 'klona/json';
const URL_PREFIX = ["/@server-ref/", "/@server-reactive/"];
const VIRTUAL_PREFIX = ["server-ref:", "server-reactive:"];
const WS_EVENT = "vue-server-ref";
const PREFIXES = [...URL_PREFIX, ...VIRTUAL_PREFIX];
function getBodyJson(req) {
return new Promise((resolve, reject) => {
let body = "";
req.on("data", (chunk) => body += chunk);
req.on("error", reject);
req.on("end", () => {
try {
resolve(parse(body) || {});
} catch (e) {
reject(e);
}
});
});
}
function get(obj, key) {
return key.split(".").reduce((acc, key2) => acc?.[key2], obj);
}
function set(obj, key, value) {
const keys = key.split(".");
let acc = obj;
keys.slice(0, -1).forEach((key2) => {
if (!acc[key2])
acc[key2] = {};
acc = acc[key2];
});
acc[keys[keys.length - 1]] = value;
}
function parseId(id) {
for (const pre of PREFIXES) {
if (id.startsWith(pre)) {
const { pathname: key, search } = parseURL(id.substr(pre.length));
const query = parseQuery(search);
return {
key: key.replace(/\//g, "."),
type: pre.includes("ref") ? "ref" : "reactive",
prefix: pre,
diff: "diff" in query
};
}
}
}
function genCode(options, id, clientUrl = "vite-plugin-vue-server-ref/client") {
const { state, defaultValue, clientVue, debug, debounce } = options;
const { key, type, prefix, diff } = id;
const access = type === "ref" ? "data.value" : "data";
return `
import { ${type}, watch } from "${clientVue}"
import { randId, stringify, parse, define, apply,${type === "reactive" ? " reactiveSet," : ""}${diff ? " clone, diff" : ""} } from ${JSON.stringify(clientUrl)}
const data = ${type}(${JSON.stringify(get(state, key) ?? defaultValue(key))})
let onSet = []
let onPatch = []
define(data, '$syncUp', true)
define(data, '$syncDown', true)
define(data, '$paused', false)
define(data, '$onSet', fn => onSet.push(fn))
define(data, '$onPatch', fn => onPatch.push(fn))
const id = randId()
if (import.meta.hot) {
let skipWatch = false
let timer = null
${diff ? "let copy = null" : ""}
function post(payload) {
${debug ? `console.log("[server-ref] [${key}] outgoing", payload)` : ""}
return fetch('${prefix + key}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: stringify(payload)
})
}
${diff ? `
function makeClone() {
copy = clone(${access})
}
function getDiff() {
return diff(${access}, copy)
}
` : ""}
function applyPatch(patch, trigger = true) {
skipWatch = true
if (trigger) {
onPatch.forEach(fn => fn(patch))
${debug ? `console.log("[server-ref] [${key}] patch incoming", patch)` : ""}
}
apply(${access}, patch)
${diff ? "makeClone()" : ""}
skipWatch = false
}
function applySet(newData) {
skipWatch = true
onSet.forEach(fn => fn(newData))
${type === "ref" ? "data.value = newData" : "reactiveSet(data, newData)"}
${debug ? `console.log("[server-ref] [${key}] incoming", newData)` : ""}
${diff ? "makeClone()" : ""}
skipWatch = false
}
${debug ? `console.log("[server-ref] [${key}] ref", data)` : ""}
${debug ? `console.log("[server-ref] [${key}] initial", ${access})` : ""}
import.meta.hot.on("${WS_EVENT}", (payload) => {
if (!data.$syncDown || data.$paused || payload.key !== "${key}" || payload.source === id)
return
if (payload.patch)
applyPatch(payload.patch)
else
applySet(payload.data)
})
define(data, '$patch', async (patch) => {
if (!data.$syncUp || data.$paused)
return false
applyPatch(patch, false)
return post({
source: id,
patch,
timestamp: Date.now(),
})
})
watch(data, (v) => {
if (timer)
clearTimeout(timer)
if (!data.$syncUp || data.$paused || skipWatch)
return
timer = setTimeout(()=>{
post({
source: id,
${diff ? "patch: getDiff()" : `data: ${access}`},
timestamp: Date.now(),
})
}, ${debounce})
}, { flush: 'sync', deep: true })
}
else {
define(data, '$patch', async () => false)
}
export default data
`.replace(/\n\s*\n/gm, "\n");
}
const defaultOptions = {
state: {},
debounce: 10,
debug: false,
defaultValue: () => void 0,
clientVue: "vue",
onChanged: () => {
}
};
function resolveOptions(options) {
return Object.assign({}, defaultOptions, options);
}
function VitePluginServerRef(options = {}) {
const resolved = resolveOptions(options);
const { state } = resolved;
const idMaps = {};
return {
name: "vite-plugin-vue-server-ref",
resolveId(id) {
const idx = VIRTUAL_PREFIX.findIndex((pre) => id.startsWith(pre));
if (idx > -1)
return URL_PREFIX[idx] + id.slice(VIRTUAL_PREFIX[idx].length);
return URL_PREFIX.some((pre) => id.startsWith(pre)) ? id : null;
},
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
if (!req.url || req.method !== "POST")
return next();
const id = parseId(req.url);
if (!id)
return next();
const key = id.key;
const payload = await getBodyJson(req);
for (const id2 of idMaps[key] || []) {
const module = server.moduleGraph.getModuleById(id2);
if (module)
server.moduleGraph.invalidateModule(module);
}
if (payload.patch)
set(state, key, apply(get(state, key), payload.patch));
else
set(state, key, payload.data);
server.ws.send({
type: "custom",
event: WS_EVENT,
data: { ...payload, key }
});
options.onChanged?.(key, get(state, key), payload.patch, payload.timestamp);
res.write("");
res.end();
});
},
async load(id) {
const res = parseId(id);
if (!res)
return;
if (!idMaps[res.key])
idMaps[res.key] = /* @__PURE__ */ new Set();
idMaps[res.key].add(id);
return genCode(
resolved,
res,
toAtFS(await resolvePath("vite-plugin-vue-server-ref/client", { url: import.meta.url }))
);
}
};
}
function toAtFS(path) {
return `/@fs${ensurePrefix("/", slash(path))}`;
}
export { VitePluginServerRef as default };