@solidjs/router
Advanced tools
Comparing version 0.10.0-beta.9 to 0.10.0
@@ -1,6 +0,6 @@ | ||
import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js"; | ||
import { $TRACK, createMemo, createSignal, onCleanup, getOwner, } from "solid-js"; | ||
import { isServer } from "solid-js/web"; | ||
import { useRouter } from "../routing"; | ||
import { redirectStatusCodes } from "../utils"; | ||
import { hashKey, revalidate } from "./cache"; | ||
import { cacheKeyOp, hashKey, revalidate } from "./cache"; | ||
export const actions = /* #__PURE__ */ new Map(); | ||
@@ -68,3 +68,5 @@ export function useSubmissions(fn, filter) { | ||
} | ||
const url = fn.url || (name && `action:${name}`) || (!isServer ? `action:${fn.name}` : ""); | ||
const url = fn.url || | ||
(name && `action:${name}`) || | ||
(!isServer ? `action:${hashString(fn.toString())}` : ""); | ||
return toAction(mutate, url); | ||
@@ -84,3 +86,3 @@ } | ||
uri.searchParams.set("args", hashKey(args)); | ||
return toAction(newFn, uri.pathname + uri.search); | ||
return toAction(newFn, (uri.protocol === "action:" ? uri.protocol : "") + uri.pathname + uri.search); | ||
}; | ||
@@ -94,2 +96,3 @@ fn.url = url; | ||
} | ||
const hashString = (s) => s.split("").reduce((a, b) => ((a << 5) - a + b.charCodeAt(0)) | 0, 0); | ||
async function handleResponse(response, navigate) { | ||
@@ -101,2 +104,4 @@ let data; | ||
keys = response.headers.get("X-Revalidate").split(","); | ||
// invalidate | ||
cacheKeyOp(keys, entry => (entry[0] = 0)); | ||
} | ||
@@ -117,4 +122,5 @@ if (response.customBody) | ||
data = response; | ||
await revalidate(keys); | ||
// trigger revalidation | ||
await revalidate(keys, false); | ||
return data; | ||
} |
@@ -0,3 +1,6 @@ | ||
import { type Signal } from "solid-js"; | ||
import { type ReconcileOptions } from "solid-js/store"; | ||
export declare function revalidate(key?: string | string[] | void): Promise<void>; | ||
type CacheEntry = [number, any, string, Set<Signal<number>>]; | ||
export declare function revalidate(key?: string | string[] | void, force?: boolean): Promise<void>; | ||
export declare function cacheKeyOp(key: string | string[] | void, fn: (cacheEntry: CacheEntry) => void): void; | ||
export type CachedFunction<T extends (...args: any) => U | Response, U> = T & { | ||
@@ -12,1 +15,2 @@ keyFor: (...args: Parameters<T>) => string; | ||
export declare function hashKey<T extends Array<any>>(args: T): string; | ||
export {}; |
@@ -29,15 +29,18 @@ import { createSignal, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js"; | ||
} | ||
export function revalidate(key) { | ||
key && !Array.isArray(key) && (key = [key]); | ||
export function revalidate(key, force = true) { | ||
return startTransition(() => { | ||
const now = Date.now(); | ||
for (let k of cacheMap.keys()) { | ||
if (key === undefined || matchKey(k, key)) { | ||
const entry = cacheMap.get(k); | ||
entry[0] = 0; //force cache miss | ||
revalidateSignals(entry[3], now); // retrigger live signals | ||
} | ||
} | ||
cacheKeyOp(key, entry => { | ||
force && (entry[0] = 0); //force cache miss | ||
revalidateSignals(entry[3], now); // retrigger live signals | ||
}); | ||
}); | ||
} | ||
export function cacheKeyOp(key, fn) { | ||
key && !Array.isArray(key) && (key = [key]); | ||
for (let k of cacheMap.keys()) { | ||
if (key === undefined || matchKey(k, key)) | ||
fn(cacheMap.get(k)); | ||
} | ||
} | ||
function revalidateSignals(set, time) { | ||
@@ -84,3 +87,3 @@ for (let s of set) | ||
// serialize on server | ||
if (isServer && (sharedConfig.context && !sharedConfig.context.noHydrate)) { | ||
if (isServer && sharedConfig.context && !sharedConfig.context.noHydrate) { | ||
const e = getRequestEvent(); | ||
@@ -138,3 +141,2 @@ (!e || !e.serverOnly) && sharedConfig.context.serialize(key, res); | ||
} | ||
; | ||
cache.set = (key, value) => { | ||
@@ -141,0 +143,0 @@ const cache = getCache(); |
@@ -771,16 +771,18 @@ import { isServer, getRequestEvent, createComponent as createComponent$1, delegateEvents, spread, mergeProps as mergeProps$1, template } from 'solid-js/web'; | ||
} | ||
function revalidate(key) { | ||
key && !Array.isArray(key) && (key = [key]); | ||
function revalidate(key, force = true) { | ||
return startTransition(() => { | ||
const now = Date.now(); | ||
for (let k of cacheMap.keys()) { | ||
if (key === undefined || matchKey(k, key)) { | ||
const entry = cacheMap.get(k); | ||
entry[0] = 0; //force cache miss | ||
revalidateSignals(entry[3], now); // retrigger live signals | ||
} | ||
} | ||
cacheKeyOp(key, entry => { | ||
force && (entry[0] = 0); //force cache miss | ||
revalidateSignals(entry[3], now); // retrigger live signals | ||
}); | ||
}); | ||
} | ||
function cacheKeyOp(key, fn) { | ||
key && !Array.isArray(key) && (key = [key]); | ||
for (let k of cacheMap.keys()) { | ||
if (key === undefined || matchKey(k, key)) fn(cacheMap.get(k)); | ||
} | ||
} | ||
function revalidateSignals(set, time) { | ||
@@ -969,3 +971,3 @@ for (let s of set) s[1](time); | ||
} | ||
const url = fn.url || name && `action:${name}` || (!isServer ? `action:${fn.name}` : ""); | ||
const url = fn.url || name && `action:${name}` || (!isServer ? `action:${hashString(fn.toString())}` : ""); | ||
return toAction(mutate, url); | ||
@@ -984,3 +986,3 @@ } | ||
uri.searchParams.set("args", hashKey(args)); | ||
return toAction(newFn, uri.pathname + uri.search); | ||
return toAction(newFn, (uri.protocol === "action:" ? uri.protocol : "") + uri.pathname + uri.search); | ||
}; | ||
@@ -994,2 +996,3 @@ fn.url = url; | ||
} | ||
const hashString = s => s.split("").reduce((a, b) => (a << 5) - a + b.charCodeAt(0) | 0, 0); | ||
async function handleResponse(response, navigate) { | ||
@@ -1001,2 +1004,4 @@ let data; | ||
keys = response.headers.get("X-Revalidate").split(","); | ||
// invalidate | ||
cacheKeyOp(keys, entry => entry[0] = 0); | ||
} | ||
@@ -1013,3 +1018,4 @@ if (response.customBody) data = await response.customBody(); | ||
} else data = response; | ||
await revalidate(keys); | ||
// trigger revalidation | ||
await revalidate(keys, false); | ||
return data; | ||
@@ -1016,0 +1022,0 @@ } |
@@ -9,3 +9,3 @@ { | ||
"license": "MIT", | ||
"version": "0.10.0-beta.9", | ||
"version": "0.10.0", | ||
"homepage": "https://github.com/solidjs/solid-router#readme", | ||
@@ -12,0 +12,0 @@ "repository": { |
@@ -7,2 +7,4 @@ <p> | ||
**Version 0.10.0 requires Solid v1.8.4 or later.** | ||
A router lets you change your view based on the URL in the browser. This allows your "single-page" application to simulate a traditional multipage site. To use Solid Router, you specify components called Routes that depend on the value of the URL (the "path"), and the router handles the mechanism of swapping them in and out. | ||
@@ -380,4 +382,6 @@ | ||
This cache can be defined anywhere and then used inside your components with: | ||
You can revalidate the cache using the `revalidate` method or you can set `revalidate` keys on your response from your actions. If you pass the whole key it will invalidate all the entries for the cache (ie "users" in the example above). You can also invalidate a single entry by using `keyFor`. | ||
`cache` can be defined anywhere and then used inside your components with: | ||
### `createAsync` | ||
@@ -395,3 +399,3 @@ | ||
Actions are data mutations that can trigger invalidations and further routing. A list of prebuilt response builders can be found below(TODO). | ||
Actions are data mutations that can trigger invalidations and further routing. A list of prebuilt response helpers can be found below. | ||
```jsx | ||
@@ -456,3 +460,3 @@ import { action, revalidate, redirect } from "@solidjs/router" | ||
The outside of a form context you can use custom data instead of formData, and these helpers preserve types. | ||
The outside of a form context you can use custom data instead of formData, and these helpers preserve types. However, even when used with server functions (in projects like SolidStart) this requires client side javascript and is not Progressive Enhancible like forms are. | ||
@@ -477,2 +481,32 @@ ### `useSubmission`/`useSubmissions` | ||
### Response Helpers | ||
These are used to communicate router navigations from cache/actions, and can include invalidation hints. Generally these are thrown to not interfere the with the types and make it clear that function ends execution at that point. | ||
#### `redirect(path, options)` | ||
Redirects to the next route | ||
```js | ||
const getUser = cache(() => { | ||
const user = await api.getCurrentUser() | ||
if (!user) throw redirect("/login"); | ||
return user; | ||
}) | ||
``` | ||
#### `reload(options)` | ||
Reloads the data on the current page | ||
```js | ||
const getTodo = cache(async (id: number) => { | ||
const todo = await fetchTodo(id); | ||
return todo; | ||
}, "todo") | ||
const updateTodo = action(async (todo: Todo) => { | ||
await updateTodo(todo.id, todo); | ||
reload({ revalidate: getTodo.keyFor(id) }) | ||
}) | ||
``` | ||
### Load Functions | ||
@@ -622,3 +656,3 @@ | ||
| children | `JSX.Element` or `RouteDefinition[]` | The route definitions | | ||
| root | Component | Top level layout comoponent | | ||
| root | Component | Top level layout component | | ||
| base | string | Base url to use for matching routes | | ||
@@ -666,3 +700,7 @@ | actionBase | string | Root url for server actions, default: `/_server` | | ||
|-|-|-| | ||
|TODO | ||
| path | string | Path partial for defining the route segment | | ||
| component | `Component` | Component that will be rendered for the matched segment | | ||
| matchFilters | `MatchFilters` | Additional constraints for matching against the route | | ||
| children | `JSX.Element` | Nested `<Route>` definitions | | ||
| load | `RouteLoadFunc` | Function called during preload or when the route is navigated to. | | ||
@@ -796,3 +834,3 @@ ## Router Primitives | ||
This is no longer used and instead will use `props.children` passed from into the page components for outlets. Nested Routes inherently cause waterfalls and are Outlets in a sense themselves. We do not want to encourage the pattern and if you must do it you can always nest `<Routers>` with appropriate base path. | ||
This is no longer used and instead will use `props.children` passed from into the page components for outlets. This keeps the outlet directly passed from its page and avoids oddness of trying to use context across Islands boundaries. Nested `<Routes>` components inherently cause waterfalls and are `<Outlets>` themselves so they have the same concerns. We do not want to encourage the pattern and if you must do it you can always nest `<Router>`s with appropriate base path. | ||
@@ -799,0 +837,0 @@ ## `element` prop removed from `Route` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
143912
3211
859