Skip to content

Commit 9218e8b

Browse files
committed
feat: compile panel & ast panel
1 parent 674b9fe commit 9218e8b

File tree

4 files changed

+67
-26
lines changed

4 files changed

+67
-26
lines changed

src/components/Editor/CodeMirror/index.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
import { type CompletionSource, autocompletion } from "@codemirror/autocomplete"
22
import { javascript } from "@codemirror/lang-javascript"
3+
import { EditorState, type Extension } from "@codemirror/state"
34
import { EditorView, basicSetup } from "codemirror"
4-
import { type FC, useLayoutEffect, useRef } from "react"
5+
import { type FC, useEffect, useLayoutEffect, useRef } from "react"
56

67
import { replJSXCompletion } from "./autocompletion"
78
import { vitesse } from "./theme"
89

910
import "./styles.css"
1011

11-
import type { Extension } from "@codemirror/state"
12-
1312
interface Props {
1413
code: string
1514
autoComplete?: CompletionSource[]
1615
cmExtensions?: Extension[]
1716
onChange?: (code: string) => void
17+
readonly?: boolean
1818
}
1919

2020
const CodeMirror: FC<Props> = (props) => {
@@ -30,6 +30,8 @@ const CodeMirror: FC<Props> = (props) => {
3030
autocompletion({
3131
override: [replJSXCompletion, ...(props.autoComplete || [])],
3232
}),
33+
EditorView.editable.of(!props.readonly || true),
34+
EditorState.readOnly.of(props.readonly || false),
3335
...(props.cmExtensions || []),
3436
]
3537

@@ -50,6 +52,19 @@ const CodeMirror: FC<Props> = (props) => {
5052
}
5153
}, [])
5254

55+
useEffect(() => {
56+
const cur = editorRef.current?.state.doc.toString() || ""
57+
if (props.code !== cur) {
58+
editorRef.current?.dispatch({
59+
changes: {
60+
from: 0,
61+
to: cur.length,
62+
insert: props.code,
63+
},
64+
})
65+
}
66+
}, [props.code])
67+
5368
return <div className="editor-container" ref={containerRef} />
5469
}
5570

src/components/Output/Preview/index.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type React from "react"
22
import { useCallback, useEffect, useRef } from "react"
33

44
import { useImportMap } from "@/hooks/impormap"
5-
import { transformCode } from "@/hooks/swc"
65
import logger from "@/utils/logger"
76
import basicTemplate from "./basic.html?raw"
87

@@ -25,7 +24,6 @@ const Preview: React.FC<Props> = ({ code, className }) => {
2524
}
2625

2726
try {
28-
const { transformedCode } = await transformCode(code)
2927
const iframeDoc = iframeRef.current.contentDocument
3028
if (!iframeDoc) {
3129
logger.warn(
@@ -41,7 +39,7 @@ const Preview: React.FC<Props> = ({ code, className }) => {
4139
.replace(
4240
"<!--PREVIEW-OPTIONS-PLACEHOLDER-HTML-->",
4341
`<div id="root"></div>
44-
<script type="module">${transformedCode}</script>`,
42+
<script type="module">${code}</script>`,
4543
)
4644

4745
iframeDoc.write(htmlContent)

src/components/Output/index.tsx

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import { useContext, useMemo, useState } from "react"
2-
import Preview from "./Preview"
1+
import { useCallback, useContext, useEffect, useMemo, useState } from "react"
32

3+
import CodeMirror from "@/components/Editor/CodeMirror"
4+
import { type OutputCode, transformCode } from "@/hooks/swc"
45
import { ReplContext } from "@/store"
6+
7+
import Preview from "./Preview"
58
import "./styles.css"
69

710
const outputTabs = [
@@ -12,10 +15,16 @@ const outputTabs = [
1215

1316
const Output = () => {
1417
const { state } = useContext(ReplContext)
15-
const { defaultCode = "", code = "", showAST, showCompile } = state
18+
const { code = "", showAST, showCompile } = state
1619
const [activeTab, setActiveTab] =
1720
useState<(typeof outputTabs)[number]["value"]>("preview")
1821

22+
const [outputCode, setOutputCode] = useState<OutputCode>({
23+
transformedCode: "",
24+
compiledCode: "",
25+
ast: "",
26+
})
27+
1928
const tabs = useMemo(() => {
2029
return outputTabs.filter((tab) => {
2130
if (!showAST && tab.value === "ast") return false
@@ -24,6 +33,16 @@ const Output = () => {
2433
})
2534
}, [showAST, showCompile])
2635

36+
const transformOutput = useCallback(async (code: string) => {
37+
const _code = await transformCode(code)
38+
setOutputCode(_code)
39+
}, [])
40+
41+
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
42+
useEffect(() => {
43+
transformOutput(code)
44+
}, [code])
45+
2746
return (
2847
<div className="repl-output-container">
2948
<div className="repl-output-tabs">
@@ -40,18 +59,20 @@ const Output = () => {
4059
</div>
4160
<div className="repl-output-content">
4261
<Preview
43-
code={code || defaultCode}
62+
code={outputCode?.transformedCode}
4463
className={`repl-output-panel ${activeTab === "preview" && "repl-output-panel-active"}`}
4564
/>
4665
<div
47-
className={`repl-output-panel ${activeTab === "compile" && "repl-output-panel-active"}`}
48-
>
49-
Compile output coming soon
50-
</div>
51-
<div
52-
className={`repl-output-panel ${activeTab === "ast" && "repl-output-panel-active"}`}
66+
className={`repl-output-panel ${activeTab !== "preview" && "repl-output-panel-active"}`}
5367
>
54-
AST output coming soon
68+
<CodeMirror
69+
readonly
70+
code={
71+
activeTab === "compile"
72+
? outputCode?.compiledCode
73+
: outputCode?.ast
74+
}
75+
/>
5576
</div>
5677
</div>
5778
</div>

src/hooks/swc.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ const SWC_PREVIEW_CONFIG: Options = {
9393

9494
let swcInstance: typeof swc | null = null
9595

96+
export interface OutputCode {
97+
transformedCode: string
98+
compiledCode: string
99+
ast: string
100+
}
101+
96102
export async function initSwc() {
97103
if (!swcInstance) {
98104
try {
@@ -109,23 +115,24 @@ export async function initSwc() {
109115
return swcInstance
110116
}
111117

112-
export async function transformCode(
113-
code: string,
114-
): Promise<{ transformedCode: string; compiledCode: string }> {
118+
export async function transformCode(code: string): Promise<OutputCode> {
115119
try {
116120
const instance = await initSwc()
117121
if (!instance) {
118122
throw new Error("SWC instance not initialized")
119123
}
120124

121-
const res = await Promise.all([
122-
instance.transform(code, SWC_PREVIEW_CONFIG),
123-
instance.transform(code, SWC_COMPILER_CONFIG),
124-
])
125+
const transformedCode = instance.transformSync(
126+
code,
127+
SWC_PREVIEW_CONFIG,
128+
).code
129+
const compiledCode = instance.transformSync(code, SWC_COMPILER_CONFIG).code
130+
const ast = JSON.stringify(await parse(code), null, 2)
125131

126132
return {
127-
transformedCode: res[0].code,
128-
compiledCode: res[1].code,
133+
transformedCode,
134+
compiledCode,
135+
ast,
129136
}
130137
} catch (error) {
131138
logger.error("Transform error:", error)

0 commit comments

Comments
 (0)