建设中 个人网站正在建设中,部分内容尚未完善

我如何用纯前端在浏览器里跑一个 Linux 终端

WebLinux 是我花了几个月做的一个开源项目 — 一个完全跑在浏览器里的 Linux 终端模拟器。这篇文章聊聊它是怎么实现的。

核心问题

浏览器里没有真正的操作系统。要让用户觉得在一个真终端里敲命令,需要模拟三样东西:

  1. Shell 解释器 — 解析用户输入的命令,决定执行什么
  2. 文件系统 — 一个内存里的目录树,支持 cd、ls、cat、mkdir 等操作
  3. 终端 UI — 命令行输入框 + 输出区域,处理光标、历史、ANSI 颜色

Shell 解释器

最简单的方式是一个命令字典:每个命令名对应一个函数。

const commands = {
  ls(args, ctx) {
    return ctx.fs.list(ctx.cwd).join('  ');
  },
  cd(args, ctx) {
    const target = args[0] || '/';
    if (ctx.fs.exists(target)) {
      ctx.cwd = ctx.fs.resolve(target);
    } else {
      return `cd: no such file or directory: ${target}`;
    }
  },
  echo(args, ctx) {
    return args.join(' ');
  },
  // ... 还有 cat, pwd, mkdir, rm, touch, whoami
};

用户每次回车,就把输入按空格拆开,第一个词查字典,剩下的当参数传进去。就这么简单。

文件系统

文件系统是一个嵌套对象:

const root = {
  type: 'dir',
  children: {
    home: {
      type: 'dir',
      children: {
        user: {
          type: 'dir',
          children: {
            'readme.txt': { type: 'file', content: 'Hello from WebLinux!' }
          }
        }
      }
    },
    etc: { type: 'dir', children: {} },
    bin: { type: 'dir', children: {} }
  }
};

路径解析就是沿着 / 分割的字符串往下走。不复杂,但足够真实。

最有趣的坑

  • Tab 补全 — 要根据当前输入的前缀匹配文件系统路径,还要处理部分输入的情况
  • 历史记录 — 上下键翻历史,要记住每个会话的输入序列
  • 异步命令 — sleep 2 这种命令不能阻塞 UI,要用 Promise + setTimeout

下一步

WebLinux 还在持续迭代。计划加上更多命令、管道支持(ls | grep txt)、以及一个能写简单脚本的环境。

项目地址:web-linux.pages.dev