solidstep 0.1.7 → 0.2.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 +47 -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 +34 -6
- package/utils/cache.d.ts +1 -0
- package/utils/cache.d.ts.map +1 -1
- package/utils/cache.js +11 -1
- 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,8 +364,16 @@ 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
|
```
|
|
373
|
+
- Regarding caching, setting `ttl` to `0` or omitting it will disable caching for that page.
|
|
374
|
+
- Setting a positive integer value will cache the page for that duration in milliseconds.
|
|
375
|
+
- Invalidation of cached pages can be done using the `invalidateCache` and `revalidatePath` utilities.
|
|
376
|
+
- The `responseHeaders` option allows you to set custom HTTP headers for the page response.
|
|
369
377
|
|
|
370
378
|
## API Routes
|
|
371
379
|
|
|
@@ -406,6 +414,45 @@ const template = await fs.promises.readFile(TEMPLATE_PATH, 'utf-8');
|
|
|
406
414
|
|
|
407
415
|
## Utilities
|
|
408
416
|
|
|
417
|
+
### Cache (Server-Side)
|
|
418
|
+
- Every page can be cached by setting the `options.cache` property in the page.
|
|
419
|
+
- You can also manually invalidate the cache for specific routes.
|
|
420
|
+
- Invalidation can be done in two ways:
|
|
421
|
+
1. Using the `invalidateCache` utility to only invalidate paths.
|
|
422
|
+
```tsx
|
|
423
|
+
import { invalidateCache } from 'solidstep/utils/cache';
|
|
424
|
+
|
|
425
|
+
const action = async () => {
|
|
426
|
+
'use server';
|
|
427
|
+
|
|
428
|
+
...
|
|
429
|
+
|
|
430
|
+
// Invalidate cache after data mutation
|
|
431
|
+
await invalidateCache('/some-route');
|
|
432
|
+
|
|
433
|
+
...
|
|
434
|
+
|
|
435
|
+
return { success: true };
|
|
436
|
+
};
|
|
437
|
+
```
|
|
438
|
+
2. Using the `revalidatePath` utility to revalidate specific paths and revalidate the frontend DOM - signaling the server action as a Single Flight Mutation query.
|
|
439
|
+
```tsx
|
|
440
|
+
import { revalidatePath } from 'solidstep/utils/cache';
|
|
441
|
+
|
|
442
|
+
const action = async () => {
|
|
443
|
+
'use server';
|
|
444
|
+
|
|
445
|
+
...
|
|
446
|
+
|
|
447
|
+
// Revalidate path after data mutation
|
|
448
|
+
await revalidatePath('/some-route');
|
|
449
|
+
|
|
450
|
+
...
|
|
451
|
+
|
|
452
|
+
return { success: true };
|
|
453
|
+
};
|
|
454
|
+
```
|
|
455
|
+
|
|
409
456
|
### Cookies
|
|
410
457
|
```tsx
|
|
411
458
|
import { getCookie, setCookie } from 'solidstep/utils/cookies';
|
|
@@ -750,7 +797,6 @@ export const RootLayout = (props) => {
|
|
|
750
797
|
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
798
|
|
|
752
799
|
## Future Plans
|
|
753
|
-
- Revalidate on demand
|
|
754
800
|
- Support for dynamic site.webmanifest, robots.txt, sitemap.xml, manifest.json, and llms.txt
|
|
755
801
|
- Support loading and error pages for parallel routes
|
|
756
802
|
- 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":"AA0hBA,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,14 @@ 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
|
-
|
|
364
|
+
if (toRender === 'main') {
|
|
365
|
+
const options = cachingOptions;
|
|
366
|
+
setCache(path, {
|
|
350
367
|
rendered: rendered,
|
|
351
368
|
documentMeta: meta,
|
|
352
369
|
documentAssets: assets,
|
|
353
370
|
loaderData: loaderData,
|
|
354
|
-
},
|
|
371
|
+
}, options?.ttl ? options.ttl : 0);
|
|
355
372
|
}
|
|
356
373
|
return {
|
|
357
374
|
rendered: rendered,
|
|
@@ -458,6 +475,14 @@ const handler = eventHandler(async (event) => {
|
|
|
458
475
|
type: 'title',
|
|
459
476
|
attributes: {},
|
|
460
477
|
content: 'SolidStep'
|
|
478
|
+
},
|
|
479
|
+
build_time: {
|
|
480
|
+
type: 'meta',
|
|
481
|
+
attributes: {
|
|
482
|
+
name: 'x-build-time',
|
|
483
|
+
content: Date.now().toString(),
|
|
484
|
+
description: 'IMPORTANT: This tag indicates the build time of the application and should not be removed.'
|
|
485
|
+
},
|
|
461
486
|
}
|
|
462
487
|
};
|
|
463
488
|
const assets = await clientManifest.inputs[clientManifest.handler].assets();
|
|
@@ -501,6 +526,9 @@ const handler = eventHandler(async (event) => {
|
|
|
501
526
|
}
|
|
502
527
|
else {
|
|
503
528
|
try {
|
|
529
|
+
if (!matched.loadingPage) {
|
|
530
|
+
throw new Error('No loading page');
|
|
531
|
+
}
|
|
504
532
|
const { rendered, documentMeta, documentAssets, loaderData, } = await render({
|
|
505
533
|
toRender: 'loading',
|
|
506
534
|
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;
|
|
@@ -36,7 +37,7 @@ const removeTail = () => {
|
|
|
36
37
|
};
|
|
37
38
|
export const getCache = (key) => {
|
|
38
39
|
const entry = cacheMap.get(key);
|
|
39
|
-
if (!entry)
|
|
40
|
+
if (!entry || !entry.expiresAt)
|
|
40
41
|
return null;
|
|
41
42
|
if (entry.expiresAt && entry.expiresAt < Date.now()) {
|
|
42
43
|
cacheMap.delete(key);
|
|
@@ -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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"}
|