npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@d8d-webcontainer/api

v1.0.13

Published

Client API for D8D WebContainer

Downloads

27

Readme

@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