wip fix time

This commit is contained in:
Rizky 2024-01-26 22:01:52 +07:00
parent 1d6ed73f2b
commit b52975ebfd
14 changed files with 275 additions and 25 deletions

View File

@ -13,21 +13,22 @@ export const SyncActionDefinition = {
}, },
"page": { "page": {
"list": "8", "list": "8",
"load": "9" "load": "9",
"cache": "10"
}, },
"yjs": { "yjs": {
"um": "10", "um": "11",
"sv_local": "11", "sv_local": "12",
"diff_local": "12", "diff_local": "13",
"sv_remote": "13" "sv_remote": "14"
}, },
"client": { "client": {
"info": "14" "info": "15"
}, },
"code": { "code": {
"load": "15", "load": "16",
"edit": "16", "edit": "17",
"parse": "17" "parse": "18"
} }
}; };
export const SyncActionPaths = { export const SyncActionPaths = {
@ -41,12 +42,13 @@ export const SyncActionPaths = {
"7": "comp.load", "7": "comp.load",
"8": "page.list", "8": "page.list",
"9": "page.load", "9": "page.load",
"10": "yjs.um", "10": "page.cache",
"11": "yjs.sv_local", "11": "yjs.um",
"12": "yjs.diff_local", "12": "yjs.sv_local",
"13": "yjs.sv_remote", "13": "yjs.diff_local",
"14": "client.info", "14": "yjs.sv_remote",
"15": "code.load", "15": "client.info",
"16": "code.edit", "16": "code.load",
"17": "code.parse" "17": "code.edit",
"18": "code.parse"
}; };

View File

@ -52,6 +52,8 @@ export const SyncActions = {
list: async (id_site: string) => list: async (id_site: string) =>
({}) as Record<string, Exclude<page, "content_tree">>, ({}) as Record<string, Exclude<page, "content_tree">>,
load: async (id: string) => ({}) as EPage | void, load: async (id: string) => ({}) as EPage | void,
cache: async (site_id: string, urls: string[], exclude_page_id: string[]) =>
({}) as { gzip: Uint8Array } | null,
}, },
yjs: { yjs: {
um: async ( um: async (

View File

@ -8,6 +8,7 @@ export * from "./comp_group";
export * from "./comp_load"; export * from "./comp_load";
export * from "./page_list"; export * from "./page_list";
export * from "./page_load"; export * from "./page_load";
export * from "./page_cache";
export * from "./yjs_um"; export * from "./yjs_um";
export * from "./yjs_sv_local"; export * from "./yjs_sv_local";
export * from "./yjs_diff_local"; export * from "./yjs_diff_local";

View File

@ -0,0 +1,58 @@
import { RadixRouter, createRouter } from "radix3";
import { SAction } from "../actions";
import { SyncConnection } from "../type";
import { gzipAsync } from "../entity/zlib";
const cache = {} as Record<
string,
{ ts: number; router: RadixRouter<{ url: string; id: string }> }
>;
const encoder = new TextEncoder();
export const page_cache: SAction["page"]["cache"] = async function (
this: SyncConnection,
site_id,
urls,
exclude_page_id
) {
let result = null as unknown as Awaited<ReturnType<SAction["page"]["cache"]>>;
if (
!cache[site_id] ||
(cache[site_id] && Date.now() - cache[site_id].ts > 5000)
) {
const pages = await db.page.findMany({
where: { id_site: site_id, is_deleted: false },
select: { id: true, url: true },
});
const router = createRouter<{ url: string; id: string }>();
for (const page of pages) {
router.insert(page.url, page);
}
cache[site_id] = {
router,
ts: Date.now(),
};
}
const router = cache[site_id]?.router;
if (router) {
const result: Record<string, any> = {};
for (const url of urls) {
const found = router.lookup(url);
if (found && !exclude_page_id.includes(found.id)) {
const row = await db.page.findFirst({
where: { id: found.id },
select: { content_tree: true },
});
if (row) {
result[found.id] = row.content_tree;
}
}
}
const gzip = await gzipAsync(encoder.encode(JSON.stringify(result)));
return { gzip };
}
return null;
};

View File

@ -25,7 +25,7 @@ export const loadApiProxyDef = async (_url: string, with_types: boolean) => {
const ts = localStorage.getItem("api-ts-" + url); const ts = localStorage.getItem("api-ts-" + url);
if (with_types) { if (with_types) {
script.src = `${base}/_prasi/load.js?url=${url}&v3&dev=1&ts=${ts}`; script.src = `${base}/_prasi/load.js?url=${url}&v3&dev=1&ts=${ts}`;
} else { } else {
script.src = `${base}/_prasi/load.js?url=${url}&v3&ts=${ts}`; script.src = `${base}/_prasi/load.js?url=${url}&v3&ts=${ts}`;

View File

@ -5,7 +5,7 @@ import { SAction } from "../../../../../srv/ws/sync/actions";
import { parseJs } from "../../../../../srv/ws/sync/editor/parser/parse-js"; import { parseJs } from "../../../../../srv/ws/sync/editor/parser/parse-js";
import { clientStartSync } from "../../../utils/sync/ws-client"; import { clientStartSync } from "../../../utils/sync/ws-client";
import { IItem } from "../../../utils/types/item"; import { IItem } from "../../../utils/types/item";
import { DCode, DComp, DPage } from "../../../utils/types/root"; import { DCode, DComp, DPage, IRoot } from "../../../utils/types/root";
import { GenMetaP, IMeta as LogicMeta } from "../../vi/utils/types"; import { GenMetaP, IMeta as LogicMeta } from "../../vi/utils/types";
export type IMeta = LogicMeta; export type IMeta = LogicMeta;
@ -147,6 +147,12 @@ export const EDGlobal = {
| "page-not-found" | "page-not-found"
| "ready", | "ready",
preview: { preview: {
url_cache: new Set<string>(),
page_cache: {} as Record<string, IRoot>,
meta_cache: {} as Record<
string,
{ entry: string[]; meta: Record<string, IMeta> }
>,
show_loading: false, show_loading: false,
}, },
sync: null as unknown as Awaited<ReturnType<typeof clientStartSync>>, sync: null as unknown as Awaited<ReturnType<typeof clientStartSync>>,

View File

@ -1,10 +1,32 @@
import { createId } from "@paralleldrive/cuid2"; import { IContent } from "../../../../utils/types/general";
import { IItem, MItem } from "../../../../utils/types/item"; import { IItem, MItem } from "../../../../utils/types/item";
import { genMeta } from "../../../vi/meta/meta"; import { genMeta } from "../../../vi/meta/meta";
import { IMeta, PG, active } from "../ed-global"; import { IMeta, PG, active } from "../ed-global";
import { assignMitem } from "./assign-mitem"; import { assignMitem } from "./assign-mitem";
import { pushTreeNode } from "./build/push-tree"; import { pushTreeNode } from "./build/push-tree";
export const treeCacheBuild = async (p: PG, page_id: string) => {
const root = p.preview.page_cache[page_id];
const meta_cache = {
meta: {} as Record<string, IMeta>,
entry: [] as string[],
};
for (const item of root.childs) {
meta_cache.entry.push(item.id);
genMeta(
{
note: "tree-rebuild",
comps: p.comp.loaded,
meta: meta_cache.meta,
mode: "page",
},
{ item: item as IContent }
);
}
p.preview.meta_cache[page_id] = meta_cache;
};
export const treeRebuild = async (p: PG, arg?: { note?: string }) => { export const treeRebuild = async (p: PG, arg?: { note?: string }) => {
if (document.activeElement) { if (document.activeElement) {
const a = document.activeElement; const a = document.activeElement;

View File

@ -4,9 +4,12 @@ import { EDGlobal, PG, active } from "../ed/logic/ed-global";
import { reloadPage } from "../ed/logic/ed-route"; import { reloadPage } from "../ed/logic/ed-route";
import { loadSite } from "../ed/logic/ed-site"; import { loadSite } from "../ed/logic/ed-site";
import { Vi } from "./vi"; import { Vi } from "./vi";
import init from "wasm-gzip"; import init, { decompress } from "wasm-gzip";
import { w } from "../../utils/types/general"; import { w } from "../../utils/types/general";
import { IRoot } from "../../utils/types/root";
import { treeCacheBuild } from "../ed/logic/tree/build";
const decoder = new TextDecoder();
export const ViPreview = (arg: { pathname: string }) => { export const ViPreview = (arg: { pathname: string }) => {
const p = useGlobal(EDGlobal, "EDITOR"); const p = useGlobal(EDGlobal, "EDITOR");
@ -49,6 +52,13 @@ export const ViPreview = (arg: { pathname: string }) => {
const mode = p.mode; const mode = p.mode;
if (!w.isEditor) {
p.preview.meta_cache[params.page_id] = {
meta: p.page.meta,
entry: p.page.entry,
};
}
return ( return (
<div className={cx("relative flex flex-1 items-center justify-center")}> <div className={cx("relative flex flex-1 items-center justify-center")}>
<div <div
@ -91,6 +101,36 @@ export const ViPreview = (arg: { pathname: string }) => {
db={p.script.db} db={p.script.db}
render_stat="disabled" render_stat="disabled"
script={{ init_local_effect: p.script.init_local_effect }} script={{ init_local_effect: p.script.init_local_effect }}
on_nav_loaded={async ({ urls }) => {
const load_urls: string[] = [];
if (p.preview.url_cache) {
for (const url of urls) {
if (!p.preview.url_cache.has(url)) {
load_urls.push(url);
p.preview.url_cache.add(url);
}
}
}
if (load_urls.length > 0) {
console.log(load_urls);
const res = await p.sync.page.cache(
p.site.id,
load_urls,
Object.keys(p.preview.page_cache)
);
if (res) {
const pages = JSON.parse(
decoder.decode(decompress(res.gzip)) || "{}"
);
for (const [id, page] of Object.entries(pages)) {
p.preview.page_cache[id] = page as IRoot;
treeCacheBuild(p, params.page_id);
}
}
}
}}
/> />
</div> </div>
</div> </div>
@ -130,6 +170,23 @@ const viRoute = async (p: PG) => {
} }
p.script.init_local_effect = {}; p.script.init_local_effect = {};
if (!w.isEditor) {
const page_cache = p.preview.meta_cache[params.page_id];
if (page_cache) {
p.page.meta = page_cache.meta;
p.page.entry = page_cache.entry;
if (p.page.cur.id !== params.page_id) {
p.page.cur = { id: params.page_id } as any;
}
p.status = "ready";
p.render();
return;
}
}
await reloadPage(p, params.page_id, "load-route"); await reloadPage(p, params.page_id, "load-route");
} }
} }

View File

@ -1,4 +1,3 @@
import { IItem } from "../../../utils/types/item";
import { IMeta } from "../../ed/logic/ed-global"; import { IMeta } from "../../ed/logic/ed-global";
import { viParts } from "./parts"; import { viParts } from "./parts";
@ -25,6 +24,13 @@ export const ViGlobal = {
| undefined | undefined
| ((meta: IMeta, parts: ReturnType<typeof viParts>) => void), | ((meta: IMeta, parts: ReturnType<typeof viParts>) => void),
on_status_changes: undefined as void | ((status: ViStatus) => void), on_status_changes: undefined as void | ((status: ViStatus) => void),
page: {
cur: { id: "" },
navs: {} as Record<string, Set<string>>,
},
on_nav_loaded: undefined as
| undefined
| ((arg: { urls: string[] }) => Promise<void>),
}; };
export type VG = typeof ViGlobal & { render: () => void }; export type VG = typeof ViGlobal & { render: () => void };

View File

@ -3,9 +3,16 @@ import { VG } from "../global";
import { ViRender } from "../render"; import { ViRender } from "../render";
import { viScriptArg } from "./arg"; import { viScriptArg } from "./arg";
import { replaceWithObject, replacement } from "./eval-script"; import { replaceWithObject, replacement } from "./eval-script";
import { extractNavigate } from "./extract-nav";
export const viEvalProps = ( export const viEvalProps = (
vi: { meta: VG["meta"]; site: { db: any; api: any } }, vi: {
mode: VG["mode"];
meta: VG["meta"];
site: { db: any; api: any };
page: VG["page"];
on_nav_loaded?: VG["on_nav_loaded"];
},
meta: IMeta, meta: IMeta,
passprop: any passprop: any
) => { ) => {
@ -85,6 +92,10 @@ export const viEvalProps = (
continue; continue;
} }
if (prop.value) {
extractNavigate(vi, prop.value);
}
const js = prop.valueBuilt || ""; const js = prop.valueBuilt || "";
const src = replaceWithObject(js, replacement) || ""; const src = replaceWithObject(js, replacement) || "";
const fn = new Function( const fn = new Function(

View File

@ -8,13 +8,18 @@ import { viScriptArg } from "./arg";
import { updatePropScope } from "./eval-prop"; import { updatePropScope } from "./eval-prop";
import { createViLocal } from "./local"; import { createViLocal } from "./local";
import { createViPassProp } from "./passprop"; import { createViPassProp } from "./passprop";
import { extractNavigate } from "./extract-nav";
import { w } from "../../../../utils/types/general";
export const viEvalScript = ( export const viEvalScript = (
vi: { vi: {
page: VG["page"];
mode: VG["mode"];
site: { db: any; api: any }; site: { db: any; api: any };
meta: VG["meta"]; meta: VG["meta"];
visit?: VG["visit"]; visit?: VG["visit"];
script?: { init_local_effect: any }; script?: { init_local_effect: any };
on_nav_loaded?: VG["on_nav_loaded"];
}, },
meta: IMeta, meta: IMeta,
passprop: any passprop: any
@ -66,6 +71,10 @@ export const viEvalScript = (
} }
} }
if (!w.isEditor && meta.item.adv?.js) {
extractNavigate(vi, meta.item.adv.js);
}
const js = meta.item.adv?.jsBuilt || ""; const js = meta.item.adv?.jsBuilt || "";
const src = replaceWithObject(js, replacement) || ""; const src = replaceWithObject(js, replacement) || "";
const fn = new Function( const fn = new Function(

View File

@ -0,0 +1,58 @@
import { VG } from "../global";
const nav = { timeout: null as any };
export const extractNavigate = (
vi: { page: VG["page"]; on_nav_loaded?: VG["on_nav_loaded"] },
str: string
) => {
const found_nav = [
...findBetween(str, `navigate(`, `)`),
...findBetween(str, `href = `, `;`),
];
const page_id = vi.page.cur.id;
if (!vi.page.navs[page_id]) {
vi.page.navs[page_id] = new Set();
}
for (const url of found_nav) {
vi.page.navs[page_id].add(url);
}
clearTimeout(nav.timeout);
nav.timeout = setTimeout(() => {
if (vi.on_nav_loaded) {
vi.on_nav_loaded({
urls: Array.from(vi.page.navs[page_id]),
});
}
}, 100);
};
const findBetween = (text: string, opener: string, closer: string) => {
let i = 0;
let last = 0;
const founds: string[] = [];
while (true) {
const startIndex = text.indexOf(opener, i);
last = i;
if (startIndex >= 0) {
const char = text[startIndex + opener.length];
if (char === '"' || char === "'" || char === "`") {
const end = text.indexOf(
`${char}${closer}`,
startIndex + opener.length + 1
);
const found = text.substring(startIndex + opener.length + 1, end);
i = end + 2 + closer.length;
founds.push(found);
}
}
if (last === i) {
break;
}
}
return founds;
};

View File

@ -1,4 +1,4 @@
import { FC, Suspense, useState } from "react"; import { FC, Suspense, useEffect, useState } from "react";
import { useGlobal } from "web-utils"; import { useGlobal } from "web-utils";
import { IMeta } from "../ed/logic/ed-global"; import { IMeta } from "../ed/logic/ed-global";
import { viLoad } from "./load/load"; import { viLoad } from "./load/load";
@ -6,6 +6,7 @@ import { VG, ViGlobal } from "./render/global";
import { ViRoot } from "./root"; import { ViRoot } from "./root";
import { ErrorBox } from "./utils/error-box"; import { ErrorBox } from "./utils/error-box";
import { render_stat } from "./render/render"; import { render_stat } from "./render/render";
import { IRoot } from "../../utils/types/root";
const w = window as any; const w = window as any;
export const Vi: FC<{ export const Vi: FC<{
@ -22,6 +23,7 @@ export const Vi: FC<{
visit?: VG["visit"]; visit?: VG["visit"];
render_stat?: "enabled" | "disabled"; render_stat?: "enabled" | "disabled";
on_status_changed?: (status: VG["status"]) => void; on_status_changed?: (status: VG["status"]) => void;
on_nav_loaded?: (arg: { urls: string[] }) => Promise<void>;
}> = ({ }> = ({
meta, meta,
entry, entry,
@ -32,15 +34,18 @@ export const Vi: FC<{
db, db,
visit, visit,
script, script,
page_id,
render_stat: rs, render_stat: rs,
on_status_changed, on_status_changed,
on_nav_loaded,
}) => { }) => {
const vi = useGlobal(ViGlobal, "VI"); const vi = useGlobal(ViGlobal, "VI");
vi.mode = mode; vi.mode = mode;
vi.on_nav_loaded = on_nav_loaded;
w.isMobile = mode === "mobile"; w.isMobile = mode === "mobile";
w.isDesktop = mode === "desktop"; w.isDesktop = mode === "desktop";
vi.page.cur.id = page_id;
vi.on_status_changes = on_status_changed; vi.on_status_changes = on_status_changed;
if (rs === "disabled") { if (rs === "disabled") {
@ -61,6 +66,19 @@ export const Vi: FC<{
viLoad(vi, { api_url, site_id }); viLoad(vi, { api_url, site_id });
} }
if (on_nav_loaded) {
useEffect(() => {
setTimeout(() => {
const nav = vi.page.navs[vi.page.cur.id];
if (nav) {
on_nav_loaded({
urls: Array.from(nav),
});
}
}, 500);
}, [vi.page.cur.id]);
}
return ( return (
<ErrorBox> <ErrorBox>
<Suspense> <Suspense>

BIN
dockerzip

Binary file not shown.