memfs vs memory-fs
Node.jsにおけるインメモリファイルシステムの選択
memfsmemory-fs類似パッケージ:

Node.jsにおけるインメモリファイルシステムの選択

memfsmemory-fs はどちらも Node.js 環境で動作するインメモリファイルシステムを提供する npm パッケージです。これらは、物理ディスクに依存せずにファイルやディレクトリを操作できる仮想的なファイルシステムを実現し、テストやビルドツール、サンドボックス環境などで広く使われます。memfs は Node.js の fs モジュールとほぼ完全に互換性のある API を提供し、最新の機能にも対応しています。一方、memory-fs は webpack v3 以前の内部で使用されていた実装で、現在は非推奨(deprecated)となっています。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
memfs25,480,3572,04328.3 kB5011日前Apache-2.0
memory-fs10,131,082879-306年前MIT

memfs vs memory-fs: インメモリファイルシステムの実用的比較

Node.js でテストやビルドプロセス中に物理ディスクを使わずにファイル操作を行いたい場合、インメモリファイルシステムが非常に役立ちます。memfsmemory-fs はその代表的な選択肢ですが、現在の状況は大きく異なります。以下では、実際の開発現場でどう使い分けるべきか、技術的観点から詳しく見ていきます。

📦 メンテナンス状況と非推奨ステータス

memory-fsnpm ページ および GitHub リポジトリ で明確に 非推奨(deprecated) とされています。作者自身が「代わりに memfs を使ってください」と記載しており、新規プロジェクトで使うべきではありません。

一方、memfs は積極的にメンテナンスされており、Node.js の最新の fs API に追従しています。TypeScript 定義も整備されており、現代的な開発ワークフローに適しています。

💡 要点:memory-fs は新規プロジェクトで使ってはいけません。既存コードで使っている場合は、早めに memfs へ移行しましょう。

🔌 fs API との互換性

memfs:ほぼ完全互換

memfs は Node.js の組み込み fs モジュールと高い互換性を持ち、同期・非同期・Promise ベースのすべての API をサポートしています。

// memfs の基本的な使い方
import { fs } from 'memfs';

fs.writeFileSync('/tmp/hello.txt', 'Hello, world!');
console.log(fs.readFileSync('/tmp/hello.txt', 'utf8')); // "Hello, world!"

// fs/promises API も利用可能
import { fs as memfs } from 'memfs';
const data = await memfs.promises.readFile('/tmp/hello.txt', 'utf8');

さらに、vol(Volume)という概念を使って複数の独立したファイルシステムインスタンスを作成できます。

import { Volume } from 'memfs';

const vol = Volume.fromJSON({ '/foo/bar.txt': 'baz' });
console.log(vol.readFileSync('/foo/bar.txt', 'utf8')); // "baz"

memory-fs:古い API に限定

memory-fs は主に同期 API とコールバックベースの非同期 API のみをサポートしており、fs/promises には対応していません。また、一部の fs メソッドが欠けていたり、挙動が異なる場合があります。

// memory-fs の基本的な使い方(非推奨)
const MemoryFileSystem = require('memory-fs');
const fs = new MemoryFileSystem();

fs.writeFileSync('/tmp/hello.txt', 'Hello, world!');
console.log(fs.readFileSync('/tmp/hello.txt', 'utf8')); // "Hello, world!"

// Promise 対応なし — コールバックまたは同期のみ
fs.readFile('/tmp/hello.txt', 'utf8', (err, data) => {
  if (!err) console.log(data);
});

🧪 テストやモックでの使いやすさ

memfs:fs モジュールの置き換えが簡単

memfsfs モジュールを直接置き換えるためのユーティリティを提供しており、ユニットテストで非常に便利です。

// Jest で fs を memfs に置き換える例
import { fs } from 'memfs';
import * as fsOriginal from 'fs';

jest.mock('fs', () => fs);

// これ以降、アプリ内の fs 呼び出しはすべて memfs 経由になる

あるいは、ufs(UnionFS)と組み合わせて、実際のファイルシステムと memfs を階層的に使うことも可能です。

memory-fs:置き換えが手動で面倒

memory-fs は単なるクラスであり、require('fs') を自動で差し替える仕組みを持っていません。テストで使うには、アプリケーション側でファイルシステムの注入(dependency injection)を自前で実装する必要があります。

// memory-fs を使うには、コードを fs 受け入れ可能に設計する必要がある
function myFunction(fileSystem) {
  fileSystem.writeFileSync('/tmp/test.txt', 'data');
}

// テスト時
myFunction(new MemoryFileSystem());
// 本番時
myFunction(require('fs'));

これは設計の柔軟性を高めますが、既存コードへの導入コストが高くなります。

🧩 実装の信頼性と機能範囲

memfsfs の仕様に忠実に実装されており、シンボリックリンク、パーミッション、stat 情報、watch など、多くの高度な機能もサポートしています(ただし watch は no-op として実装される場合があります)。

// memfs での stat 情報取得
const stats = fs.statSync('/tmp/hello.txt');
console.log(stats.isFile()); // true
console.log(stats.size);     // 13

一方、memory-fs は基本的な読み書きに特化しており、lstatreadlinkfchmod などの一部のメソッドが未実装または不完全なことがあります。これは予期しないエラーを引き起こす可能性があります。

🔄 移行の実際

memory-fs から memfs への移行は、ほとんどのケースで非常に簡単です。主な違いはインスタンスの作成方法だけです。

// memory-fs(古い)
const MemoryFileSystem = require('memory-fs');
const fs = new MemoryFileSystem();

// memfs(新しい)
import { createFsFromVolume, Volume } from 'memfs';
const fs = createFsFromVolume(new Volume());
// またはシンプルに
import { fs } from 'memfs';

API 自体はほぼ同じなので、コードの大部分は変更不要です。

✅ まとめ:どちらを選ぶべきか?

項目memfsmemory-fs
メンテナンス状況✅ アクティブ❌ 非推奨
fs/promises 対応✅ あり❌ なし
fs 互換性✅ 高い⚠️ 限定的
テスト統合✅ 簡単(モック可能)⚠️ 手動注入が必要
新規プロジェクトでの使用✅ 推奨❌ 避けるべき

最終的なアドバイス

  • 新しいプロジェクトでは、迷わず memfs を使ってください。
  • 既存の memory-fs 使用コードがあれば、早めに memfs に置き換えることを検討してください。移行コストは低く、長期的なメンテナンス性が大幅に向上します。
  • webpack ユーザーであれば、webpack 4 以降は内部で memfs を使用しているため、プラグイン開発時も自然と memfs と親和性が高くなります。

インメモリファイルシステムは強力なツールですが、信頼性と将来性を考慮すれば、選択肢は一つだけです:memfs

選び方: memfs vs memory-fs

  • memfs:

    memfs は Node.js の fs モジュールと高い互換性を持ち、Promise 対応や fs/promises API など現代的な機能もサポートしています。新しいプロジェクトや、堅牢でメンテナンスされているインメモリファイルシステムが必要な場合は、memfs を選ぶべきです。特に Jest や Webpack 5 以降との統合を考慮する場合、このパッケージが最適です。

  • memory-fs:

    memory-fs は公式に非推奨(deprecated)とされており、新規プロジェクトでの使用は避けるべきです。既存の古いコードベース(例:webpack v3 以下のカスタムプラグイン)でしか見かけることはなく、今後のバグ修正や機能追加は期待できません。もし使用している場合は、memfs への移行を強く推奨します。

memfs のREADME

memfs

In-memory file system with Node.js fs API and browser File System (Access) API.

npm

Overview

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.

Installation

npm install memfs

Quick Start

Node.js fs API

import { 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']

Browser File System API

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!"

Features

  • Node.js fs module API compatibility
  • Browser File System (Access) API implementation
  • Adapters between fs and File System API
  • Directory snapshots and tree printing utilities
  • Works in Node.js and modern browsers
  • TypeScript support

Documentation

For detailed documentation and more examples, visit the main project page.

License

Apache 2.0