1
- import { load } from '@webcontainer/api' ;
1
+ import { WebContainer } from '@webcontainer/api' ;
2
2
import base64 from 'base64-js' ;
3
3
import { get_depth } from '../../../utils.js' ;
4
4
import { ready } from '../common/index.js' ;
5
5
6
6
/** @type {import('@webcontainer/api').WebContainer } Web container singleton */
7
7
let vm ;
8
8
9
+ /** @param {string } label */
10
+ function console_stream ( label ) {
11
+ return new WritableStream ( {
12
+ write ( chunk ) {
13
+ console . log ( `[${ label } ] ${ chunk } ` ) ;
14
+ }
15
+ } ) ;
16
+ }
17
+
9
18
/**
10
19
* @param {import('$lib/types').Stub[] } stubs
11
20
* @param {(progress: number, status: string) => void } callback
@@ -31,15 +40,12 @@ export async function create(stubs, callback) {
31
40
/** @type {boolean } Track whether there was an error from vite dev server */
32
41
let vite_error = false ;
33
42
34
- callback ( 1 / 6 , 'loading webcontainer' ) ;
35
- const WebContainer = await load ( ) ;
36
-
37
- callback ( 2 / 6 , 'booting webcontainer' ) ;
43
+ callback ( 1 / 5 , 'booting webcontainer' ) ;
38
44
vm = await WebContainer . boot ( ) ;
39
45
40
- callback ( 3 / 6 , 'writing virtual files' ) ;
46
+ callback ( 2 / 5 , 'writing virtual files' ) ;
41
47
const common = await ready ;
42
- await vm . loadFiles ( {
48
+ await vm . mount ( {
43
49
'common.zip' : {
44
50
file : { contents : new Uint8Array ( common . zipped ) }
45
51
} ,
@@ -49,24 +55,18 @@ export async function create(stubs, callback) {
49
55
...convert_stubs_to_tree ( stubs )
50
56
} ) ;
51
57
52
- callback ( 4 / 6 , 'unzipping files' ) ;
53
- const unzip = await vm . run (
54
- {
55
- command : 'node' ,
56
- args : [ 'unzip.cjs' ]
57
- } ,
58
- {
59
- stderr : ( data ) => console . error ( `[unzip] ${ data } ` )
60
- }
61
- ) ;
62
- const code = await unzip . onExit ;
58
+ callback ( 3 / 5 , 'unzipping files' ) ;
59
+ const unzip = await vm . spawn ( 'node' , [ 'unzip.cjs' ] ) ;
60
+ unzip . output . pipeTo ( console_stream ( 'unzip' ) ) ;
61
+ const code = await unzip . exit ;
62
+
63
63
if ( code !== 0 ) {
64
64
throw new Error ( 'Failed to initialize WebContainer' ) ;
65
65
}
66
66
67
- await vm . run ( { command : 'chmod' , args : [ 'a+x' , 'node_modules/vite/bin/vite.js' ] } ) ;
67
+ await vm . spawn ( 'chmod' , [ 'a+x' , 'node_modules/vite/bin/vite.js' ] ) ;
68
68
69
- callback ( 5 / 6 , 'starting dev server' ) ;
69
+ callback ( 4 / 5 , 'starting dev server' ) ;
70
70
const base = await new Promise ( async ( fulfil , reject ) => {
71
71
const error_unsub = vm . on ( 'error' , ( error ) => {
72
72
error_unsub ( ) ;
@@ -75,27 +75,21 @@ export async function create(stubs, callback) {
75
75
76
76
const ready_unsub = vm . on ( 'server-ready' , ( port , base ) => {
77
77
ready_unsub ( ) ;
78
- callback ( 6 / 6 , 'ready' ) ;
78
+ callback ( 5 / 5 , 'ready' ) ;
79
79
fulfil ( base ) ; // this will be the last thing that happens if everything goes well
80
80
} ) ;
81
81
82
82
await run_dev ( ) ;
83
83
84
84
async function run_dev ( ) {
85
- const process = await vm . run (
86
- { command : 'turbo' , args : [ 'run' , 'dev' ] } ,
87
- {
88
- stdout : ( data ) => {
89
- console . log ( `[dev] ${ data } ` ) ;
90
- } ,
91
- stderr : ( data ) => {
92
- vite_error = true ;
93
- console . error ( `[dev] ${ data } ` ) ;
94
- }
95
- }
96
- ) ;
85
+ const process = await vm . spawn ( 'turbo' , [ 'run' , 'dev' ] ) ;
86
+
87
+ // TODO differentiate between stdout and stderr (sets `vite_error` to `true`)
88
+ // https://github.com/stackblitz/webcontainer-core/issues/971
89
+ process . output . pipeTo ( console_stream ( 'dev' ) ) ;
90
+
97
91
// keep restarting dev server (can crash in case of illegal +files for example)
98
- process . onExit . then ( ( code ) => {
92
+ process . exit . then ( ( code ) => {
99
93
if ( code !== 0 ) {
100
94
setTimeout ( ( ) => {
101
95
run_dev ( ) ;
@@ -185,10 +179,10 @@ export async function create(stubs, callback) {
185
179
// This will invoke a restart of Vite. Hacky but it works.
186
180
// TODO: remove when https://github.com/vitejs/vite/issues/12127 is closed
187
181
if ( ! previous_env && current_stubs . has ( '/.env' ) ) {
188
- await vm . run ( { command : 'touch' , args : [ '.env' ] } ) ;
182
+ await vm . spawn ( 'touch' , [ '.env' ] ) ;
189
183
}
190
184
191
- await vm . loadFiles ( convert_stubs_to_tree ( to_write ) ) ;
185
+ await vm . mount ( convert_stubs_to_tree ( to_write ) ) ;
192
186
await promise ;
193
187
await new Promise ( ( f ) => setTimeout ( f , 200 ) ) ; // wait for chokidar
194
188
@@ -220,13 +214,13 @@ export async function create(stubs, callback) {
220
214
} ;
221
215
}
222
216
223
- tree = /** @type {import('@webcontainer/api').DirectoryEntry } */ ( tree [ part ] ) . directory ;
217
+ tree = /** @type {import('@webcontainer/api').DirectoryNode } */ ( tree [ part ] ) . directory ;
224
218
}
225
219
226
220
tree [ basename ] = to_file ( stub ) ;
227
221
}
228
222
229
- await vm . loadFiles ( root ) ;
223
+ await vm . mount ( root ) ;
230
224
231
225
stubs_to_map ( stubs , current_stubs ) ;
232
226
@@ -236,8 +230,6 @@ export async function create(stubs, callback) {
236
230
} ,
237
231
destroy : async ( ) => {
238
232
vm . teardown ( ) ;
239
- // @ts -ignore
240
- vm = null ;
241
233
}
242
234
} ;
243
235
}
0 commit comments