From 214a6ed036930c362a2ac07e1a18fa94556fbe70 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Tue, 7 Nov 2023 14:54:37 -0600 Subject: [PATCH] Don't load all docs just to render the sidebar. In order to render 1 doc, you need to load them all. This is because the `title` attribute of each guide is stored inside the doc itself within the YAML frontmatter. Which means in order to render the title in the side bar, you have to load and parse all of the the documents. This pops the title into `structure.json`. That way, we can construct all the doc metadata without ever having to load or parse anything but the document that is being requested. This actually simplifies things considerably, as we can now hang the list of topics on the doc itself which means no need for a separate `getTopics()` operation, and no need to maintain a document context. --- www/deno.lock | 64 --------------------- www/docs/actions.mdx | 4 -- www/docs/collections.mdx | 4 -- www/docs/docs.ts | 115 +++++++++++++++++-------------------- www/docs/errors.mdx | 4 -- www/docs/events.mdx | 4 -- www/docs/inspector.mdx | 4 -- www/docs/introduction.mdx | 4 -- www/docs/operations.mdx | 4 -- www/docs/processes.mdx | 4 -- www/docs/resources.mdx | 4 -- www/docs/scope.mdx | 4 -- www/docs/spawn.mdx | 4 -- www/docs/structure.json | 26 ++++----- www/docs/testing.mdx | 4 -- www/docs/typescript.mdx | 4 -- www/html/document.html.tsx | 13 ++--- www/server.ts | 3 +- 18 files changed, 71 insertions(+), 202 deletions(-) diff --git a/www/deno.lock b/www/deno.lock index 674bacf94..32d9d78a9 100644 --- a/www/deno.lock +++ b/www/deno.lock @@ -14,9 +14,7 @@ "npm:rehype-autolink-headings@6.1.1": "npm:rehype-autolink-headings@6.1.1", "npm:rehype-prism-plus@1.5.1": "npm:rehype-prism-plus@1.5.1", "npm:rehype-slug@5.1.0": "npm:rehype-slug@5.1.0", - "npm:remark-frontmatter@4.0.1": "npm:remark-frontmatter@4.0.1", "npm:remark-gfm@3.0.1": "npm:remark-gfm@3.0.1", - "npm:remark-mdx-frontmatter@3.0.0": "npm:remark-mdx-frontmatter@3.0.0", "npm:route-recognizer@0.3.4": "npm:route-recognizer@0.3.4", "npm:unified@10.1.2": "npm:unified@10.1.2" }, @@ -287,13 +285,6 @@ "source-map": "source-map@0.7.4" } }, - "estree-util-value-to-estree@3.0.1": { - "integrity": "sha512-b2tdzTurEIbwRh+mKrEcaWfu1wgb8J1hVsgREg7FFiecWwK/PhO8X0kyc+0bIcKNtD4sqxIdNoRy6/p/TvECEA==", - "dependencies": { - "@types/estree": "@types/estree@1.0.4", - "is-plain-obj": "is-plain-obj@4.1.0" - } - }, "estree-util-visit@1.2.1": { "integrity": "sha512-xbgqcrkIVbIG+lI/gzbvd9SGTJL4zqJKBFttUl5pP27KhAjtMKbX/mQXJ7qgyXpMgVy/zvpm0xoQQaGL8OloOw==", "dependencies": { @@ -311,16 +302,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dependencies": {} }, - "fault@2.0.1": { - "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", - "dependencies": { - "format": "format@0.2.2" - } - }, - "format@0.2.2": { - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", - "dependencies": {} - }, "github-slugger@2.0.0": { "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "dependencies": {} @@ -634,14 +615,6 @@ "uvu": "uvu@0.5.6" } }, - "mdast-util-frontmatter@1.0.1": { - "integrity": "sha512-JjA2OjxRqAa8wEG8hloD0uTU0kdn8kbtOWpPP94NBkfAlbxn4S8gCGf/9DwFtEeGPXrDcNXdiDjVaRdUFqYokw==", - "dependencies": { - "@types/mdast": "@types/mdast@3.0.14", - "mdast-util-to-markdown": "mdast-util-to-markdown@1.5.0", - "micromark-extension-frontmatter": "micromark-extension-frontmatter@1.1.1" - } - }, "mdast-util-gfm-autolink-literal@1.0.3": { "integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==", "dependencies": { @@ -814,15 +787,6 @@ "uvu": "uvu@0.5.6" } }, - "micromark-extension-frontmatter@1.1.1": { - "integrity": "sha512-m2UH9a7n3W8VAH9JO9y01APpPKmNNNs71P0RbknEmYSaZU5Ghogv38BYO94AI5Xw6OYfxZRdHZZ2nYjs/Z+SZQ==", - "dependencies": { - "fault": "fault@2.0.1", - "micromark-util-character": "micromark-util-character@1.2.0", - "micromark-util-symbol": "micromark-util-symbol@1.1.0", - "micromark-util-types": "micromark-util-types@1.1.0" - } - }, "micromark-extension-gfm-autolink-literal@1.0.5": { "integrity": "sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==", "dependencies": { @@ -1287,15 +1251,6 @@ "unist-util-visit": "unist-util-visit@4.1.2" } }, - "remark-frontmatter@4.0.1": { - "integrity": "sha512-38fJrB0KnmD3E33a5jZC/5+gGAC2WKNiPw1/fdXJvijBlhA7RCsvJklrYJakS0HedninvaCYW8lQGf9C918GfA==", - "dependencies": { - "@types/mdast": "@types/mdast@3.0.14", - "mdast-util-frontmatter": "mdast-util-frontmatter@1.0.1", - "micromark-extension-frontmatter": "micromark-extension-frontmatter@1.1.1", - "unified": "unified@10.1.2" - } - }, "remark-gfm@3.0.1": { "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", "dependencies": { @@ -1305,17 +1260,6 @@ "unified": "unified@10.1.2" } }, - "remark-mdx-frontmatter@3.0.0": { - "integrity": "sha512-Tnkz8n/fxZGKMBaFJa5jKumJPpuTr9eZF+u+4UcnlUNmUQP3h8ZwgaTzIvkVb6QjG6QE0itsP5JjWnkEBz8IJw==", - "dependencies": { - "@types/mdast": "@types/mdast@3.0.14", - "estree-util-is-identifier-name": "estree-util-is-identifier-name@2.1.0", - "estree-util-value-to-estree": "estree-util-value-to-estree@3.0.1", - "toml": "toml@3.0.0", - "unified": "unified@10.1.2", - "yaml": "yaml@2.3.3" - } - }, "remark-mdx@2.3.0": { "integrity": "sha512-g53hMkpM0I98MU266IzDFMrTD980gNF3BJnkyFcmN+dD873mQeD5rdMO3Y2X+x8umQfbSE0PcoEDl7ledSA+2g==", "dependencies": { @@ -1375,10 +1319,6 @@ "inline-style-parser": "inline-style-parser@0.1.1" } }, - "toml@3.0.0": { - "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", - "dependencies": {} - }, "trim-lines@3.0.1": { "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", "dependencies": {} @@ -1548,10 +1488,6 @@ "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", "dependencies": {} }, - "yaml@2.3.3": { - "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", - "dependencies": {} - }, "zwitch@1.0.5": { "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", "dependencies": {} diff --git a/www/docs/actions.mdx b/www/docs/actions.mdx index 3be8ef90e..935e10cf0 100644 --- a/www/docs/actions.mdx +++ b/www/docs/actions.mdx @@ -1,7 +1,3 @@ ---- -title: Actions and Suspensions ---- - In this section, we'll cover the first two fundamental operations in Effection: `suspend()` and `action()`, and how we can use them in tandem to serve as a safe alternative to the [Promise constructor][promise-constructor]. diff --git a/www/docs/collections.mdx b/www/docs/collections.mdx index 7892a3dab..4a559771e 100644 --- a/www/docs/collections.mdx +++ b/www/docs/collections.mdx @@ -1,7 +1,3 @@ ---- -title: Streams and Subscriptions ---- - For every tool in the `async/await` toolbox, there is an equilavent in Effection. We were already introduced to the most important of these in [the introduction][introduction]. diff --git a/www/docs/docs.ts b/www/docs/docs.ts index 5df963210..4a0c8aff6 100644 --- a/www/docs/docs.ts +++ b/www/docs/docs.ts @@ -1,10 +1,8 @@ -import { createContext, all, call, spawn, type Operation, type Task } from "effection"; +import { call, spawn, type Operation, type Task } from "effection"; import structure from "./structure.json" assert { type: "json" }; import { basename } from "https://deno.land/std@0.205.0/path/posix/basename.ts"; -import remarkFrontmatter from "npm:remark-frontmatter@4.0.1"; -import remarkMdxFrontmatter from "npm:remark-mdx-frontmatter@3.0.0"; import remarkGfm from "npm:remark-gfm@3.0.1"; import rehypePrismPlus from "npm:rehype-prism-plus@1.5.1"; @@ -12,9 +10,6 @@ import { evaluate } from "npm:@mdx-js/mdx@2.3.0"; import { Fragment, jsx, jsxs } from "hastx/jsx-runtime"; -export const Docs = createContext("docs"); -export const useDocs = () => Docs; - export interface DocModule { default: () => JSX.Element; frontmatter: { @@ -24,22 +19,25 @@ export interface DocModule { } export interface Docs { - getTopics(): Operation; getDoc(id?: string): Operation; } export interface Topic { name: string; - items: Doc[]; + items: DocMeta[]; } -export interface Doc { +export interface DocMeta { id: string; title: string; - MDXContent: () => JSX.Element; filename: string; - nextId?: string; - previousId?: string; + topics: Topic[]; + next?: DocMeta; + prev?: DocMeta; +} + +export interface Doc extends DocMeta { + MDXContent: () => JSX.Element; } export function* loadDocs(): Operation { @@ -48,63 +46,54 @@ export function* loadDocs(): Operation { let entries = Object.entries(structure); - let topics = entries.map(([name]) => ({ name, items: []}) as Topic) - - let topicsByName = new Map(topics.map(topic => [topic.name, topic])); - - let files = entries.flatMap(([topicName, files]) => { - return files.map((filename, topicIndex) => ({ topicName, topicIndex, filename, id: basename(filename, ".mdx") })); - }) - - for (let i = 0; i < files.length; i++ ) { - let file = files[i]; - let nextId = files[i + 1]?.id; - let previousId = files[i - 1]?.id; - let { topicName, topicIndex, filename, id } = file; - let location = new URL(filename, import.meta.url); - - loaders.set(id, yield* spawn(function*() { - let source = yield* call(Deno.readTextFile(location)); - let mod = yield* call(evaluate(source, { - jsx, - jsxs, - jsxDEV: jsx, - Fragment, - remarkPlugins: [ - remarkFrontmatter, - remarkMdxFrontmatter, - remarkGfm, - ], - rehypePlugins: [ - [rehypePrismPlus, { showLineNumbers: true }], - ], - })); + let topics: Topic[] = []; - let { title } = mod.frontmatter as { id: string; title: string }; + for (let [name, contents] of entries) { + let topic: Topic = { name, items: [] }; + topics.push(topic); - let doc: Doc = { - id, - nextId, - previousId, + let current: DocMeta | undefined = void(0); + for (let i = 0; i < contents.length; i++) { + let prev: DocMeta | undefined = current; + let [filename, title] = contents[i]; + let meta: DocMeta = current = { + id: basename(filename, ".mdx"), title, filename, - MDXContent: () => mod.default({}), - } as Doc; - - let topic = topicsByName.get(topicName); - - topic!.items[topicIndex] = doc; - - return doc; - })); + topics, + prev + }; + if (prev) { + prev.next = current; + } + topic.items.push(current); + + loaders.set(meta.id, yield* spawn(function*() { + let location = new URL(filename, import.meta.url); + let source = yield* call(Deno.readTextFile(location)); + let mod = yield* call(evaluate(source, { + jsx, + jsxs, + jsxDEV: jsx, + Fragment, + remarkPlugins: [ + remarkGfm, + ], + rehypePlugins: [ + [rehypePrismPlus, { showLineNumbers: true }], + ], + })); + + return { + ...meta, + MDXContent: () => mod.default({}), + } as Doc; + })); + } } - return yield* Docs.set({ - *getTopics() { - yield* all([...loaders.values()]); - return topics; - }, + return { *getDoc(id) { if (id) { let task = loaders.get(id); @@ -113,5 +102,5 @@ export function* loadDocs(): Operation { } } }, - }); + }; } diff --git a/www/docs/errors.mdx b/www/docs/errors.mdx index 87d84607a..b2625084b 100644 --- a/www/docs/errors.mdx +++ b/www/docs/errors.mdx @@ -1,7 +1,3 @@ ---- -title: Errors ---- - We have previously discussed how correctness and proper handling of failure cases is why we wrote Effection in the first place. In this chapter we will take a more in-depth look at how Effection handles failures and how you can diff --git a/www/docs/events.mdx b/www/docs/events.mdx index 6a14cf1fb..4734626ec 100644 --- a/www/docs/events.mdx +++ b/www/docs/events.mdx @@ -1,7 +1,3 @@ ---- -title: Events ---- - Asynchronous code often needs to interact with evented code. Using `async/await` this can be quite challenging. Evented code often needs to be synchronous, because the timing of when to subscribe and diff --git a/www/docs/inspector.mdx b/www/docs/inspector.mdx index 2ca4e8d84..0f4fc0829 100644 --- a/www/docs/inspector.mdx +++ b/www/docs/inspector.mdx @@ -1,7 +1,3 @@ ---- -title: Inspector ---- - >⚠️ These docs have not been updated from version 2 of Effection, and do not > apply to version 3. The information you find here may be of use, but may > also be outdated or misleading. diff --git a/www/docs/introduction.mdx b/www/docs/introduction.mdx index e59f86918..9a32b2e54 100644 --- a/www/docs/introduction.mdx +++ b/www/docs/introduction.mdx @@ -1,7 +1,3 @@ ---- -title: Introduction ---- - ## Why use Effection? JavaScript has gone through multiple evolutionary steps in how to deal diff --git a/www/docs/operations.mdx b/www/docs/operations.mdx index 07c22c966..a5cb1988b 100644 --- a/www/docs/operations.mdx +++ b/www/docs/operations.mdx @@ -1,7 +1,3 @@ ---- -title: Operations ---- - In the introduction, we saw how to replace `async/await` by writing equivalent code in Effection. We can do this because there are strong analogues between the way both systems work. However, there are also two key differences that diff --git a/www/docs/processes.mdx b/www/docs/processes.mdx index c2d841814..07aab38c5 100644 --- a/www/docs/processes.mdx +++ b/www/docs/processes.mdx @@ -1,7 +1,3 @@ ---- -title: Spawning processes ---- - >⚠️ These docs have not been updated from version 2 of Effection, and do not > apply to version 3. The information you find here may be of use, but may > also be outdated or misleading. diff --git a/www/docs/resources.mdx b/www/docs/resources.mdx index 85529782d..a25fc2d19 100644 --- a/www/docs/resources.mdx +++ b/www/docs/resources.mdx @@ -1,7 +1,3 @@ ---- -title: Resources ---- - The third fundamental Effection operation is [`resource()`][resource]. It can seem a little complicated at first, but the reason for its existence is rather simple. Sometimes there are operations which meet the following criteria: diff --git a/www/docs/scope.mdx b/www/docs/scope.mdx index 7e8d45ff3..1d1077449 100644 --- a/www/docs/scope.mdx +++ b/www/docs/scope.mdx @@ -1,7 +1,3 @@ ---- -title: Scope ---- - We have talked about how Effection operations allow you to bundle setup and teardown as a unit so that automatic cleanup is _guaranteed_, but how are they able to do this, and how can you implement your own operations that clean diff --git a/www/docs/spawn.mdx b/www/docs/spawn.mdx index 72bf30ffb..ec0350ff4 100644 --- a/www/docs/spawn.mdx +++ b/www/docs/spawn.mdx @@ -1,7 +1,3 @@ ---- -title: Spawn ---- - Suppose we are using the `fetchWeekDay` function from the introduction to fetch the current weekday in multiple timezones: ``` javascript diff --git a/www/docs/structure.json b/www/docs/structure.json index bcf0db574..53a51faa2 100644 --- a/www/docs/structure.json +++ b/www/docs/structure.json @@ -1,19 +1,19 @@ { "Getting Started": [ - "introduction.mdx", - "operations.mdx", - "actions.mdx", - "resources.mdx", - "spawn.mdx", - "collections.mdx", - "events.mdx", - "errors.mdx", - "typescript.mdx" + ["introduction.mdx", "Introduction"], + ["operations.mdx", "Operations"], + ["actions.mdx", "Actions and Suspensions"], + ["resources.mdx", "Resources"], + ["spawn.mdx", "Spawn"], + ["collections.mdx", "Streams and Subscriptions"], + ["events.mdx", "Events"], + ["errors.mdx", "Error Handling"], + ["typescript.mdx", "TypeScript"] ], "Advanced": [ - "scope.mdx", - "testing.mdx", - "inspector.mdx", - "processes.mdx" + ["scope.mdx", "Scope"], + ["testing.mdx", "Testing"], + ["inspector.mdx", "Inspector"], + ["processes.mdx", "Processes"] ] } diff --git a/www/docs/testing.mdx b/www/docs/testing.mdx index 47d408477..928d3d368 100644 --- a/www/docs/testing.mdx +++ b/www/docs/testing.mdx @@ -1,7 +1,3 @@ ---- -title: Testing ---- - >⚠️ These docs have not been updated from version 2 of Effection, and do not > apply to version 3. The information you find here may be of use, but may > also be outdated or misleading. diff --git a/www/docs/typescript.mdx b/www/docs/typescript.mdx index e2a8e0668..2cf8e1ce6 100644 --- a/www/docs/typescript.mdx +++ b/www/docs/typescript.mdx @@ -1,7 +1,3 @@ ---- -title: TypeScript ---- - >⚠️ These docs have not been updated from version 2 of Effection, and do not > apply to version 3. The information you find here may be of use, but may > also be outdated or misleading.q diff --git a/www/html/document.html.tsx b/www/html/document.html.tsx index cc3dce7e1..507d72381 100644 --- a/www/html/document.html.tsx +++ b/www/html/document.html.tsx @@ -1,6 +1,5 @@ import type { Operation } from "effection"; -import type { Doc } from "../docs/docs.ts"; -import { useDocs } from "../docs/docs.ts"; +import type { Doc, DocMeta } from "../docs/docs.ts"; import { Navburger } from "./components/navburger.tsx"; import { Rehype } from "./components/rehype.tsx"; @@ -10,10 +9,7 @@ import rehypeAddClasses from "npm:rehype-add-classes@1.0.0"; import rehypeToc from "npm:@jsdevtools/rehype-toc@3.0.2"; export default function* (doc: Doc): Operation { - let docs = yield* useDocs(); - let topics = yield* docs.getTopics(); - let next = yield* docs.getDoc(doc.nextId); - let prev = yield* docs.getDoc(doc.previousId); + let { topics } = doc; return (
@@ -116,14 +112,15 @@ export default function* (doc: Doc): Operation { > - +
); } -function NextPrevLinks({ next, prev }: { next?: Doc, prev?: Doc }): JSX.Element { +function NextPrevLinks({ doc }: { doc: DocMeta }): JSX.Element { + let { next, prev } = doc; return ( {prev diff --git a/www/server.ts b/www/server.ts index 4af1885b1..1da59b807 100644 --- a/www/server.ts +++ b/www/server.ts @@ -1,7 +1,7 @@ import { serve } from "freejack/server.ts"; import { html } from "freejack/html.ts"; import { render } from "freejack/view.ts"; -import { Docs, loadDocs } from "./docs/docs.ts"; +import { loadDocs } from "./docs/docs.ts"; import { useV2Docs } from "./hooks/use-v2-docs.ts"; import { AppHtml, DocumentHtml, IndexHtml } from "./html/templates.ts"; @@ -13,7 +13,6 @@ export default function* start() { }); let docs = yield* loadDocs(); - yield* Docs.set(docs); return yield* serve({ "/": html.get(function* () {