@ecopages/file-system

中文文档
0.7.1发布于 2026/11/13MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 4509

Node file system utilities for Ecopages

原始使用文档
文档目录5 节
  1. Features
  2. Installation
  3. Usage
  4. Paths
  5. API

@ecopages/file-system

Runtime file system utilities for Ecopages. The implementation is Node's node:fs and crypto on every runtime, including Bun.

Features

  • Node implementation: node:fs/promises.glob(), crypto, and node:fs on every runtime.
  • One interface: Call sites import fileSystem and do not choose an adapter. Tests replace it with installFileSystem and can wrap it with createRecordingFileSystem to observe every path argument.
  • Recursive watch: watch() opens one native recursive watcher per minimal directory root, rather than one watcher for every subdirectory. File and missing roots share non-recursive parent watches. It indexes existing entries without emitting initial changes, coalesces native events for 50 ms, supports adding paths to a running watch, and maps canonical paths back to the requested roots.
  • Type Safe: Full TypeScript support with a consistent API.

Installation

bun add @ecopages/file-system

Usage

import { fileSystem } from '@ecopages/file-system';

// Glob files
const files = await fileSystem.glob(['**/*.ts'], { cwd: './src' });

// Read files
const content = await fileSystem.readFile('file.txt');

// Hash files
const hash = fileSystem.hash('file.txt');

// Write files
fileSystem.write('output.txt', 'Hello World');

// Check existence
if (fileSystem.exists('file.txt')) {
    // ...
}

// Watch a tree, skipping dependencies
const watcher = fileSystem.watch(['./src'], {
    ignored: (path) => path.includes('node_modules'),
    onChange: ({ type, path }) => console.log(type, path),
    onError: (error) => console.error(error),
});
await watcher.ready;
await watcher.add(['./generated']);
await watcher.close();

watch() reports file changes as add, change or unlink, and directory changes as addDir or unlinkDir. Atomic replacement of an existing file is reported as one change. If a native event omits its filename, watch() reconciles the native root and can emit a rescan event for each mapped requested root; consumers should invalidate those roots once. A missing root is watched from its nearest existing parent and begins reporting once it is created. add() extends the running subscription and indexes entries already present under the new paths without reporting them. If registration fails, the added paths are rolled back so callers can retry them. Permission-denied children are skipped during indexing so accessible siblings remain watched. Symlinked roots are reported using the path passed to watch(). The optional ignored predicate runs before existing subdirectory contents are indexed, so ignored subtrees are not scanned. A path the predicate ignores when called without stats is also skipped by the native recursive watcher; on Linux, where Node opens one inotify watch per entry of a recursive root, that keeps trees such as node_modules from costing kernel watches. Return true without stats only for paths that stay ignored, because a predicate that widens later can only do so for answers given with stats. A directory removed while it is being indexed is treated as gone, not as an error.

Paths

@ecopages/file-system/path holds the path convention of Ecopages: every path uses forward slashes, and an absolute Windows path keeps its drive letter as given (D:/app/src/page.tsx); use path.isWithin rather than a string prefix to test containment. Its operations mirror node:path (join, resolve, relative, dirname, basename, extname, isAbsolute, normalize, parse, format, matchesGlob) and always return that form. Paths that fileSystem returns, from realpath, glob, readdir, readlink, mkdtemp, tempDir and watch, are in it too.

import { path } from '@ecopages/file-system/path';

const page = path.join(rootDir, 'src', 'pages', 'index.tsx');
const here = path.fromFileUrl(import.meta.url);
const module = await import(path.toFileUrl(page).href);
ExportDescription
path.cwd()The working directory, in this form
path.isWithin(directory, file)Whether file is directory or below it
path.fromNative(path)Convert a native path, such as import.meta.dirname
path.toNative(path)Convert to backslashes on Windows, for a tool that needs them
path.fromFileUrl(url)Convert a file: URL to a path
path.toFileUrl(path)Convert a path to a file: URL, as import() needs on Windows
createPath('posix' | 'win32')The same operations for one host flavor, for tests

API

MethodDescription
glob(patterns, options)Find files matching glob patterns
readFile(path)Read file as string (async)
readFileSync(path)Read file as string (sync)
readFileAsBuffer(path)Read file as Buffer
write(path, content)Write content to file
writeAsync(path, content)Write content to file (async)
exists(path)Check if path exists
ensureDir(path)Ensure directory exists
copyDir(src, dest)Copy directory recursively
copyFile(src, dest)Copy single file
remove(path)Remove file or directory
removeAsync(path)Remove file or directory (async)
hash(path)Get hash of file contents
gzipFile(path)Gzip a single file
gzipDir(path, extensions)Gzip files in directory
isDirectory(path)Check if path is directory
realpath(path)Resolve symlinks to canonical path
stat(path)Kind, size and mtime, following symlinks
lstat(path)Kind, size and mtime of the path itself
readdir(path, options)List entries with their kind
readlink(path)Read a symlink's stored target
mkdtemp(prefix)Create a uniquely named directory
tempDir()The OS directory for temporary files
rename(src, dest)Move a file or directory
verifyFileExists(path)Throw if file doesn't exist
watch(paths, options)Watch paths; the returned handle can add more
installFileSystem(next)Replace the process-wide fileSystem (tests)
createRecordingFileSystem(inner)Wrap inner and record every path argument

stat, lstat and readdir return plain objects (isFile, isDirectory, isSymbolicLink, plus size and mtimeMs for stats). readdir(path, { recursive: true }) also lists subdirectories, naming each entry by its path relative to path. stat, lstat, readdir, readlink, mkdtemp and rename throw Node's error unchanged, so a missing path can be detected by error.code === 'ENOENT'.

版本与发布记录

@ecopages/file-system 共发布 125 个版本,首次发布于 2026/03/09;过去 12 个月发布了 125 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.7.1latest2026/11/13今天
0.7.02026/11/094 天前
0.6.12026/10/3014 天前
0.6.02026/10/2915 天前
0.5.02026/10/2420 天前
0.4.02026/10/2222 天前

其他发布通道:alpha → 0.2.0-alpha.55,beta → 0.2.0-beta.43,rc → 0.2.0-rc.14。

关于 @ecopages/file-system 的常见问题

@ecopages/file-system 是什么?

Node file system utilities for Ecopages

如何安装 @ecopages/file-system?

在项目目录运行 npm install @ecopages/file-system,或使用 pnpm add / yarn add / bun add。

@ecopages/file-system 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@ecopages/file-system 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@ecopages/file-system 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js ^24.22.0 || >=26.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@ecopages/file-system 可以商用吗?

@ecopages/file-system 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@ecopages/file-system 的下载量有多少?

根据 npm 官方下载统计,@ecopages/file-system 在 2026/10/13 – 2026/11/11 这 30 天内被下载 4,509 次,日均约 150 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ecopages/file-system 还在维护吗?

最新版本 0.7.1 发布于 2026/11/13(今天);至今共发布 125 个版本,其中过去 12 个月发布了 125 个;首次发布于 2026/03/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。