From 082d94314cb9e29bb90bb6db3273701e9d1546c5 Mon Sep 17 00:00:00 2001
From: danwood <118035379+Floating-Y@users.noreply.github.com>
Date: Mon, 26 Oct 2026 20:28:53 +0800
Subject: [PATCH] Defer block source loading until its Code panel opens
Signed-off-by: danwood <118035379+Floating-Y@users.noreply.github.com>
---
.github/workflows/checks.yml | 2 +-
scripts/block-sources.test.mjs | 116 +++++++++++++++++++++++++++++++++
src/App.tsx | 2 +-
src/blocks/index.ts | 77 ++++------------------
src/blocks/source.ts | 71 ++++++++++++++++++++
src/pages/blocks.tsx | 83 ++++++++++++++++-------
6 files changed, 261 insertions(+), 90 deletions(-)
create mode 100644 scripts/block-sources.test.mjs
create mode 100644 src/blocks/source.ts
diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index 39def38..6f919a4 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -26,7 +26,7 @@ jobs:
node-version: 22
cache: npm
- run: npm ci
- - run: node --test scripts/block-metadata.test.mjs
+ - run: node --test scripts/block-metadata.test.mjs scripts/block-sources.test.mjs
# the documentation and the registry are generated: the types of what renders them depend on them
- run: npm run docs
- name: The registry is as committed
diff --git a/scripts/block-sources.test.mjs b/scripts/block-sources.test.mjs
new file mode 100644
index 0000000..5ef5225
--- /dev/null
+++ b/scripts/block-sources.test.mjs
@@ -0,0 +1,116 @@
+import assert from "node:assert/strict"
+import { readFileSync } from "node:fs"
+import test from "node:test"
+import vm from "node:vm"
+import ts from "typescript"
+
+// Replace only Vite's glob boundary; run the real registry and source loader without a browser.
+function loadModule(path, glob, require = () => { throw new Error("Unexpected module import") }) {
+ const source = readFileSync(new URL(path, import.meta.url), "utf8")
+ const { outputText } = ts.transpileModule(source.replaceAll("import.meta.glob", "glob"), {
+ compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 },
+ })
+ const exports = {}
+ vm.runInNewContext(outputText, { exports, glob, require }, { filename: path })
+ return exports
+}
+
+function sourceModule(fixtures) {
+ const calls = []
+ const sources = Object.fromEntries(Object.entries(fixtures).map(([path, source]) => [path, async () => {
+ calls.push(path)
+ return typeof source === "function" ? source() : source
+ }]))
+ const module = loadModule("../src/blocks/source.ts", (_patterns, options) => {
+ assert.equal(options.query, "?raw")
+ assert.notEqual(options.eager, true)
+ return sources
+ })
+ return { ...module, calls }
+}
+
+test("initializing the registry and loading a preview never imports raw sources", async () => {
+ const previewCalls = []
+ let sourceImports = 0
+ const { blocks } = loadModule("../src/blocks/index.ts", (_patterns, options) => {
+ assert.notEqual(options?.query, "?raw")
+ return new Proxy({}, { get: (_target, path) => async () => {
+ previewCalls.push(path)
+ return { default: () => null }
+ } })
+ }, (name) => {
+ if (name === "react") return { lazy: (load) => ({ load }) }
+ if (name === "./source") {
+ sourceImports++
+ return { loadBlockSource: async (name) => ({ files: [{ path: `${name}.tsx`, source: "code" }] }) }
+ }
+ throw new Error(`Unexpected module import: ${name}`)
+ })
+ assert.equal(sourceImports, 0)
+ assert.deepEqual(previewCalls, [])
+ const selected = blocks.find((block) => block.name === "sidebar-07")
+ await selected.component.load()
+ assert.deepEqual(previewCalls, ["/src/blocks/sidebar-07/page.tsx"])
+ assert.equal(sourceImports, 0)
+ const code = await selected.loadSource()
+ assert.equal(sourceImports, 1)
+ assert.equal(code.files[0].path, "sidebar-07.tsx")
+})
+
+test("Code loads only its block and overview, preserving file order and copied paths", async () => {
+ const { loadBlockSource, calls } = sourceModule({
+ "/src/blocks/sidebar-07/components/z.tsx": 'import A from "@/blocks/sidebar-07/components/a"',
+ "/src/blocks/sidebar-07/page.tsx": 'export const iframeHeight = "800px"\n\nexport const description = "Preview"\n\nimport Overview from "@/blocks/shared/overview"\nimport Sidebar from "@/blocks/sidebar-07/components/a"\nexport default Sidebar',
+ "/src/blocks/sidebar-07/components/a.tsx": "export const description = 'Keep component exports'\n",
+ "/src/blocks/sidebar-07/data.json": '{"rows": []}',
+ "/src/blocks/shared/overview.tsx": 'export default function Overview() { return "overview" }',
+ "/src/blocks/login-04/page.tsx": "Must not load",
+ "/src/blocks/agent-workspace.tsx": "Must not load",
+ })
+ assert.deepEqual(calls, [])
+ const result = await loadBlockSource("sidebar-07")
+ assert.deepEqual(Array.from(result.files, (file) => file.path), [
+ "page.tsx", "components/a.tsx", "components/z.tsx", "data.json", "shared/overview.tsx",
+ ])
+ assert.equal(result.files[0].source, 'import Overview from "@/shared/overview"\nimport Sidebar from "@/components/a"\nexport default Sidebar')
+ assert.equal(result.files[1].source, "export const description = 'Keep component exports'\n")
+ assert.equal(result.files[2].source, 'import A from "@/components/a"')
+ assert.equal(result.files[3].source, '{"rows": []}')
+ assert.match(result.note, /empty boxes.*/)
+ assert.equal(calls.length, 5)
+ assert.ok(calls.every((path) => path.startsWith("/src/blocks/sidebar-07/") || path === "/src/blocks/shared/overview.tsx"))
+ assert.strictEqual(await loadBlockSource("sidebar-07"), result)
+ assert.equal(calls.length, 5)
+})
+
+test("own blocks retain their install path and successful concurrent loads are reused", async () => {
+ const original = 'import Panel from "@/components/ui/panel"\nexport default Panel'
+ const { loadBlockSource, calls } = sourceModule({
+ "/src/blocks/agent-workspace.tsx": original,
+ "/src/blocks/login-04/page.tsx": "Must not load",
+ })
+ const [first, second] = await Promise.all([
+ loadBlockSource("agent-workspace", true), loadBlockSource("agent-workspace", true),
+ ])
+ assert.strictEqual(first, second)
+ assert.deepEqual(Array.from(first.files, (file) => file.path), ["components/agent-workspace.tsx"])
+ assert.equal(first.files[0].source, original)
+ assert.equal(first.note, undefined)
+ assert.deepEqual(calls, ["/src/blocks/agent-workspace.tsx"])
+})
+
+test("failed source loads reject and allow a later retry", async () => {
+ let attempts = 0
+ const { loadBlockSource, calls } = sourceModule({
+ "/src/blocks/login-04/page.tsx": () => {
+ if (++attempts === 1) throw new Error("Network unavailable")
+ return "export default function Login() {}"
+ },
+ "/src/blocks/sidebar-07/page.tsx": "Must not load",
+ })
+ await assert.rejects(loadBlockSource("login-04"), /Network unavailable/)
+ const result = await loadBlockSource("login-04")
+ assert.equal(result.files[0].source, "export default function Login() {}")
+ assert.equal(result.note, undefined)
+ assert.deepEqual(calls, ["/src/blocks/login-04/page.tsx", "/src/blocks/login-04/page.tsx"])
+})
diff --git a/src/App.tsx b/src/App.tsx
index 3d75d39..80849d4 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -16,7 +16,7 @@ const DocPage = React.lazy(() => import("@/site/docs").then((page) => ({ default
const DevExamples = import.meta.env.DEV
? React.lazy(() => import("@/pages/dev-examples").then((page) => ({ default: page.DevExamples })))
: null
-// The blocks carry their own source to show it: fetched with the Blocks page, not with every page.
+// Preview components and Code sources are fetched separately, when each is opened.
const Blocks = React.lazy(() => import("@/pages/blocks").then((page) => ({ default: page.Blocks })))
const BlockView = React.lazy(() => import("@/pages/block-view"))
diff --git a/src/blocks/index.ts b/src/blocks/index.ts
index f3cdfa9..a34b5ab 100644
--- a/src/blocks/index.ts
+++ b/src/blocks/index.ts
@@ -1,4 +1,5 @@
import * as React from "react";
+import type { BlockSource } from "./source";
/**
* The blocks: whole screens made of the components. A block is shown on the Blocks page in a frame
@@ -19,78 +20,26 @@ export type Block = {
own?: boolean;
/** How tall a window it is shown in. */
height?: number;
- /** Said beside the code, where what is shown is not quite what the command installs. */
- note?: string;
- files: { path: string; source: string }[];
+ loadSource: () => Promise;
component: React.LazyExoticComponent;
};
-const sources = import.meta.glob(
- ["/src/blocks/**/*.tsx", "/src/blocks/**/*.json"],
- { query: "?raw", import: "default", eager: true },
-);
const pages = import.meta.glob<{ default: React.ComponentType }>([
"/src/blocks/*.tsx",
"/src/blocks/*/page.tsx",
]);
-/** The files a block is made of, the page first. */
-function filesOf(name: string, own?: boolean) {
- if (own)
- return [
- {
- path: `components/${name}.tsx`,
- source: sources[`/src/blocks/${name}.tsx`],
- },
- ];
- const prefix = `/src/blocks/${name}/`;
- const files = Object.keys(sources)
- .filter((path) => path.startsWith(prefix))
- .map((path) => ({ path: path.slice(prefix.length), source: sources[path] }))
- .sort(
- (a, b) =>
- Number(b.path === "page.tsx") - Number(a.path === "page.tsx") ||
- a.path.localeCompare(b.path),
- );
- // The page that fills a sidebar block's empty boxes is shared by them, and shown with each.
- if (files[0]?.source.includes(OVERVIEW))
- files.push({
- path: "shared/overview.tsx",
- source: sources["/src/blocks/shared/overview.tsx"],
- });
- // Previews use the site's block folders; copied files live at the paths shown above.
- return files.map((file) => ({
- ...file,
- // Upstream preview metadata is not a supported Next App Router page export.
- source: (file.path === "page.tsx"
- ? file.source.replace(/^export const (?:iframeHeight|description) = [^\n]*\n\n?/gm, "")
- : file.source)
- .replaceAll(`@/blocks/${name}/`, "@/")
- .replaceAll("@/blocks/shared/", "@/shared/"),
- }));
-}
-
-const OVERVIEW = "@/blocks/shared/overview";
-const FILLED =
- "From shadcn/ui the page comes with empty boxes where this one has : a page of Solid Glass's own, shown with the block's files.";
-
-const block = (entry: Omit): Block => {
- const files = filesOf(entry.name, entry.own);
- return {
- ...entry,
- note: files.some((file) => file.path === "shared/overview.tsx")
- ? FILLED
- : undefined,
- files,
- component: React.lazy(
- pages[
- entry.own
- ? `/src/blocks/${entry.name}.tsx`
- : `/src/blocks/${entry.name}/page.tsx`
- ],
- ),
- };
-};
+const block = (entry: Omit): Block => ({
+ ...entry,
+ loadSource: () => import("./source").then((module) => module.loadBlockSource(entry.name, entry.own)),
+ component: React.lazy(
+ pages[
+ entry.own
+ ? `/src/blocks/${entry.name}.tsx`
+ : `/src/blocks/${entry.name}/page.tsx`
+ ],
+ ),
+});
export const blocks: Block[] = [
block({
diff --git a/src/blocks/source.ts b/src/blocks/source.ts
new file mode 100644
index 0000000..a5ae5db
--- /dev/null
+++ b/src/blocks/source.ts
@@ -0,0 +1,71 @@
+export type BlockSource = {
+ files: { path: string; source: string }[];
+ /** Said beside the code, where what is shown is not quite what the command installs. */
+ note?: string;
+};
+
+const sources = import.meta.glob(
+ ["/src/blocks/**/*.tsx", "/src/blocks/**/*.json"],
+ { query: "?raw", import: "default" },
+);
+const cache = new Map>();
+const OVERVIEW = "@/blocks/shared/overview";
+const FILLED =
+ "From shadcn/ui the page comes with empty boxes where this one has : a page of Solid Glass's own, shown with the block's files.";
+
+/** The files a block is made of, fetched only when its Code panel opens. */
+async function filesOf(name: string, own?: boolean): Promise {
+ if (own)
+ return {
+ files: [{
+ path: `components/${name}.tsx`,
+ source: await sources[`/src/blocks/${name}.tsx`](),
+ }],
+ };
+
+ const prefix = `/src/blocks/${name}/`;
+ const paths = Object.keys(sources)
+ .filter((path) => path.startsWith(prefix))
+ .sort(
+ (a, b) =>
+ Number(b === `${prefix}page.tsx`) - Number(a === `${prefix}page.tsx`) ||
+ a.localeCompare(b),
+ );
+ const files = await Promise.all(paths.map(async (path) => ({
+ path: path.slice(prefix.length),
+ source: await sources[path](),
+ })));
+ // The page that fills a sidebar block's empty boxes is shared by them, and shown with each.
+ const filled = files[0]?.source.includes(OVERVIEW);
+ if (filled)
+ files.push({
+ path: "shared/overview.tsx",
+ source: await sources["/src/blocks/shared/overview.tsx"](),
+ });
+
+ return {
+ note: filled ? FILLED : undefined,
+ // Previews use the site's block folders; copied files live at the paths shown here.
+ files: files.map((file) => ({
+ ...file,
+ // Upstream preview metadata is not a supported Next App Router page export.
+ source: (file.path === "page.tsx"
+ ? file.source.replace(/^export const (?:iframeHeight|description) = [^\n]*\n\n?/gm, "")
+ : file.source)
+ .replaceAll(`@/blocks/${name}/`, "@/")
+ .replaceAll("@/blocks/shared/", "@/shared/"),
+ })),
+ };
+}
+
+export function loadBlockSource(name: string, own?: boolean): Promise {
+ const cached = cache.get(name);
+ if (cached) return cached;
+ const pending = filesOf(name, own).catch((error: unknown) => {
+ // A failed request must not poison the next attempt.
+ cache.delete(name);
+ throw error;
+ });
+ cache.set(name, pending);
+ return pending;
+}
diff --git a/src/pages/blocks.tsx b/src/pages/blocks.tsx
index fa2059d..79879ec 100644
--- a/src/pages/blocks.tsx
+++ b/src/pages/blocks.tsx
@@ -4,6 +4,7 @@ import { Link } from "react-router-dom"
import { cn } from "@/lib/utils"
import { blocks, type Block } from "@/blocks"
+import type { BlockSource } from "@/blocks/source"
import { Button, buttonVariants } from "@/components/ui/button"
import { StatusGlyph } from "@/components/ui/status-glyph"
import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard"
@@ -19,6 +20,63 @@ const WIDTHS = [
{ name: "Mobile", icon: SmartphoneIcon, width: "390px" },
]
+/** Mounted only while Code is visible; leaving the panel ignores any pending result. */
+function BlockCode({ block, file, setFile }: {
+ block: Block
+ file: number
+ setFile: (index: number) => void
+}) {
+ const [source, setSource] = React.useState()
+ const [failed, setFailed] = React.useState(false)
+ const [attempt, setAttempt] = React.useState(0)
+
+ React.useEffect(() => {
+ let active = true
+ setSource(undefined)
+ setFailed(false)
+ block.loadSource().then(
+ (loaded) => { if (active) setSource(loaded) },
+ () => { if (active) setFailed(true) },
+ )
+ return () => { active = false }
+ }, [block, attempt])
+
+ if (failed) return (
+
+
Could not load this block's source.
+
+
+ )
+ if (!source) return
Loading sourceā¦
+
+ return (
+
+ {source.note &&
{source.note}
}
+ {source.files.length > 1 && (
+
+ {source.files.map((entry, index) => (
+
+ ))}
+
+ )}
+
+
+ )
+}
+
/** One block: a bar to switch between looking at it and reading it, then the block in a frame of its own. */
function BlockViewer({ block }: { block: Block }) {
const { theme } = useTheme()
@@ -101,30 +159,7 @@ function BlockViewer({ block }: { block: Block }) {
/>
) : (
-