Skip to content

Commit 0b373f0

Browse files
committed
dynamic import に変更
1 parent 461a1b0 commit 0b373f0

File tree

1 file changed

+72
-32
lines changed

1 file changed

+72
-32
lines changed

app/terminal/typescript/runtime.tsx

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,64 @@
11
"use client";
22

3-
import ts, { CompilerOptions } from "typescript";
4-
import {
5-
createSystem,
6-
createVirtualTypeScriptEnvironment,
7-
knownLibFilesForCompilerOptions,
8-
VirtualTypeScriptEnvironment,
9-
} from "@typescript/vfs";
3+
import type { CompilerOptions } from "typescript";
4+
import type { VirtualTypeScriptEnvironment } from "@typescript/vfs";
105
import {
116
createContext,
127
ReactNode,
138
useCallback,
149
useContext,
1510
useEffect,
16-
useRef,
1711
useState,
1812
} from "react";
1913
import { useEmbedContext } from "../embedContext";
2014
import { ReplOutput } from "../repl";
2115
import { RuntimeContext } from "../runtime";
16+
import dynamic from "next/dynamic";
2217

2318
export const compilerOptions: CompilerOptions = {};
2419

25-
const TypeScriptContext = createContext<VirtualTypeScriptEnvironment | null>(
26-
null
20+
type TSModules = {
21+
ts: typeof import("typescript");
22+
vfs: typeof import("@typescript/vfs");
23+
};
24+
interface ITypeScriptContext {
25+
modules: TSModules | null;
26+
setModules: (modules: TSModules) => void;
27+
tsEnv: VirtualTypeScriptEnvironment | null;
28+
}
29+
const TypeScriptContext = createContext<ITypeScriptContext>({
30+
modules: null,
31+
setModules: () => {},
32+
tsEnv: null,
33+
});
34+
const LazyInitTypeScript = dynamic(
35+
async () => {
36+
const ts = await import("typescript");
37+
const vfs = await import("@typescript/vfs");
38+
return function LazyInitTypeScript() {
39+
const { setModules } = useContext(TypeScriptContext);
40+
useEffect(() => {
41+
setModules({ ts, vfs });
42+
}, [setModules]);
43+
return null;
44+
};
45+
},
46+
{ ssr: false }
2747
);
2848
export function TypeScriptProvider({ children }: { children: ReactNode }) {
2949
const [tsEnv, setTSEnv] = useState<VirtualTypeScriptEnvironment | null>(null);
50+
const [modules, setModules] = useState<TSModules | null>(null);
51+
3052
useEffect(() => {
31-
if (tsEnv === null) {
53+
if (modules !== null && tsEnv === null) {
54+
const { ts, vfs } = modules;
3255
const abortController = new AbortController();
3356
(async () => {
34-
const system = createSystem(new Map());
35-
const libFiles = knownLibFilesForCompilerOptions(compilerOptions, ts);
57+
const system = vfs.createSystem(new Map());
58+
const libFiles = vfs.knownLibFilesForCompilerOptions(
59+
compilerOptions,
60+
ts
61+
);
3662
const libFileContents = await Promise.all(
3763
libFiles.map(async (libFile) => {
3864
const response = await fetch(
@@ -52,7 +78,7 @@ export function TypeScriptProvider({ children }: { children: ReactNode }) {
5278
system.writeFile(`/${libFile}`, content);
5379
}
5480
});
55-
const env = createVirtualTypeScriptEnvironment(
81+
const env = vfs.createVirtualTypeScriptEnvironment(
5682
system,
5783
[],
5884
ts,
@@ -64,21 +90,22 @@ export function TypeScriptProvider({ children }: { children: ReactNode }) {
6490
abortController.abort();
6591
};
6692
}
67-
}, [tsEnv]);
93+
}, [tsEnv, setTSEnv, modules]);
6894
return (
69-
<TypeScriptContext.Provider value={tsEnv}>
95+
<TypeScriptContext.Provider value={{ tsEnv, modules, setModules }}>
96+
<LazyInitTypeScript />
7097
{children}
7198
</TypeScriptContext.Provider>
7299
);
73100
}
74101

75102
export function useTypeScript(jsEval: RuntimeContext): RuntimeContext {
76-
const tsEnv = useContext(TypeScriptContext);
103+
const { modules, tsEnv } = useContext(TypeScriptContext);
77104

78105
const { writeFile } = useEmbedContext();
79106
const runFiles = useCallback(
80107
async (filenames: string[], files: Record<string, string>) => {
81-
if (tsEnv === null) {
108+
if (tsEnv === null || modules === null) {
82109
return [
83110
{ type: "error" as const, message: "TypeScript is not ready yet." },
84111
];
@@ -95,11 +122,14 @@ export function useTypeScript(jsEval: RuntimeContext): RuntimeContext {
95122
)) {
96123
outputs.push({
97124
type: "error",
98-
message: ts.formatDiagnosticsWithColorAndContext([diagnostic], {
99-
getCurrentDirectory: () => "",
100-
getCanonicalFileName: (f) => f,
101-
getNewLine: () => "\n",
102-
}),
125+
message: modules.ts.formatDiagnosticsWithColorAndContext(
126+
[diagnostic],
127+
{
128+
getCurrentDirectory: () => "",
129+
getCanonicalFileName: (f) => f,
130+
getNewLine: () => "\n",
131+
}
132+
),
103133
});
104134
}
105135

@@ -108,23 +138,33 @@ export function useTypeScript(jsEval: RuntimeContext): RuntimeContext {
108138
)) {
109139
outputs.push({
110140
type: "error",
111-
message: ts.formatDiagnosticsWithColorAndContext([diagnostic], {
112-
getCurrentDirectory: () => "",
113-
getCanonicalFileName: (f) => f,
114-
getNewLine: () => "\n",
115-
}),
141+
message: modules.ts.formatDiagnosticsWithColorAndContext(
142+
[diagnostic],
143+
{
144+
getCurrentDirectory: () => "",
145+
getCanonicalFileName: (f) => f,
146+
getNewLine: () => "\n",
147+
}
148+
),
116149
});
117150
}
118151

119152
const emitOutput = tsEnv.languageService.getEmitOutput(filenames[0]);
120-
files = await writeFile(Object.fromEntries(emitOutput.outputFiles.map((of) => [of.name, of.text])));
153+
files = await writeFile(
154+
Object.fromEntries(
155+
emitOutput.outputFiles.map((of) => [of.name, of.text])
156+
)
157+
);
121158

122-
console.log(emitOutput)
123-
const jsOutputs = jsEval.runFiles([emitOutput.outputFiles[0].name], files);
159+
console.log(emitOutput);
160+
const jsOutputs = jsEval.runFiles(
161+
[emitOutput.outputFiles[0].name],
162+
files
163+
);
124164

125165
return outputs.concat(await jsOutputs);
126166
},
127-
[tsEnv, writeFile, jsEval]
167+
[modules, tsEnv, writeFile, jsEval]
128168
);
129169
return {
130170
ready: tsEnv !== null,

0 commit comments

Comments
 (0)