1.0.13 • Published 1 year ago

@d8d-webcontainer/api v1.0.13

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

@d8d-webcontainer/api

WebContainer API 客户端库,提供容器操作和文件系统功能。

安装

npm install @d8d-webcontainer/api

基本用法

import { WebContainer } from "@d8d-webcontainer/api";
async function main() {
  // 初始化 WebContainer
  const container = await WebContainer.getInstance({
    serverUrl: "http://localhost:3000",
  });
  // 挂载文件
  await container.mount({
    "package.json": {
      file: {
        contents: JSON.stringify({
          name: "my-project",
          dependencies: {},
        }),
      },
    },
  });
  // 监听文件变化
  const watcher = await container.fs.watch('src/**/*.ts', {
    onChange: (event) => {
      console.log('文件变化:', {
        type: event.type,  // 'create' | 'update' | 'delete'
        path: event.path
      });
    }
  });
  // 执行命令
  await container.spawn("npm", ["install"], {
    onOutput: (data) => console.log(data),
  });
}

API 参考

WebContainer

静态方法

WebContainer.getInstance(config: WebContainerConfig)

创建或获取 WebContainer 实例。

参数:

  • config.serverUrl: WebContainer 服务器地址

返回值: Promise<WebContainer>

WebContainer.hasInstance()

检查是否已存在 WebContainer 实例。

返回值: boolean

WebContainer.destroyInstance()

销毁当前的 WebContainer 实例。

实例方法

mount(files: FileSystemTree)

挂载文件系统。

参数:

  • files: 文件系统树结构对象
spawn(command: string, args?: string[], options?: SpawnOptions)

执行命令。

参数:

  • command: 要执行的命令
  • args: 命令参数数组
  • options.onOutput: 输出回调函数
on<K extends keyof WebContainerEvents>(event: K, handler: WebContainerEvents[K])

添加事件监听器。

参数:

  • event: 事件名称
  • handler: 事件处理函数
off<K extends keyof WebContainerEvents>(event: K, handler: WebContainerEvents[K])

移除事件监听器。

参数:

  • event: 事件名称
  • handler: 要移除的事件处理函数

文件系统 API

通过 container.fs 访问文件系统 API。

list(path?: string)

列出目录内容。

参数:

  • path: 目录路径,默认为 '.'

返回值: Promise<{ name: string; type: 'file' | 'directory' }[]>

readFile(path: string)

读取文件内容。

参数:

  • path: 文件路径

返回值: Promise<string>

writeFile(path: string, content: string)

写入文件内容。

参数:

  • path: 文件路径
  • content: 文件内容

remove(path: string)

删除文件或目录。

参数:

  • path: 文件或目录路径

mkdir(path: string)

创建目录。

参数:

  • path: 目录路径

watch(glob: string, options: WatchOptions)

监听文件变化。

参数:

  • glob: 要监听的文件 glob 模式
  • options.onChange: 文件变化回调函数

返回值: Promise<{ close: () => void }>

文件监听

fs.watch(glob: string, options: WatchOptions)

监听文件变化。

参数:

  • glob: 要监听的文件 glob 模式
    • '.' - 监听当前目录及其所有子内容
    • 'src' - 监听特定目录及其所有子内容
    • 'src/**/*.ts' - 监听特定目录下的特定文件类型
  • options.onChange: 文件变化回调函数

返回值: Promise<{ close: () => void }>

FileChangeEvent

interface FileChangeEvent {
  type: 'create' | 'update' | 'delete';  // 变化类型
  path: string;                          // 文件路径
  kind: 'file' | 'directory';           // 实体类型
}

WatchOptions

interface WatchOptions {
  onChange: (event: FileChangeEvent) => void;  // 文件变化回调函数
  ignore?: string[];                          // 要忽略的文件模式
  ignoreInitial?: boolean;                    // 是否忽略初始文件扫描事件
}

文件监听示例

// 监听当前目录,忽略初始扫描事件
const watcher = await container.fs.watch('.', {
  onChange: (event) => {
    if (event.type === 'create') {
      console.log(`新${event.kind}创建:`, event.path);
    } else if (event.type === 'update') {
      console.log(`${event.kind}已修改:`, event.path);
    } else if (event.type === 'delete') {
      console.log(`${event.kind}已删除:`, event.path);
    }
  },
  ignore: [
    '**/node_modules/**',   // 忽略 node_modules 目录
    '**/.git/**',           // 忽略 .git 目录
    '**/dist/**',           // 忽略构建输出目录
    '**/.DS_Store',         // 忽略 macOS 系统文件
    '**/thumbs.db',         // 忽略 Windows 系统文件
    '**/.idea/**',          // 忽略 IDE 配置目录
    '**/.vscode/**'         // 忽略 VSCode 配置目录
  ],
  ignoreInitial: true       // 忽略初始文件扫描事件
});

// 监听特定目录,包含初始扫描事件
const srcWatcher = await container.fs.watch('src', {
  onChange: (event) => {
    console.log(`src目录变化:`, event);
  },
  ignore: [
    '**/*.test.ts',        // 忽略测试文件
    '**/*.spec.ts',        // 忽略规格文件
    '**/coverage/**'       // 忽略测试覆盖率目录
  ],
  ignoreInitial: false     // 包含初始文件扫描事件
});

// 监听特定文件类型,忽略临时文件
const tsWatcher = await container.fs.watch('src/**/*.ts', {
  onChange: (event) => {
    console.log(`TypeScript文件变化:`, event);
  },
  ignore: [
    '**/*.tmp.ts',         // 忽略临时文件
    '**/*.bak.ts'          // 忽略备份文件
  ]
});

// 停止监听
await watcher.close();
await srcWatcher.close();
await tsWatcher.close();

事件

server-ready

当开发服务器就绪时触发。

事件参数:

interface ServerReadyEvent {
  port: number;
  url: string;
  localUrl?: string;
}

类型定义

WebContainerConfig

interface WebContainerConfig {
  serverUrl: string;
}

SpawnOptions

interface SpawnOptions {
  onOutput?: (data: string) => void;
}

FileSystemTree

interface FileSystemTree {
  [path: string]:
    | {
        file: {
          contents: string;
        };
      }
    | {
        directory: {
          contents: FileSystemTree;
        };
      };
}

SpawnOptions

interface SpawnOptions {
  onOutput?: (data: string) => void;
}

FileChangeEvent

interface FileChangeEvent {
  type: 'create' | 'update' | 'delete';  // 变化类型
  path: string;                          // 文件路径
  kind: 'file' | 'directory';           // 实体类型
}

WatchOptions

interface WatchOptions {
  onChange: (event: FileChangeEvent) => void;
  ignore?: string[];  // 要忽略的文件模式
}

示例

创建并运行 Node.js 项目

import { WebContainer } from "@d8d-webcontainer/api";
async function createNodeProject() {
  const container = await WebContainer.getInstance({
    serverUrl: "http://localhost:3000",
  });
  // 创建项目文件
  await container.mount({
    "package.json": {
      file: {
        contents: JSON.stringify({
          name: "node-demo",
          type: "module",
          dependencies: {
            express: "^4.18.2",
          },
        }),
      },
    },
    "index.js": {
      file: {
        contents: `import express from 'express'; const app = express(); app.get('/', (req, res) => { res.send('Hello from WebContainer!'); }); app.listen(3000);`,
      },
    },
  });
  // 安装依赖
  await container.spawn("npm", ["install"], {
    onOutput: console.log,
  });
  // 运行服务器
  await container.spawn("node", ["index.js"], {
    onOutput: console.log,
  });
}

文件操作示例

async function fileOperations(container: WebContainer) {
  // 创建目录
  await container.fs.mkdir("src");
  // 写入文件
  await container.fs.writeFile("src/hello.js", 'console.log("Hello");');
  // 列出文件
  const files = await container.fs.list("src");
  console.log("Files:", files);
  // 读取文件
  const content = await container.fs.readFile("src/hello.js");
  console.log("Content:", content);
  // 删除文件
  await container.fs.remove("src/hello.js");
}

文件监听示例

async function watchFiles(container: WebContainer) {
  // 设置文件监听
  const watcher = await container.fs.watch('src/**/*', {
    onChange: (event) => {
      if (event.type === 'create') {
        console.log(`新${event.kind}创建:`, event.path);
      } else if (event.type === 'update') {
        console.log(`${event.kind}已修改:`, event.path);
      } else if (event.type === 'delete') {
        console.log(`${event.kind}已删除:`, event.path);
      }
    }
  });

  // 执行一些文件操作
  await container.fs.writeFile('src/test.ts', 'console.log("Hello");');
  await container.fs.writeFile('src/test.ts', 'console.log("Updated");');
  await container.fs.remove('src/test.ts');

  // 停止监听
  await watcher.close();
}

注意事项

  1. WebContainer 实例是单例的,同一时间只能存在一个实例。

  2. 在组件卸载时应该调用 WebContainer.destroyInstance() 清理资源。

  3. 文件路径使用正斜杠 / 作为分隔符。

  4. spawn 命令的输出会通过 onOutput 回调返回,包括 stdout 和 stderr。

  5. 错误输出会以红色显示,退出信息会以黄色显示。

  6. 文件监听会自动处理文件和目录的创建、修改和删除事件

  7. 每个变化事件都会包含实体类型(file/directory)信息
  8. 可以使用 '.' 监听当前目录下的所有变化
  9. 默认会忽略 node_modules 和 .git 目录
  10. 可以通过 ignore 选项自定义要忽略的文件模式
  11. ignore 模式支持 glob 语法,如 **/node_modules/**
  12. ignoreInitial 参数控制是否触发已存在文件的初始事件
  13. 建议在组件卸载时调用 watcher.close() 清理监听器

License

MIT

1.0.13

1 year ago

1.0.12

1 year ago

1.0.11

1 year ago

1.0.10

1 year ago

1.0.9

1 year ago

1.0.8

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago