History

move prettier from web to control-plane, remove client-side formatting

Prettier formatting now happens server-side in source-inspection, so remove the browser-side format.ts hook and the prettier dependency from the web app. Add prettier to control-plane where it is actually used.

Rhys Sullivan committed 8 months ago

Commit bf1e7b21 parent c0a9ebd5 files · +5 −141Browse files

Unified · Split

5 files
  1. apps/web/package.json +0 −1
  2. apps/web/src/components/document-panel.tsx +2 −5
  3. apps/web/src/lib/format.ts +0 −133
  4. bun.lock +1 −1
  5. packages/control-plane/package.json +2 −1
apps/web/package.json+0−1
@@ -16,7 +16,6 @@ · 15 unmodified lines
1616 "class-variance-authority": "^0.7.1",
1717 "clsx": "^2.1.1",
1818 "effect": "catalog:",
19− "prettier": "^3.8.1",
2019 "react": "^19.2.0",
2120 "react-dom": "^19.2.0",
2221 "react-grab": "^0.1.26",
apps/web/src/components/document-panel.tsx+2−5
@@ -1,5 +1,4 @@
11 import { cn } from "../lib/utils";
2−import { useFormattedCode } from "../lib/format";
32 import { CodeBlock } from "./code-block";
43
54 export function DocumentPanel(props: {
@@ -9,8 +8,6 @@ export function DocumentPanel(props: { · 3 unmodified lines
98 empty: string;
109 compact?: boolean;
1110 }) {
12− const formatted = useFormattedCode(props.body, props.lang);
13−
1411 return (
1512 <section
1613 className={cn(
@@ -21,8 +18,8 @@ export function DocumentPanel(props: { · 4 unmodified lines
2118 <div className="border-b border-border px-3 py-2 text-[11px] font-medium uppercase tracking-wider text-muted-foreground/70">
2219 {props.title}
2320 </div>
24− {formatted ? (
25− <CodeBlock code={formatted} lang={props.lang} className="max-h-[32rem]" />
21+ {props.body ? (
22+ <CodeBlock code={props.body} lang={props.lang} className="max-h-[32rem]" />
2623 ) : (
2724 <div className="flex items-center justify-center p-6 text-[13px] text-muted-foreground/40">
2825 {props.empty}
apps/web/src/lib/format.ts+0−133
@@ -1,133 +0,0 @@
1−import { useState, useEffect } from "react";
2−
3−// Cache formatted results so we don't re-format on every render
4−const formatCache = new Map<string, string>();
5−
6−function formatCacheKey(code: string, parser: string): string {
7− return `${parser}::${code.length}::${code}`;
8−}
9−
10−/**
11− * Lazily load prettier + parsers and format code.
12− * Returns the original string if formatting fails.
13− */
14−async function formatCode(
15− code: string,
16− parser: "json" | "typescript" | "babel",
17−): Promise<string> {
18− const key = formatCacheKey(code, parser);
19− const cached = formatCache.get(key);
20− if (cached) return cached;
21−
22− try {
23− const [prettier, parserPlugin] = await Promise.all([
24− import("prettier/standalone"),
25− parser === "json"
26− ? import("prettier/plugins/babel")
27− : import("prettier/plugins/typescript"),
28− ]);
29−
30− // both babel and typescript parsers need estree
31− const estree = await import("prettier/plugins/estree");
32− // eslint-disable-next-line @typescript-eslint/no-explicit-any
33− const plugins: any[] = [parserPlugin, estree];
34−
35− let input = code;
36− let unwrap = false;
37−
38− // Type signature strings (e.g. `{ body: { ... } }`) aren't valid TS
39− // on their own. Wrap as `type T = ...` so prettier can parse them.
40− if (parser === "typescript") {
41− input = `type __T = ${code}`;
42− unwrap = true;
43− }
44−
45− const result = await prettier.format(input, {
46− parser: parser === "json" ? "json" : "typescript",
47− plugins,
48− printWidth: 60,
49− tabWidth: 2,
50− semi: true,
51− singleQuote: false,
52− trailingComma: "all",
53− });
54−
55− let trimmed = result.trimEnd();
56−
57− // Strip the `type __T = ` wrapper and trailing `;`
58− if (unwrap) {
59− trimmed = trimmed
60− .replace(/^type __T =\s*/, "")
61− .replace(/;$/, "")
62− .trimEnd();
63− }
64−
65− formatCache.set(key, trimmed);
66− return trimmed;
67− } catch {
68− // If formatting fails, return original
69− return code;
70− }
71−}
72−
73−/**
74− * Detect the right parser for a code string.
75− */
76−function detectParser(
77− code: string,
78− langHint?: string,
79−): "json" | "typescript" | null {
80− if (langHint === "json" || langHint === "jsonc") return "json";
81− if (langHint === "typescript" || langHint === "ts") return "typescript";
82−
83− const trimmed = code.trimStart();
84− if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
85−
86− return null;
87−}
88−
89−/**
90− * Hook: formats code with prettier. Returns the formatted string
91− * (or the original while loading / if formatting fails).
92− */
93−export function useFormattedCode(
94− code: string | null,
95− langHint?: string,
96−): string | null {
97− const [formatted, setFormatted] = useState<string | null>(code);
98−
99− useEffect(() => {
100− if (!code) {
101− setFormatted(null);
102− return;
103− }
104−
105− const parser = detectParser(code, langHint);
106− if (!parser) {
107− setFormatted(code);
108− return;
109− }
110−
111− // Check cache synchronously first
112− const key = formatCacheKey(code, parser);
113− const cached = formatCache.get(key);
114− if (cached) {
115− setFormatted(cached);
116− return;
117− }
118−
119− // Set original immediately, then replace with formatted
120− setFormatted(code);
121−
122− let cancelled = false;
123− formatCode(code, parser).then((result) => {
124− if (!cancelled) setFormatted(result);
125− });
126−
127− return () => {
128− cancelled = true;
129− };
130− }, [code, langHint]);
131−
132− return formatted;
133−}
bun.lock+1−1
@@ -56,7 +56,6 @@ · 55 unmodified lines
5656 "class-variance-authority": "^0.7.1",
5757 "clsx": "^2.1.1",
5858 "effect": "catalog:",
59− "prettier": "^3.8.1",
6059 "react": "^19.2.0",
6160 "react-dom": "^19.2.0",
6261 "react-grab": "^0.1.26",
@@ -149,6 +148,7 @@ · 86 unmodified lines
149148 "drizzle-orm": "1.0.0-beta.15-859cf75",
150149 "effect": "catalog:",
151150 "postgres": "^3.4.7",
151+ "prettier": "^3.8.1",
152152 },
153153 "devDependencies": {
154154 "@effect/platform-node": "catalog:",
packages/control-plane/package.json+2−1
@@ -31,7 +31,8 @@ · 30 unmodified lines
3131 "@executor-v3/runtime-local-inproc": "workspace:*",
3232 "drizzle-orm": "1.0.0-beta.15-859cf75",
3333 "effect": "catalog:",
34− "postgres": "^3.4.7"
34+ "postgres": "^3.4.7",
35+ "prettier": "^3.8.1"
3536 },
3637 "devDependencies": {
3738 "@effect/vitest": "catalog:",