55 ReactNode ,
66 useCallback ,
77 useEffect ,
8+ useMemo ,
89 useRef ,
910 useState ,
1011} from "react" ;
@@ -69,7 +70,7 @@ export function WorkerProvider({
6970} ) {
7071 const workerRef = useRef < Worker | null > ( null ) ;
7172 const [ ready , setReady ] = useState < boolean > ( false ) ;
72- const mutex = useRef < MutexInterface > ( new Mutex ( ) ) ;
73+ const mutex = useMemo < MutexInterface > ( ( ) => new Mutex ( ) , [ ] ) ;
7374 const { writeFile } = useEmbedContext ( ) ;
7475
7576 const messageCallbacks = useRef <
@@ -96,6 +97,13 @@ export function WorkerProvider({
9697 }
9798
9899 const initializeWorker = useCallback ( async ( ) => {
100+ if ( ! mutex . isLocked ( ) ) {
101+ throw new Error ( `mutex of context must be locked for initializeWorker` ) ;
102+ }
103+ if ( workerRef . current ) {
104+ return ;
105+ }
106+
99107 let worker : Worker ;
100108 lang satisfies RuntimeLang ;
101109 switch ( lang ) {
@@ -135,15 +143,27 @@ export function WorkerProvider({
135143 } ) . then ( ( payload ) => {
136144 capabilities . current = payload . capabilities ;
137145 } ) ;
138- } , [ lang ] ) ;
146+ } , [ lang , mutex ] ) ;
147+
148+ const [ doInit , setDoInit ] = useState ( false ) ;
149+ const init = useCallback ( ( ) => setDoInit ( true ) , [ ] ) ;
139150
140151 // Initialization effect
141152 useEffect ( ( ) => {
142- initializeWorker ( ) . then ( ( ) => setReady ( true ) ) ;
143- return ( ) => {
144- workerRef . current ?. terminate ( ) ;
145- } ;
146- } , [ initializeWorker ] ) ;
153+ if ( doInit ) {
154+ void mutex . runExclusive ( async ( ) => {
155+ await initializeWorker ( ) ;
156+ setReady ( true ) ;
157+ } ) ;
158+ return ( ) => {
159+ void mutex . runExclusive ( async ( ) => {
160+ workerRef . current ?. terminate ( ) ;
161+ workerRef . current = null ;
162+ setReady ( false ) ;
163+ } ) ;
164+ } ;
165+ }
166+ } , [ doInit , initializeWorker , mutex ] ) ;
147167
148168 const interrupt = useCallback ( ( ) => {
149169 if ( ! capabilities . current ) return ;
@@ -161,9 +181,10 @@ export function WorkerProvider({
161181 messageCallbacks . current . clear ( ) ;
162182
163183 workerRef . current ?. terminate ( ) ;
184+ workerRef . current = null ;
164185 setReady ( false ) ;
165186
166- void mutex . current . runExclusive ( async ( ) => {
187+ void mutex . runExclusive ( async ( ) => {
167188 await initializeWorker ( ) ;
168189 if ( commandHistory . current . length > 0 ) {
169190 await postMessage ( "restoreState" , {
@@ -178,11 +199,11 @@ export function WorkerProvider({
178199 capabilities . current ?. interrupt satisfies never ;
179200 break ;
180201 }
181- } , [ initializeWorker ] ) ;
202+ } , [ initializeWorker , mutex ] ) ;
182203
183204 const runCommand = useCallback (
184205 async ( code : string ) : Promise < ReplOutput [ ] > => {
185- if ( ! mutex . current . isLocked ( ) ) {
206+ if ( ! mutex . isLocked ( ) ) {
186207 throw new Error ( `mutex of context must be locked for runCommand` ) ;
187208 }
188209 if ( ! workerRef . current || ! ready ) {
@@ -222,18 +243,18 @@ export function WorkerProvider({
222243 return [ { type : "error" , message : String ( error ) } ] ;
223244 }
224245 } ,
225- [ ready , writeFile ]
246+ [ ready , writeFile , mutex ]
226247 ) ;
227248
228249 const checkSyntax = useCallback (
229250 async ( code : string ) : Promise < SyntaxStatus > => {
230251 if ( ! workerRef . current || ! ready ) return "invalid" ;
231- const { status } = await mutex . current . runExclusive ( ( ) =>
252+ const { status } = await mutex . runExclusive ( ( ) =>
232253 postMessage ( "checkSyntax" , { code } )
233254 ) ;
234255 return status ;
235256 } ,
236- [ ready ]
257+ [ ready , mutex ]
237258 ) ;
238259
239260 const runFiles = useCallback (
@@ -263,7 +284,7 @@ export function WorkerProvider({
263284 ) {
264285 interruptBuffer . current [ 0 ] = 0 ;
265286 }
266- return mutex . current . runExclusive ( async ( ) => {
287+ return mutex . runExclusive ( async ( ) => {
267288 const { output, updatedFiles } = await postMessage ( "runFile" , {
268289 name : filenames [ 0 ] ,
269290 files,
@@ -272,16 +293,17 @@ export function WorkerProvider({
272293 return output ;
273294 } ) ;
274295 } ,
275- [ ready , writeFile ]
296+ [ ready , writeFile , mutex ]
276297 ) ;
277298
278299 return (
279300 < context . Provider
280301 value = { {
302+ init,
281303 ready,
282304 runCommand,
283305 checkSyntax,
284- mutex : mutex . current ,
306+ mutex,
285307 runFiles,
286308 interrupt,
287309 } }
0 commit comments