memfs 和 memory-fs 都是用于在内存中模拟 Node.js 文件系统的工具库,常用于测试、构建工具(如 Webpack)或需要隔离文件操作的场景。它们提供与原生 fs 模块兼容的 API,允许开发者在不实际读写磁盘的情况下进行文件操作。memfs 是一个活跃维护的现代替代方案,而 memory-fs 已被官方标记为废弃,不再推荐用于新项目。
在开发构建工具、测试环境或需要隔离文件 I/O 的 Node.js 应用时,我们常常需要一个不依赖真实磁盘的文件系统实现。memfs 和 memory-fs 都试图解决这个问题,但它们的现状、能力与维护状态截然不同。本文将从技术细节出发,帮助你做出正确选择。
memory-fs 已被废弃首先必须明确:memory-fs 已在 npm 上被官方标记为 deprecated(废弃)。其 GitHub 仓库的 README 明确写道:“This package is deprecated. Use memfs instead.”
这意味着:
memfs因此,除非你在维护一个尚未升级的旧项目,否则不应在新代码中引入 memory-fs。
fs?memfs:几乎完整的 fs 替代memfs 的目标是提供一个与 Node.js 原生 fs 模块行为一致的内存实现。它不仅支持回调风格,还完整支持 fs.promises 和 fs.Stats 对象。
// 使用 memfs
import { fs } from 'memfs';
// 回调风格
fs.writeFile('/test.txt', 'hello', (err) => {
if (err) throw err;
fs.readFile('/test.txt', 'utf8', (err, data) => {
console.log(data); // 'hello'
});
});
// Promise 风格(现代推荐)
await fs.promises.writeFile('/test.txt', 'world');
const content = await fs.promises.readFile('/test.txt', 'utf8');
console.log(content); // 'world'
它还支持 fs.createReadStream / fs.createWriteStream,这对构建工具处理大文件至关重要。
memory-fs:仅基础回调 APImemory-fs 仅实现了部分回调风格的 fs 方法,不支持 Promise API,也不完全兼容 fs.Stats 或流操作。
// 使用 memory-fs(已废弃)
const MemoryFileSystem = require('memory-fs');
const fs = new MemoryFileSystem();
fs.writeFileSync('/test.txt', 'hello');
const content = fs.readFileSync('/test.txt', 'utf8');
console.log(content); // 'hello'
// ❌ 以下代码会失败或行为异常:
// fs.promises 不存在
// fs.createReadStream 可能不完整或缺失
如果你尝试在需要流式处理的场景(如 Webpack 的 asset emit)中使用 memory-fs,很可能会遇到兼容性问题。
memfs 支持高级文件系统特性symlink, readlink)chmod, stat.mode)atime, mtime)readdir with options)// memfs 支持符号链接
await fs.promises.symlink('/target.txt', '/link.txt');
const target = await fs.promises.readlink('/link.txt');
console.log(target); // '/target.txt'
这些特性对于模拟真实文件系统行为(如测试 CLI 工具)至关重要。
memory-fs 功能有限memory-fs 缺少对符号链接、精确时间戳和权限位的支持。它的 stat 对象是简化版,很多字段为固定值或 null。
// memory-fs 的 stat 对象可能缺少关键字段
const stats = fs.statSync('/test.txt');
console.log(stats.mtime); // 可能是 Date 对象,但不随写入更新
console.log(stats.mode); // 可能不反映真实权限
Webpack 4 曾使用 memory-fs 作为默认输出文件系统,但从 Webpack 5 开始,已切换到 memfs。如果你在编写自定义 Webpack 插件或 loader 并需要操作内存文件系统,必须使用 memfs 才能与现代 Webpack 兼容。
// Webpack 5+ 中获取内存文件系统
compiler.outputFileSystem = require('memfs').fs;
尝试在 Webpack 5+ 中注入 memory-fs 实例会导致类型错误或运行时异常。
两者都允许预填充初始文件结构,但 memfs 的方式更灵活。
// memfs:通过 vol.fromJSON 初始化
import { Volume } from 'memfs';
const vol = Volume.fromJSON({
'/src/index.js': 'console.log("hello");',
'/package.json': '{"name":"test"}'
});
const fs = vol.fs;
// memory-fs:需手动写入
const fs = new MemoryFileSystem();
fs.mkdirpSync('/src');
fs.writeFileSync('/src/index.js', '...');
memfs 的 fromJSON 方法让测试 setup 更简洁、可读。
memfs 是唯一合理选择| 特性 | memfs | memory-fs |
|---|---|---|
| 维护状态 | ✅ 活跃维护 | ❌ 已废弃 |
| Promise API | ✅ 完整支持 | ❌ 不支持 |
| 流式操作 | ✅ 完整支持 | ⚠️ 部分或缺失 |
| 符号链接 | ✅ 支持 | ❌ 不支持 |
| Webpack 5+ 兼容 | ✅ 官方使用 | ❌ 不兼容 |
| 初始化便捷性 | ✅ fromJSON 快速填充 | ⚠️ 需手动创建 |
memfs,它是当前事实标准。memory-fs:制定迁移计划,替换为 memfs。通常只需更改 import/require 语句并调整少量 API 调用(如使用 fs.promises)。memfs 的 Volume.fromJSON 和完整 API,让你的代码更健壮、更贴近真实环境。记住:在工程实践中,选择一个仍在维护、功能完整、社区支持良好的依赖,远比节省几行配置更重要。memfs 正是这样的选择。
选择 memfs 如果你需要一个功能完整、与 Node.js fs 模块高度兼容且仍在积极维护的内存文件系统实现。它支持 Promise API、流式操作和符号链接等高级特性,适合集成到现代构建工具、测试框架或任何需要可靠虚拟文件系统的场景。
不要在新项目中使用 memory-fs。该包已在 npm 上被标记为废弃(deprecated),官方推荐迁移到 memfs。仅在维护遗留代码且暂时无法升级时才考虑保留它,但应尽快规划替换方案。
In-memory file system with Node.js fs API and browser File System (Access) API.
memfs is a JavaScript library that implements an in-memory file system compatible with Node.js fs module and the browser File System (Access) API. Use it for testing, mocking file systems, or creating virtual file systems in both Node.js and browser environments.
npm install memfs
fs APIimport { fs } from 'memfs';
// Write a file
fs.writeFileSync('/hello.txt', 'Hello, World!');
// Read a file
const content = fs.readFileSync('/hello.txt', 'utf-8');
console.log(content); // "Hello, World!"
// Create a directory
fs.mkdirSync('/mydir');
// List directory contents
console.log(fs.readdirSync('/')); // ['hello.txt', 'mydir']
import { fsa } from 'memfs';
// Get root directory handle
const root = await fsa.getRoot();
// Create a file
const file = await root.getFileHandle('hello.txt', { create: true });
const writable = await file.createWritable();
await writable.write('Hello, World!');
await writable.close();
// Read the file
const readable = await file.getFile();
const text = await readable.text();
console.log(text); // "Hello, World!"
fs module API compatibilityfs and File System APIFor detailed documentation and more examples, visit the main project page.
Apache 2.0