Skip to content

Commit 7a0c5d4

Browse files
fix: internal state manager
1 parent 5580162 commit 7a0c5d4

File tree

4 files changed

+87
-94
lines changed

4 files changed

+87
-94
lines changed

src/lib/Editor.tsx

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,12 @@ export default function Editor({
3939
}: Props) {
4040
const [esm, setESM] = useState<boolean>(false);
4141
const containerRef = useRef(null);
42-
const { editorRef, wcStatus, webcontainer, wcSetup } = useAppState(
43-
(s) => ({
44-
editorRef: s.editorRef,
45-
wcStatus: s.wcStatus,
46-
webcontainer: s.webContainer,
47-
wcSetup: s.wcSetup,
48-
}),
49-
{ shallow: true }
50-
);
42+
const { editorRef, wcStatus, webcontainer, wcSetup } = useAppState((s) => ({
43+
editorRef: s.editorRef,
44+
wcStatus: s.wcStatus,
45+
webcontainer: s.webContainer,
46+
wcSetup: s.wcSetup,
47+
}));
5148

5249
const options = merge(
5350
{ header: true, darkMode: false },
@@ -72,7 +69,7 @@ export default function Editor({
7269
keymap.of([indentWithTab]),
7370
javascript(),
7471
EditorView.updateListener.of(async (update: ViewUpdate) => {
75-
if (update.docChanged && webcontainer.current) {
72+
if (update.docChanged && webcontainer) {
7673
await writeFile(NODE_MAIN_FILE, update.state.doc.toString());
7774
}
7875
}),
@@ -86,25 +83,25 @@ export default function Editor({
8683
parent: containerRef.current,
8784
});
8885

89-
setAppState({ editorRef: { current: editor } });
86+
setAppState({ editorRef: editor });
9087
}
9188
};
9289

9390
useEffect(() => {
9491
return () => {
95-
editorRef.current?.destroy();
96-
editorRef.current = null;
92+
editorRef?.destroy();
93+
setAppState({ editorRef: null });
9794
};
98-
}, [editorRef.current]);
95+
}, []);
9996

10097
useEffect(() => {
101-
if (wcStatus === WC_STATUS.READY && editorRef.current === null) {
98+
if (wcStatus === WC_STATUS.READY && editorRef === null) {
10299
init();
103100
}
104101
}, [wcStatus]);
105102

106103
useEffect(() => {
107-
if (wcSetup && wcStatus === WC_STATUS.READY && editorRef.current) {
104+
if (wcSetup && wcStatus === WC_STATUS.READY && editorRef) {
108105
const runCmdExt = Prec.highest(
109106
keymap.of([
110107
{
@@ -117,17 +114,17 @@ export default function Editor({
117114
])
118115
);
119116

120-
editorRef.current.dispatch({ effects: keyAction.reconfigure(runCmdExt) });
117+
editorRef.dispatch({ effects: keyAction.reconfigure(runCmdExt) });
121118
}
122-
}, [editorRef.current, onRun, wcSetup, wcStatus]);
119+
}, [editorRef, onRun, wcSetup, wcStatus]);
123120

124121
useEffect(() => {
125-
if (editorRef.current) {
126-
editorRef.current.dispatch({
122+
if (editorRef) {
123+
editorRef.dispatch({
127124
effects: themeComp.reconfigure(editorProps?.darkMode ? monokai : []),
128125
});
129126
}
130-
}, [editorRef.current, editorProps]);
127+
}, [editorRef, editorProps]);
131128

132129
const renderHeader = () => {
133130
if (options.header) {
@@ -186,14 +183,14 @@ export default function Editor({
186183
label="ESM"
187184
onChange={async (e) => {
188185
setESM(e.target.checked);
189-
if (webcontainer.current) {
190-
const content = await webcontainer.current.fs.readFile(
186+
if (webcontainer) {
187+
const content = await webcontainer.fs.readFile(
191188
PACKAGE_JSON_FILE,
192189
"utf-8"
193190
);
194191
const obj = JSON.parse(content);
195192
obj.type = e.target.checked ? "module" : "commonjs";
196-
await webcontainer.current.fs.writeFile(
193+
await webcontainer.fs.writeFile(
197194
PACKAGE_JSON_FILE,
198195
JSON.stringify(obj, null, 2)
199196
);

src/lib/NodeREPL.tsx

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default function NodeREPL(props: Props) {
3333
setAppState({ wcStatus: WC_STATUS.BOOTING });
3434
const webContainer = await WebContainer.boot();
3535
setAppState({
36-
webContainer: { current: webContainer },
36+
webContainer: webContainer,
3737
wcStatus: WC_STATUS.STARTED,
3838
});
3939
};
@@ -53,11 +53,11 @@ export default function NodeREPL(props: Props) {
5353

5454
useEffect(() => {
5555
return () => {
56-
if (shellProcessRef?.current) {
57-
shellProcessRef?.current.kill();
58-
shellProcessRef.current = null;
56+
if (shellProcessRef) {
57+
shellProcessRef.kill();
5958
dispOjbRef.current?.dispose();
6059
dispOjbRef.current = null;
60+
setAppState({ shellProcessRef: null, terminalRef: null });
6161
}
6262
};
6363
}, []);
@@ -72,38 +72,41 @@ export default function NodeREPL(props: Props) {
7272
if (
7373
wcSetup &&
7474
wcStatus === WC_STATUS.READY &&
75-
shellProcessRef.current === null &&
76-
terminalRef.current
75+
shellProcessRef === null &&
76+
terminalRef
7777
) {
7878
if (dispOjbRef.current) {
7979
dispOjbRef.current.dispose();
8080
dispOjbRef.current = null;
8181
}
8282
startShell();
8383
}
84-
}, [wcStatus, wcSetup, shellProcessRef.current, terminalRef.current]);
84+
}, [wcStatus, wcSetup, shellProcessRef, terminalRef]);
8585

8686
async function startShell() {
87-
if (!terminalRef.current) {
87+
if (!terminalRef || !webContainer) {
8888
return;
8989
}
9090

91-
shellProcessRef.current = (await webContainer.current?.spawn("jsh", {
91+
const shellProcessRef = (await webContainer.spawn("jsh", {
9292
terminal: {
93-
cols: terminalRef.current.cols,
94-
rows: terminalRef.current.rows,
93+
cols: terminalRef.cols,
94+
rows: terminalRef.rows,
9595
},
9696
})) as WebContainerProcess;
97-
shellProcessRef.current?.output.pipeTo(
97+
98+
shellProcessRef.output.pipeTo(
9899
new WritableStream({
99100
write(data) {
100-
terminalRef.current?.write(data);
101+
terminalRef.write(data);
101102
},
102103
})
103104
);
104105

105-
const input = shellProcessRef?.current.input.getWriter();
106-
dispOjbRef.current = terminalRef.current?.onData((data) => {
106+
setAppState({ shellProcessRef });
107+
108+
const input = shellProcessRef?.input.getWriter();
109+
dispOjbRef.current = terminalRef.onData((data) => {
107110
input?.write(data);
108111
});
109112
}
@@ -115,8 +118,8 @@ export default function NodeREPL(props: Props) {
115118
const pkgFile = JSON.parse(files["package.json"].file.contents);
116119
pkgFile.dependencies = getDeps(options.deps);
117120
files["package.json"].file.contents = JSON.stringify(pkgFile);
118-
if (webContainer.current) {
119-
await webContainer.current.mount(files);
121+
if (webContainer) {
122+
await webContainer.mount(files);
120123
setAppState({ wcStatus: WC_STATUS.READY });
121124
await sleep(100);
122125
}
@@ -130,44 +133,44 @@ export default function NodeREPL(props: Props) {
130133
};
131134

132135
const runCmd = async (prog: string, args: string[], output = true) => {
133-
if (shellProcessRef?.current) {
134-
shellProcessRef?.current.kill();
135-
shellProcessRef.current = null;
136+
if (shellProcessRef) {
137+
shellProcessRef?.kill();
138+
setAppState({ shellProcessRef: null });
136139
dispOjbRef.current?.dispose();
137140
dispOjbRef.current = null;
138141
}
139142

140-
if (terminalRef.current) {
141-
terminalRef.current.writeln("");
143+
if (terminalRef) {
144+
terminalRef.writeln("");
142145
}
143146

144-
if (webContainer.current) {
145-
runProcessRef.current = await webContainer.current.spawn(
146-
prog,
147-
[...args],
148-
{ output }
149-
);
147+
if (webContainer) {
148+
runProcessRef.current = await webContainer.spawn(prog, [...args], {
149+
output,
150+
});
150151
runProcessRef.current.output.pipeTo(
151152
new WritableStream({
152153
write(data) {
153-
if (terminalRef.current) {
154-
terminalRef.current.write(data);
154+
if (terminalRef) {
155+
terminalRef.write(data);
155156
}
156-
setAppState((s) => ({ logs: [...s.logs, data] }));
157+
setAppState((s) => {
158+
s.logs.push(data);
159+
});
157160
},
158161
})
159162
);
160163

161164
let disposeObj;
162-
if (terminalRef.current) {
165+
if (terminalRef) {
163166
const input = runProcessRef?.current.input.getWriter();
164-
disposeObj = terminalRef.current?.onData((data) => {
167+
disposeObj = terminalRef.onData((data) => {
165168
input?.write(data);
166169
});
167170
}
168171

169172
await runProcessRef.current.exit;
170-
terminalRef.current?.writeln("");
173+
terminalRef?.writeln("");
171174
runProcessRef.current = null;
172175
disposeObj?.dispose();
173176
}
@@ -178,22 +181,22 @@ export default function NodeREPL(props: Props) {
178181
};
179182

180183
async function writeFile(path: string, content: string) {
181-
if (webContainer.current) {
182-
await webContainer.current.fs.writeFile(path, content);
184+
if (webContainer) {
185+
await webContainer.fs.writeFile(path, content);
183186
}
184187
}
185188

186189
const handleRun = async () => {
187190
if (wcSetup && wcStatus === WC_STATUS.READY) {
188-
setAppState((s) => ({ ...s, wcStatus: WC_STATUS.RUNNING }));
191+
setAppState({ wcStatus: WC_STATUS.RUNNING });
189192
await runCmd("node", [NODE_INDEX_FILE]);
190-
setAppState((s) => ({ ...s, wcStatus: WC_STATUS.READY }));
193+
setAppState({ wcStatus: WC_STATUS.READY });
191194
}
192195
};
193196

194197
const handleClear = () => {
195198
if (terminalRef) {
196-
terminalRef.current?.clear();
199+
terminalRef.clear();
197200
}
198201
setAppState({ logs: [] });
199202
};

src/lib/Terminal.tsx

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,21 @@ const baseStyles: CSSProperties = {
1717
export default function Terminal({ style }: Props) {
1818
const fitAddonRef = useRef<FitAddon | null>(null);
1919
const terminalContRef = useRef<HTMLDivElement>(null);
20-
const { terminalRef, shellProcessRef } = useAppState(
21-
(s) => ({
22-
terminalRef: s.terminalRef,
23-
shellProcessRef: s.shellProcessRef,
24-
}),
25-
{ shallow: true }
26-
);
20+
const { terminalRef, shellProcessRef } = useAppState((s) => ({
21+
terminalRef: s.terminalRef,
22+
shellProcessRef: s.shellProcessRef,
23+
}));
2724

2825
useEffect(() => {
2926
return () => {
30-
terminalRef.current = null;
31-
shellProcessRef.current?.kill();
32-
shellProcessRef.current = null;
27+
shellProcessRef?.kill();
28+
terminalRef?.dispose();
29+
setAppState({ terminalRef: null, shellProcessRef: null });
3330
};
34-
}, [terminalRef.current]);
31+
}, []);
3532

3633
useEffect(() => {
37-
if (terminalContRef.current && terminalRef.current === null) {
34+
if (terminalContRef.current) {
3835
const terminal = new XTerminal({
3936
fontSize: 15,
4037
lineHeight: 1,
@@ -43,21 +40,17 @@ export default function Terminal({ style }: Props) {
4340
terminal.loadAddon(fitAddonRef.current);
4441
terminal.open(terminalContRef.current);
4542
fitAddonRef.current.fit();
46-
setAppState({ terminalRef: { current: terminal } });
43+
setAppState({ terminalRef: terminal });
4744
}
4845
}, []);
4946

5047
useEffect(() => {
5148
const handleResize = () => {
52-
if (
53-
shellProcessRef.current &&
54-
terminalRef.current &&
55-
fitAddonRef.current
56-
) {
49+
if (shellProcessRef && terminalRef && fitAddonRef.current) {
5750
fitAddonRef.current.fit();
58-
shellProcessRef.current.resize({
59-
cols: terminalRef.current.cols,
60-
rows: terminalRef.current.rows,
51+
shellProcessRef.resize({
52+
cols: terminalRef.cols,
53+
rows: terminalRef.rows,
6154
});
6255
}
6356
};
@@ -67,7 +60,7 @@ export default function Terminal({ style }: Props) {
6760
return () => {
6861
window.removeEventListener("resize", handleResize);
6962
};
70-
}, [shellProcessRef.current, terminalRef.current, fitAddonRef.current]);
63+
}, [shellProcessRef, terminalRef, fitAddonRef.current]);
7164

7265
return <div style={merge({}, baseStyles, style)} ref={terminalContRef}></div>;
7366
}

src/lib/store.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,21 @@ import { WC_STATUS } from "./constants";
66
import { EditorView } from "codemirror";
77

88
type State = {
9-
webContainer: { current: WebContainer | null };
10-
shellProcessRef: {current: WebContainerProcess | null}
11-
terminalRef: { current: Terminal | null };
12-
editorRef: { current: EditorView | null };
9+
webContainer: WebContainer | null;
10+
shellProcessRef: WebContainerProcess | null;
11+
terminalRef: Terminal | null;
12+
editorRef: EditorView | null;
1313
wcStatus: WcStatus;
1414
wcSetup: boolean;
1515
logs: string[];
1616
};
1717

18-
const [useAppState, setAppState] = create<State>({
19-
webContainer: { current: null },
20-
shellProcessRef: {current: null},
18+
const { useAppState, setAppState } = create<State>({
19+
webContainer: null,
20+
shellProcessRef: null,
2121
wcStatus: WC_STATUS.UNKNOWN,
22-
terminalRef: { current: null },
23-
editorRef: { current: null },
22+
terminalRef: null,
23+
editorRef: null,
2424
wcSetup: false,
2525
logs: [],
2626
});

0 commit comments

Comments
 (0)