Skip to content

Commit

Permalink
0.0.9 (#11)
Browse files Browse the repository at this point in the history
* Add evictAll method
* Add createSingleEntryCache convenience wrapper
* Convert caches to use named parameters
* Update tests and documentation
  • Loading branch information
bvaughn authored Feb 27, 2023
2 parents c4fc93c + 3aec718 commit 71f1029
Show file tree
Hide file tree
Showing 33 changed files with 461 additions and 91 deletions.
File renamed without changes.
6 changes: 6 additions & 0 deletions packages/suspense-website/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BrowserRouter, Route, Routes } from "react-router-dom";
import {
CREATE_CACHE,
CREATE_DEFERRED,
CREATE_SINGLE_ENTRY_CACHE,
CREATE_STREAMING_CACHE,
EXAMPLE_ABORT_A_REQUEST,
EXAMPLE_FETCH_WITH_STATUS,
Expand All @@ -16,6 +17,7 @@ import {

import CreateCacheRoute from "./src/routes/api/createCache";
import CreateDeferredRoute from "./src/routes/api/createDeferred";
import CreateSingleEntryCacheRoute from "./src/routes/api/createSingleEntryCache";
import CreateStreamingCacheRoute from "./src/routes/api/createStreamingCache";
import HomeRoute from "./src/routes/Home";
import IsThenableRoute from "./src/routes/api/isThenable";
Expand All @@ -40,6 +42,10 @@ root.render(
<Route path="/" element={<HomeRoute />} />
<Route path={CREATE_CACHE} element={<CreateCacheRoute />} />
<Route path={CREATE_DEFERRED} element={<CreateDeferredRoute />} />
<Route
path={CREATE_SINGLE_ENTRY_CACHE}
element={<CreateSingleEntryCacheRoute />}
/>
<Route
path={CREATE_STREAMING_CACHE}
element={<CreateStreamingCacheRoute />}
Expand Down
9 changes: 4 additions & 5 deletions packages/suspense-website/root.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
--color-default: #ffffff;
--color-demo-background: #273f35;
--color-demo-button: #fff;
--color-demo-button-background: #152c23;
--color-demo-button-background-hover: #183127;
--color-demo-button-background: #0004;
--color-demo-button-background-hover: #0006;
--color-demo-contrast: #ffffff20;
--color-demo-panel: #1e332a;
--color-demo-progress-background: #111b17;
Expand All @@ -23,9 +23,8 @@
--color-dim: #d2e1f9a6;
--color-horizontal-rule: #39414d;
--color-input: #ffffff;
--color-input-background: #18181a;
--color-input-border: #39414d;
--color-input-border-focused: #dcadff;
--color-input-background: #0004;
--color-input-background-focused: #0006;
--color-link: #7ac1ff;
--color-loader: #ffffffcc;
--color-loader-background: #00000030;
Expand Down
1 change: 0 additions & 1 deletion packages/suspense-website/src/components/ScrollToTop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export default function ScrollToTop(): null {
// In all other cases, check fragment/scroll to top
if (hash) {
let element = document.querySelector(hash);
console.log("found element:", element);
if (element) {
element.scrollIntoView({ block: "start", behavior: "smooth" });
}
Expand Down
10 changes: 5 additions & 5 deletions packages/suspense-website/src/examples/createCache/cache.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createCache } from "suspense";

export const userProfileCache = createCache<[userId: string], JSON>(
async (userId: string) => {
const response = await fetch(`https://example.com/user?id=${userId}`);
export const userProfileCache = createCache<[userId: string], JSON>({
load: async (userId: string) => {
const response = await fetch(`/api/user?id=${userId}`);
const json = await response.json();
return json;
}
);
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ class ApiClient {
}

// REMOVE_BEFORE
createCache<[client: ApiClient, id: string], JSON>(
// In this example, data is loaded by a "client" object
async (client: ApiClient, id: string) => client.loadData(id),

// The id parameter is sufficiently unique to be the key
(client: ApiClient, id: string) => id
);
createCache<[client: ApiClient, id: string], JSON>({
// The "client" parameter can't be serialized to a string
// The "id" parameter is unique, so it can be the key
getKey: (client: ApiClient, id: string) => id,

// In this example, data is loaded by a "client" object
load: async (client: ApiClient, id: string) => client.loadData(id),
});
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { CacheLoadOptions, createCache } from "suspense";

// REMOVE_BEFORE
createCache<[userId: string], JSON>(
async (userId: string, options: CacheLoadOptions) => {

createCache<[userId: string], JSON>({
load: async (userId: string, options: CacheLoadOptions) => {
// An AbortSignal is passed in as the final parameter with each request
const { signal } = options;

// The native fetch API supports AbortSignals
// All that's required to support cancellation is to forward the signal
const response = await fetch(`https://example.com/user?id=${userId}`, {
const response = await fetch(`/api/user?id=${userId}`, {
signal,
});
const json = await response.json();
return json;
}
);
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createSingleEntryCache } from "suspense";

const articlesCache = createSingleEntryCache<[], JSON>({
load: async () => {
const response = await fetch(`/api/articles/?sort=DESC&limit=10`);
const json = await response.json();
return json;
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createSingleEntryCache } from "suspense";

class ApiClient {
async getRecentArticles() {
return JSON.parse("");
}
}

// REMOVE_BEFORE

createSingleEntryCache<[ApiClient], JSON>({
load: async (client: ApiClient) => client.getRecentArticles(),
});
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
type Comment = any;
type Message = any;

// REMOVE_BEFORE
import { createStreamingCache, StreamingCacheLoadOptions } from "suspense";

const socket = new WebSocket(`ws://example.com`);
const socket = new WebSocket("...");

export const userCommentsCache = createStreamingCache<
[userId: string],
Comment
>(
>({
// Stream data for params
async (options: StreamingCacheLoadOptions<Comment>, userId: string) => {
load: async (options: StreamingCacheLoadOptions<Comment>, userId: string) => {
const { reject, update, resolve } = options;

let countLoaded = 0;
Expand Down Expand Up @@ -48,5 +49,5 @@ export const userCommentsCache = createStreamingCache<
userId,
})
);
}
);
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ class ApiClient {
type Comment = any;

// REMOVE_BEFORE
createStreamingCache<[client: ApiClient, id: string], Comment>(

createStreamingCache<[client: ApiClient, id: string], Comment>({
// The "client" parameter can't be serialized to a string
// The "id" parameter is unique, so it can be the key
getKey: (client: ApiClient, id: string) => id,

// In this example, comments are fetched using a "client" object
async (
load: async (
options: StreamingCacheLoadOptions<Comment>,
client: ApiClient,
id: string
Expand All @@ -28,7 +33,4 @@ createStreamingCache<[client: ApiClient, id: string], Comment>(
() => resolve()
);
},

// The id parameter is sufficiently unique to be the key
(client: ApiClient, id: string) => id
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { createStreamingCache, StreamingCacheLoadOptions } from "suspense";
type Comment = any;

// REMOVE_BEFORE
createStreamingCache<[userId: string], Comment>(
async (options: StreamingCacheLoadOptions<Comment>, userId: string) => {

createStreamingCache<[userId: string], Comment>({
load: async (options: StreamingCacheLoadOptions<Comment>, userId: string) => {
// An AbortSignal is included in the options parameter with each request
const { signal } = options;

Expand All @@ -14,5 +15,5 @@ createStreamingCache<[userId: string], Comment>(
};

// ...
}
);
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ function getRandomUsers(): User[] {
return shuffle(users).slice(0, 5);
}

export const userProfileCache = createCache<[number], User>(
async (id: number) => {
export const userProfileCache = createCache<[number], User>({
debugLabel: "userProfileCache",
load: async (id: number) => {
return new Promise((resolve, reject) => {
const delay = 500 + Math.random() * 4_500;
setTimeout(() => {
Expand All @@ -36,8 +37,8 @@ export const userProfileCache = createCache<[number], User>(
}
}, delay);
});
}
);
},
});

export const SelectedUserContext = createContext<{
selectedUserId: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ export type Metadata = {
postCount: number;
};

const streamingCache = createStreamingCache<[Post[]], Post, Metadata>(
async (options: StreamingCacheLoadOptions<Post, Metadata>, posts: Post[]) => {
const streamingCache = createStreamingCache<[Post[]], Post, Metadata>({
load: async (
options: StreamingCacheLoadOptions<Post, Metadata>,
posts: Post[]
) => {
const { signal } = options;

for (let i = 0; i < posts.length; i++) {
Expand All @@ -40,8 +43,8 @@ const streamingCache = createStreamingCache<[Post[]], Post, Metadata>(
options.update([post], progress, { postCount: posts.length });
}
options.resolve();
}
);
},
});

export default function Demo() {
return (
Expand Down
21 changes: 20 additions & 1 deletion packages/suspense-website/src/examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ const createDeferred = {
),
};

const createSingleEntryCache = {
cache: processExample(
readFileSync(join(__dirname, "createSingleEntryCache", "cache.ts"), "utf8")
),
cacheWithParameters: processExample(
readFileSync(
join(__dirname, "createSingleEntryCache", "cacheWithParameters.ts"),
"utf8"
)
),
};

const createStreamingCache = {
abort: processExample(
readFileSync(join(__dirname, "createStreamingCache", "abort.ts"), "utf8")
Expand Down Expand Up @@ -128,4 +140,11 @@ const isThenable = {
),
};

export { createCache, createDeferred, createStreamingCache, demos, isThenable };
export {
createCache,
createDeferred,
createSingleEntryCache,
createStreamingCache,
demos,
isThenable,
};
6 changes: 6 additions & 0 deletions packages/suspense-website/src/routes/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Note from "../components/Note";
import {
CREATE_CACHE,
CREATE_DEFERRED,
CREATE_SINGLE_ENTRY_CACHE,
CREATE_STREAMING_CACHE,
EXAMPLE_ABORT_A_REQUEST,
EXAMPLE_FETCH_WITH_STATUS,
Expand Down Expand Up @@ -54,6 +55,11 @@ export default function Route() {
<SubHeading title="Core API" />
<ul>
<LinkListItem children="createCache" to={CREATE_CACHE} type="code" />
<LinkListItem
children="createSingleEntryCache"
to={CREATE_SINGLE_ENTRY_CACHE}
type="code"
/>
<LinkListItem
children="createStreamingCache"
to={CREATE_STREAMING_CACHE}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Block from "../../components/Block";
import Container from "../../components/Container";
import Code from "../../components/Code";
import { createSingleEntryCache } from "../../examples";
import Header from "../../components/Header";
import { Link } from "react-router-dom";
import { CREATE_CACHE } from "../config";

export default function Route() {
return (
<Container>
<Block>
<Header title="createSingleEntryCache" />
</Block>
<Block>
<p>
Convenience wrapper around{" "}
<code>
<Link to={CREATE_CACHE}>createCache</Link>
</code>{" "}
for caches that only contain a single value.
</p>
<Code code={createSingleEntryCache.cache} />
<p>
This type of cache can still accept parameters, although they won't be
used to store the cached value.
</p>
<Code code={createSingleEntryCache.cacheWithParameters} />
</Block>
</Container>
);
}
1 change: 1 addition & 0 deletions packages/suspense-website/src/routes/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const CREATE_CACHE = "/createCache";
export const CREATE_DEFERRED = "/createDeferred";
export const CREATE_SINGLE_ENTRY_CACHE = "/createSingleEntryCache";
export const CREATE_STREAMING_CACHE = "/createStreamingCache";
export const IS_THENNABLE = "/isThenable";
export const USE_CACHE_STATUS = "/useCacheStatus";
Expand Down
29 changes: 16 additions & 13 deletions packages/suspense-website/src/suspense/ImportCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ type Module = any;
export const {
fetchAsync: fetchModuleAsync,
fetchSuspense: fetchModuleSuspense,
} = createCache<[string], Module>(async (path: string) => {
switch (path) {
case "@codemirror/lang-css":
return await import("@codemirror/lang-css");
case "@codemirror/lang-html":
return await import("@codemirror/lang-html");
case "@codemirror/lang-javascript":
return await import("@codemirror/lang-javascript");
case "@codemirror/lang-markdown":
return await import("@codemirror/lang-markdown");
default:
throw Error(`Unknown path: ${path}`);
}
} = createCache<[string], Module>({
debugLabel: "ImportCache",
load: async (path: string) => {
switch (path) {
case "@codemirror/lang-css":
return await import("@codemirror/lang-css");
case "@codemirror/lang-html":
return await import("@codemirror/lang-html");
case "@codemirror/lang-javascript":
return await import("@codemirror/lang-javascript");
case "@codemirror/lang-markdown":
return await import("@codemirror/lang-markdown");
default:
throw Error(`Unknown path: ${path}`);
}
},
});
Loading

1 comment on commit 71f1029

@vercel
Copy link

@vercel vercel bot commented on 71f1029 Feb 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.