WebContainer
WebContainer 是一个基于 WebAssembly 的能在浏览器内执行 Node.js 应用程序和操作系统命令的库
基本使用
准备工作
由于 WebContainer 需要使用 SharedArrayBuffer 功能,而该功能需要设置跨域隔离 cross-origin isolated,因此需要设置 COOP 和 COEP 标头
1 | Cross-Origin-Opener-Policy: same-origin |
启动系统
调用 WebContainer
类的 boot
静态方法启动系统
1 | import { WebContainer } from '@webcontainer/api' |
此方法只能被调用一次,在系统启动之后,系统注销之前,调用该方法会报错
挂载文件
调用 WebContainer
实例的 mount
方法一次性挂载大量文件到文件系统中,这比直接调用文件系统方法单次挂载文件更有校性能优势
1 | const files = { |
执行命令
调用 WebContainer
实例的 spawn
方法执行命令,如下载 npm 依赖
1 | const installProcess = await webcontainerInstance.spawn('npm', ['install']) |
或运行本地服务器
1 | await webcontainerInstance.spawn('npm', ['run', 'start']) |
监听事件
可以监听 WebContainer
实例上一系列事件以执行对应的操作
1 | webcontainerInstance.on('server-ready', (port, url) => { |
注销系统
调用 WebContainer
实例的 teardown
方法注销系统运行
1 | webcontainerInstance.teardown() |
文件系统机制
文件系统结构
文件系统结构中,包括文件,目录和链接,其数据结构如下所示:
1 | { |
对于文件,通过 file.contents
键指定文件的内容
对于目录,通过 directory
键指定目录中包含的文件
对于链接,通过 file.contents
键指定链接所指向的目标
文件系统挂载
使用 WebContainer
实例的 mount
方法一次性挂载大量文件(及目录)到文件系统中
1 | await webcontainerInstance.mount(files) |
文件系统数据需要遵循 FileSystemTree
类型的结构(可以自 @webcontainer/api
中导出)
1 | /** @type {import('@webcontainer/api').FileSystemTree} */ |
默认情况下,文件会被挂载到根目录下;可以指定 mountPoint
参数以挂载到其他目录下
1 | await webcontainerInstance.mount(files, { mountPoint: 'custom-mount-point' }) |
文件系统操作
主要的文件系统操作包括读取文件、读取目录、删除文件目录、写入文件、创建目录,通过 WebContainer
实例的 fs
属性使用
读取文件
readFile
1
2const file = await webcontainerInstance.fs.readFile('/package.json')
const file = await webcontainerInstance.fs.readFile('/package.json', 'utf-8')读取目录
readdir
1
2
3
4
5const files = await webcontainerInstance.fs.readdir('/src')
for (const file of files) {
console.log('file or dir name: ', file)
}withFileTypes
参数指定返回值的是否为Dirent
类型对象数组1
2
3
4
5
6
7
8
9
10
11
12const files = await webcontainerInstance.fs.readdir('/src', {
withFileTypes: true,
})
for (const file of files) {
if (file.isFile()) {
console.log('file name: ', file.name)
}
if (file.isDirectory()) {
console.log('dir name: ', file.name)
}
}encoding
参数指定返回值的类型1
const files = await webcontainerInstance.fs.readdir('/src', { encoding: 'buffer' })
删除文件目录
rm
1
await webcontainerInstance.fs.rm('/src/main.js');
删除非空目录时需要指定
recursive
参数以递归删除1
await webcontainerInstance.fs.rm('/src', { recursive: true });
写入文件
writeFile
1
2
3
4
5
6
7await webcontainerInstance.fs.writeFile('/src/main.js', 'console.log("Hello from WebContainers!")')
await webcontainerInstance.fs.writeFile(
'/src/main.js',
'\xE5\x8D\x83\xE8\x91\x89\xE5\xB8\x82\xE3\x83\x96\xE3\x83\xAB\xE3\x83\xBC\xE3\x82\xB9',
{ encoding: 'latin1' }
)创建目录
mkdir
1
await webcontainerInstance.fs.mkdir('src')
传递
recursive
参数以递归创建目录1
await webcontainerInstance.fs.mkdir('this/is/my/nested/folder', { recursive: true })
文件系统快照
可以使用 @webcontainer/snapshot
包提供的 snapshot
方法来生成一个本地文件系统的快照
1 | import { snapshot } from '@webcontainer/snapshot' |
从而可以提供给客户端挂载到文件系统上
1 | const snapshotResponse = await fetch('/snapshot'); |
线程机制
使用 WebContainer
实例的 spawn
方法执行命令
第一个参数表示命令的名称,第二个参数表示命令的参数,第三个参数表示执行命令的额外选项
方法返回的是一个 WebContainerProcess
实例
1 | const installProcess = await webcontainerInstance.spawn('npm', ['install']) |
可以通过 WebContainerProcess
实例的 exit
属性,其返回一个兑现 number
值的 Promise
,兑现后返回线程执行结果的状态码
线程输入输出
WebContainerProcess
实例的 input
属性返回 WritableStream<string>
值,向线程传入输入数据
WebContainerProcess
实例的 output
属性返回 ReadableStream<string>
值,接收对于线程终端的输出
1 | installProcess.output.pipeTo(new WritableStream({ |
中止线程
调用 WebContainerProcess
实例的 kill
方法中止线程的执行
1 | installProcess.kill() |
状态事件
系统包含多个事件响应
server-ready
事件,当服务完全可接收请求时触发port
事件,当端口被线程开启或关闭时触发error
事件,当内部错误抛出时触发
1 | webcontainerInstance.on('server-ready', (port, url) => { |
通常可以通过 WebContainer
实例的 on
方法监听对应的事件并绑定事件回调函数