solidstep 0.1.7 → 0.1.8
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 +43 -1
- package/client.d.ts.map +1 -1
- package/client.js +26 -0
- package/package.json +1 -1
- package/server.d.ts.map +1 -1
- package/server.js +33 -6
- package/utils/cache.d.ts +1 -0
- package/utils/cache.d.ts.map +1 -1
- package/utils/cache.js +10 -0
- package/utils/diff-dom.d.ts +72 -0
- package/utils/diff-dom.d.ts.map +1 -0
- package/utils/diff-dom.js +1081 -0
- package/utils/server-action.client.d.ts.map +1 -1
- package/utils/server-action.client.js +35 -8
- package/utils/server-action.server.d.ts.map +1 -1
- package/utils/server-action.server.js +34 -0
package/README.md
CHANGED
|
@@ -364,6 +364,10 @@ export const options = {
|
|
|
364
364
|
cache: {
|
|
365
365
|
ttl: 60000, // Cache for 60 seconds
|
|
366
366
|
},
|
|
367
|
+
responseHeaders: { // Custom headers for pages
|
|
368
|
+
'X-Custom-Header': 'MyValue',
|
|
369
|
+
'Cache-Control': 'public, max-age=60', // Client-side caching
|
|
370
|
+
},
|
|
367
371
|
};
|
|
368
372
|
```
|
|
369
373
|
|
|
@@ -406,6 +410,45 @@ const template = await fs.promises.readFile(TEMPLATE_PATH, 'utf-8');
|
|
|
406
410
|
|
|
407
411
|
## Utilities
|
|
408
412
|
|
|
413
|
+
### Cache (Server-Side)
|
|
414
|
+
- Every page can be cached by setting the `options.cache` property in the page.
|
|
415
|
+
- You can also manually invalidate the cache for specific routes.
|
|
416
|
+
- Invalidation can be done in two ways:
|
|
417
|
+
1. Using the `invalidateCache` utility to only invalidate paths.
|
|
418
|
+
```tsx
|
|
419
|
+
import { invalidateCache } from 'solidstep/utils/cache';
|
|
420
|
+
|
|
421
|
+
const action = async () => {
|
|
422
|
+
'use server';
|
|
423
|
+
|
|
424
|
+
...
|
|
425
|
+
|
|
426
|
+
// Invalidate cache after data mutation
|
|
427
|
+
await invalidateCache('/some-route');
|
|
428
|
+
|
|
429
|
+
...
|
|
430
|
+
|
|
431
|
+
return { success: true };
|
|
432
|
+
};
|
|
433
|
+
```
|
|
434
|
+
2. Using the `revalidatePath` utility to revalidate specific paths and revalidate the frontend DOM - signaling the server action as a Single Flight Mutation query.
|
|
435
|
+
```tsx
|
|
436
|
+
import { revalidatePath } from 'solidstep/utils/cache';
|
|
437
|
+
|
|
438
|
+
const action = async () => {
|
|
439
|
+
'use server';
|
|
440
|
+
|
|
441
|
+
...
|
|
442
|
+
|
|
443
|
+
// Revalidate path after data mutation
|
|
444
|
+
await revalidatePath('/some-route');
|
|
445
|
+
|
|
446
|
+
...
|
|
447
|
+
|
|
448
|
+
return { success: true };
|
|
449
|
+
};
|
|
450
|
+
```
|
|
451
|
+
|
|
409
452
|
### Cookies
|
|
410
453
|
```tsx
|
|
411
454
|
import { getCookie, setCookie } from 'solidstep/utils/cookies';
|
|
@@ -750,7 +793,6 @@ export const RootLayout = (props) => {
|
|
|
750
793
|
As SolidStep is built using Vite, it follows the same guide as stated in [Vite docs](https://vite.dev/guide/env-and-mode) regarding environment variables.
|
|
751
794
|
|
|
752
795
|
## Future Plans
|
|
753
|
-
- Revalidate on demand
|
|
754
796
|
- Support for dynamic site.webmanifest, robots.txt, sitemap.xml, manifest.json, and llms.txt
|
|
755
797
|
- Support loading and error pages for parallel routes
|
|
756
798
|
- Support deferring loaders
|
package/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../client.ts"],"names":[],"mappings":"AACA,OAAO,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../client.ts"],"names":[],"mappings":"AACA,OAAO,cAAc,CAAC;AAwCtB,eAAO,MAAM,IAAI,GACb,YAAY,MAAM,EAClB,cAAa,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACxC,eAAc,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACzC,qBAAoB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,kBAsF/C,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
package/client.js
CHANGED
|
@@ -2,6 +2,32 @@ import { hydrate } from 'solid-js/web';
|
|
|
2
2
|
import 'vinxi/client';
|
|
3
3
|
import fileRoutes from 'vinxi/routes';
|
|
4
4
|
import { getManifest } from 'vinxi/manifest';
|
|
5
|
+
import { createDiffDOM } from './utils/diff-dom';
|
|
6
|
+
window.onpageshow = () => {
|
|
7
|
+
const state = window.history.state;
|
|
8
|
+
const key = `${window.location.pathname}:build-time`;
|
|
9
|
+
const buildTimeMeta = document.querySelector('meta[name="x-build-time"]');
|
|
10
|
+
const buildTime = buildTimeMeta ? Number.parseInt(buildTimeMeta.getAttribute('content') || '0', 10) : 0;
|
|
11
|
+
const lastBuildTime = Number.parseInt(sessionStorage.getItem(key) || '0', 10);
|
|
12
|
+
const diffString = sessionStorage.getItem(window.location.pathname);
|
|
13
|
+
if (state?.revalidated && buildTime === lastBuildTime && diffString) {
|
|
14
|
+
// we need to re-apply the diff from session storage
|
|
15
|
+
const diff = JSON.parse(diffString);
|
|
16
|
+
const dd = createDiffDOM();
|
|
17
|
+
const didApply = dd.apply(document.body, diff);
|
|
18
|
+
if (didApply) {
|
|
19
|
+
const key = window.location.pathname;
|
|
20
|
+
sessionStorage.setItem(key, JSON.stringify(diff));
|
|
21
|
+
window.history.pushState({ revalidated: true }, '', window.location.href);
|
|
22
|
+
}
|
|
23
|
+
if (import.meta.env.DEV && !didApply) {
|
|
24
|
+
console.error('The mutation was not applied, this seems to be an edge case.');
|
|
25
|
+
console.error('Please raise an issue on GitHub describing your case.');
|
|
26
|
+
console.error('The diff calculated:', diff);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
sessionStorage.setItem(key, buildTime.toString());
|
|
30
|
+
};
|
|
5
31
|
const importModule = async (routeModule) => {
|
|
6
32
|
const manifest = getManifest('client');
|
|
7
33
|
if (import.meta.env.DEV) {
|
package/package.json
CHANGED
package/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../server.ts"],"names":[],"mappings":"AAyhBA,QAAA,MAAM,OAAO,+FAgVX,CAAC;AAEH,eAAe,OAAO,CAAC"}
|
package/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { eventHandler, toWebRequest } from 'vinxi/http';
|
|
1
|
+
import { eventHandler, toWebRequest, setResponseHeader, getEvent } from 'vinxi/http';
|
|
2
2
|
import { getManifest } from 'vinxi/manifest';
|
|
3
3
|
import { generateHydrationScript, renderToString } from 'solid-js/web';
|
|
4
4
|
import fileRoutes, {} from 'vinxi/routes';
|
|
@@ -215,9 +215,18 @@ const sendNodeResponse = async (res, response) => {
|
|
|
215
215
|
}
|
|
216
216
|
};
|
|
217
217
|
const render = async ({ toRender, entry, routeParams, searchParams, req, cspNonce, }) => {
|
|
218
|
-
const url = req.url
|
|
219
|
-
const
|
|
218
|
+
const url = new URL(req.url);
|
|
219
|
+
const path = url.pathname;
|
|
220
|
+
const cachedEntry = getCache(path);
|
|
220
221
|
if (cachedEntry && toRender === 'main') {
|
|
222
|
+
const { options } = entry.mainPage.options ? await entry.mainPage.options.import() : { options: {} };
|
|
223
|
+
if (options?.responseHeaders) {
|
|
224
|
+
const headers = options.responseHeaders;
|
|
225
|
+
const event = getEvent();
|
|
226
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
227
|
+
setResponseHeader(event, key, value);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
221
230
|
return {
|
|
222
231
|
rendered: cachedEntry.rendered,
|
|
223
232
|
documentMeta: cachedEntry.documentMeta,
|
|
@@ -316,6 +325,13 @@ const render = async ({ toRender, entry, routeParams, searchParams, req, cspNonc
|
|
|
316
325
|
if (options?.cache) {
|
|
317
326
|
cachingOptions = options.cache;
|
|
318
327
|
}
|
|
328
|
+
if (options?.responseHeaders) {
|
|
329
|
+
const headers = options.responseHeaders;
|
|
330
|
+
const event = getEvent();
|
|
331
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
332
|
+
setResponseHeader(event, key, value);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
319
335
|
let data = {};
|
|
320
336
|
if (pageLoader) {
|
|
321
337
|
const result = await pageLoader.loader(req);
|
|
@@ -345,13 +361,13 @@ const render = async ({ toRender, entry, routeParams, searchParams, req, cspNonc
|
|
|
345
361
|
});
|
|
346
362
|
const composed = await compose();
|
|
347
363
|
const rendered = await renderToString(() => composed());
|
|
348
|
-
if (
|
|
349
|
-
setCache(
|
|
364
|
+
if (toRender === 'main') {
|
|
365
|
+
setCache(path, {
|
|
350
366
|
rendered: rendered,
|
|
351
367
|
documentMeta: meta,
|
|
352
368
|
documentAssets: assets,
|
|
353
369
|
loaderData: loaderData,
|
|
354
|
-
}, cachingOptions.ttl);
|
|
370
|
+
}, cachingOptions ? cachingOptions.ttl : 0);
|
|
355
371
|
}
|
|
356
372
|
return {
|
|
357
373
|
rendered: rendered,
|
|
@@ -458,6 +474,14 @@ const handler = eventHandler(async (event) => {
|
|
|
458
474
|
type: 'title',
|
|
459
475
|
attributes: {},
|
|
460
476
|
content: 'SolidStep'
|
|
477
|
+
},
|
|
478
|
+
build_time: {
|
|
479
|
+
type: 'meta',
|
|
480
|
+
attributes: {
|
|
481
|
+
name: 'x-build-time',
|
|
482
|
+
content: Date.now().toString(),
|
|
483
|
+
description: 'IMPORTANT: This tag indicates the build time of the application and should not be removed.'
|
|
484
|
+
},
|
|
461
485
|
}
|
|
462
486
|
};
|
|
463
487
|
const assets = await clientManifest.inputs[clientManifest.handler].assets();
|
|
@@ -501,6 +525,9 @@ const handler = eventHandler(async (event) => {
|
|
|
501
525
|
}
|
|
502
526
|
else {
|
|
503
527
|
try {
|
|
528
|
+
if (!matched.loadingPage) {
|
|
529
|
+
throw new Error('No loading page');
|
|
530
|
+
}
|
|
504
531
|
const { rendered, documentMeta, documentAssets, loaderData, } = await render({
|
|
505
532
|
toRender: 'loading',
|
|
506
533
|
entry: matched,
|
package/utils/cache.d.ts
CHANGED
|
@@ -2,4 +2,5 @@ export declare const getCache: <T>(key: string) => T | null;
|
|
|
2
2
|
export declare const setCache: <T>(key: string, value: T, ttlMs?: number) => void;
|
|
3
3
|
export declare const invalidateCache: (key: string) => void;
|
|
4
4
|
export declare const clearAllCache: () => void;
|
|
5
|
+
export declare const revalidatePath: (path: string) => void;
|
|
5
6
|
//# sourceMappingURL=cache.d.ts.map
|
package/utils/cache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../utils/cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../utils/cache.ts"],"names":[],"mappings":"AA+CA,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,KAAK,MAAM,KAAG,CAAC,GAAG,IAe7C,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,KAAK,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,MAAM,SA0BhE,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,SAU1C,CAAC;AAEF,eAAO,MAAM,aAAa,YAGzB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,SAS1C,CAAC"}
|
package/utils/cache.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getEvent, setResponseHeader } from 'vinxi/http';
|
|
1
2
|
const MAX_CACHE_ENTRIES = 1000;
|
|
2
3
|
const cacheMap = new Map();
|
|
3
4
|
let head;
|
|
@@ -95,3 +96,12 @@ export const clearAllCache = () => {
|
|
|
95
96
|
cacheMap.clear();
|
|
96
97
|
head = tail = undefined;
|
|
97
98
|
};
|
|
99
|
+
export const revalidatePath = (path) => {
|
|
100
|
+
// get and verify the event
|
|
101
|
+
const event = getEvent();
|
|
102
|
+
if (!event.path.includes('_server')) {
|
|
103
|
+
throw new Error('This function can only be used in server functions.');
|
|
104
|
+
}
|
|
105
|
+
// add the revalidate header as a flag for the server action to do diffing
|
|
106
|
+
setResponseHeader(event, 'X-Revalidate', path);
|
|
107
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
declare const SKIP_MODES: {
|
|
2
|
+
readonly CHILDREN: "children";
|
|
3
|
+
readonly FULL: "full";
|
|
4
|
+
};
|
|
5
|
+
type SkipMode = (typeof SKIP_MODES)[keyof typeof SKIP_MODES];
|
|
6
|
+
type SkipPredicate = (domNode: Node | VirtualNode, virtualNode: VirtualNode) => boolean | SkipMode;
|
|
7
|
+
type PreDiffApplyHook = (info: {
|
|
8
|
+
diff: DiffResult;
|
|
9
|
+
node: Node;
|
|
10
|
+
}) => boolean | undefined;
|
|
11
|
+
type PostDiffApplyHook = (info: {
|
|
12
|
+
diff: DiffResult;
|
|
13
|
+
node: Node;
|
|
14
|
+
}) => void;
|
|
15
|
+
type FilterOuterDiffHook = (oldNode: VirtualNode, newNode: VirtualNode, diffs: DiffResult[]) => DiffResult[] | undefined;
|
|
16
|
+
type TextDiffHook = (target: Node, currentData: string, oldValue: string, newValue: string) => void;
|
|
17
|
+
interface DiffOptions {
|
|
18
|
+
skipSelector: string | null;
|
|
19
|
+
skipPredicate: SkipPredicate | null;
|
|
20
|
+
skipAttributes: string[];
|
|
21
|
+
skipChildren: boolean;
|
|
22
|
+
skipMode: SkipMode;
|
|
23
|
+
debug: boolean;
|
|
24
|
+
diffcap: number;
|
|
25
|
+
valueDiffing: boolean;
|
|
26
|
+
caseSensitive: boolean;
|
|
27
|
+
preVirtualDiffApply: PreDiffApplyHook | null;
|
|
28
|
+
postVirtualDiffApply: PostDiffApplyHook | null;
|
|
29
|
+
preDiffApply: PreDiffApplyHook | null;
|
|
30
|
+
postDiffApply: PostDiffApplyHook | null;
|
|
31
|
+
filterOuterDiff: FilterOuterDiffHook | null;
|
|
32
|
+
textDiff: TextDiffHook | null;
|
|
33
|
+
document: Document | null;
|
|
34
|
+
}
|
|
35
|
+
interface VirtualNode {
|
|
36
|
+
nodeType: number;
|
|
37
|
+
nodeName: string;
|
|
38
|
+
route?: number[];
|
|
39
|
+
data?: string;
|
|
40
|
+
attributes?: Record<string, string>;
|
|
41
|
+
value?: string;
|
|
42
|
+
checked?: boolean;
|
|
43
|
+
selected?: boolean;
|
|
44
|
+
childNodes?: VirtualNode[];
|
|
45
|
+
innerDone?: boolean;
|
|
46
|
+
skipFull?: boolean;
|
|
47
|
+
}
|
|
48
|
+
interface DiffResult {
|
|
49
|
+
action: string;
|
|
50
|
+
route: number[];
|
|
51
|
+
from?: number[];
|
|
52
|
+
to?: number[];
|
|
53
|
+
element?: VirtualNode;
|
|
54
|
+
index?: number;
|
|
55
|
+
name?: string;
|
|
56
|
+
value?: string;
|
|
57
|
+
oldValue?: string | boolean | VirtualNode;
|
|
58
|
+
newValue?: string | boolean | VirtualNode;
|
|
59
|
+
}
|
|
60
|
+
export declare const nodeToObj: (node: Node, options?: Partial<DiffOptions>) => VirtualNode | null;
|
|
61
|
+
export declare const stringToObj: (htmlString: string, options?: Partial<DiffOptions>) => VirtualNode;
|
|
62
|
+
export declare const objToNode: (obj: VirtualNode, options?: Partial<DiffOptions>) => Node | null;
|
|
63
|
+
export declare const diff: (elementA: string | Node | VirtualNode, elementB: string | Node | VirtualNode, options?: Partial<DiffOptions>) => DiffResult[];
|
|
64
|
+
export declare const apply: (element: Node, diffs: DiffResult[], options?: Partial<DiffOptions>) => boolean;
|
|
65
|
+
export declare const undo: (element: Node, diffs: DiffResult[], options?: Partial<DiffOptions>) => boolean;
|
|
66
|
+
export declare const createDiffDOM: (userOptions?: Partial<DiffOptions>) => {
|
|
67
|
+
diff: (elementA: string | Node | VirtualNode, elementB: string | Node | VirtualNode) => DiffResult[];
|
|
68
|
+
apply: (element: Node, diffs: DiffResult[]) => boolean;
|
|
69
|
+
undo: (element: Node, diffs: DiffResult[]) => boolean;
|
|
70
|
+
};
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=diff-dom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-dom.d.ts","sourceRoot":"","sources":["../../utils/diff-dom.ts"],"names":[],"mappings":"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"}
|