@@ -4,6 +4,10 @@ import { ready } from '../common/index.js';
4
4
5
5
/** @type {import('@webcontainer/api').WebContainer } */
6
6
let vm ;
7
+ /** Keep track of startup progress, so we don't repeat previous steps in case of a timeout */
8
+ let step = 0 ;
9
+ /** @type {string } */
10
+ let base ;
7
11
8
12
/**
9
13
* @param {import('$lib/types').Stub[] } stubs
@@ -24,10 +28,22 @@ export async function create(stubs) {
24
28
throw new Error ( 'WebContainers are not supported by Safari' ) ;
25
29
}
26
30
27
- const base = await new Promise ( async ( fulfil , reject ) => {
28
- setTimeout ( ( ) => {
29
- reject ( new Error ( 'Timed out starting WebContainer' ) ) ;
30
- } , 15000 ) ;
31
+ base = await new Promise ( async ( fulfil , reject ) => {
32
+ if ( base ) {
33
+ // startup was successful in the meantime
34
+ fulfil ( base ) ;
35
+ }
36
+
37
+ /** @type {any } */
38
+ let timeout ;
39
+ function reset_timeout ( ) {
40
+ clearTimeout ( timeout ) ;
41
+ timeout = setTimeout ( ( ) => {
42
+ reject ( new Error ( 'Timed out starting WebContainer' ) ) ;
43
+ } , 8000 ) ;
44
+ }
45
+
46
+ reset_timeout ( ) ;
31
47
32
48
// There can only be one instance, else it throws an error - guard against this case
33
49
// if there was an error later on or a timeout and the user tries again
@@ -46,44 +62,62 @@ export async function create(stubs) {
46
62
reject ( new Error ( error . message ) ) ;
47
63
} ) ;
48
64
49
- const ready_unsub = vm . on ( 'server-ready' , ( port , base ) => {
65
+ const ready_unsub = vm . on ( 'server-ready' , ( port , _base ) => {
66
+ base = _base ;
50
67
ready_unsub ( ) ;
51
- console . log ( `server ready on port ${ port } at ${ performance . now ( ) } : ${ base } ` ) ;
52
- fulfil ( base ) ;
68
+ console . log ( `server ready on port ${ port } at ${ performance . now ( ) } : ${ _base } ` ) ;
69
+ fulfil ( _base ) ;
53
70
} ) ;
54
71
55
- console . log ( 'loading files' ) ;
56
-
57
- await vm . loadFiles ( tree ) ;
58
-
59
- console . log ( 'unpacking modules' ) ;
60
-
61
- const unzip = await vm . run (
62
- {
63
- command : 'node' ,
64
- args : [ 'unzip.cjs' ]
65
- } ,
66
- {
67
- stderr : ( data ) => console . error ( `[unzip] ${ data } ` )
68
- }
69
- ) ;
70
-
71
- const code = await unzip . onExit ;
72
+ if ( step < 1 ) {
73
+ reset_timeout ( ) ;
74
+ step = 1 ;
75
+ console . log ( 'loading files' ) ;
72
76
73
- if ( code !== 0 ) {
74
- reject ( new Error ( 'Failed to initialize WebContainer' ) ) ;
77
+ await vm . loadFiles ( tree ) ;
75
78
}
76
79
77
- console . log ( 'starting dev server' ) ;
80
+ if ( step < 2 ) {
81
+ reset_timeout ( ) ;
82
+ step = 2 ;
83
+ console . log ( 'unpacking modules' ) ;
84
+
85
+ const unzip = await vm . run (
86
+ {
87
+ command : 'node' ,
88
+ args : [ 'unzip.cjs' ]
89
+ } ,
90
+ {
91
+ stderr : ( data ) => console . error ( `[unzip] ${ data } ` )
92
+ }
93
+ ) ;
78
94
79
- await vm . run ( { command : 'chmod' , args : [ 'a+x' , 'node_modules/vite/bin/vite.js' ] } ) ;
95
+ const code = await unzip . onExit ;
80
96
81
- await vm . run (
82
- { command : 'turbo' , args : [ 'run' , 'dev' ] } ,
83
- {
84
- stderr : ( data ) => console . error ( `[dev] ${ data } ` )
97
+ if ( code !== 0 ) {
98
+ reject ( new Error ( 'Failed to initialize WebContainer' ) ) ;
85
99
}
86
- ) ;
100
+ }
101
+
102
+ if ( step < 3 ) {
103
+ reset_timeout ( ) ;
104
+ step = 3 ;
105
+ console . log ( 'starting dev server' ) ;
106
+
107
+ await vm . run ( { command : 'chmod' , args : [ 'a+x' , 'node_modules/vite/bin/vite.js' ] } ) ;
108
+
109
+ await vm . run (
110
+ { command : 'turbo' , args : [ 'run' , 'dev' ] } ,
111
+ {
112
+ stdout : ( ) => {
113
+ if ( ! base ) {
114
+ reset_timeout ( ) ;
115
+ }
116
+ } ,
117
+ stderr : ( data ) => console . error ( `[dev] ${ data } ` )
118
+ }
119
+ ) ;
120
+ }
87
121
} ) ;
88
122
89
123
/**
@@ -94,7 +128,7 @@ export async function create(stubs) {
94
128
* Keeps track of the latest create/reset to ensure things are not processed in parallel.
95
129
* (if this turns out to be insufficient, we can use a queue)
96
130
*/
97
- let running = base ;
131
+ let running = Promise . resolve ( ) ;
98
132
99
133
return {
100
134
base,
0 commit comments