rush-fs 0.0.1 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/README.md +183 -103
  2. package/README.zh-CN.md +180 -103
  3. package/index.d.ts +2 -2
  4. package/index.js +138 -134
  5. package/package.json +28 -22
package/README.md CHANGED
@@ -1,21 +1,187 @@
1
- # Hyper-FS
1
+ <div align="center">
2
+
3
+ # Rush-FS
4
+
5
+ [English](./README.md) | [中文](./README.zh-CN.md)
2
6
 
3
7
  <p align="center">
4
8
  <img src="https://img.shields.io/badge/Written%20in-Rust-orange?style=flat-square" alt="Written in Rust">
5
- <img src="https://img.shields.io/npm/v/hyper-fs?style=flat-square" alt="NPM Version">
6
- <img src="https://img.shields.io/npm/l/hyper-fs?style=flat-square" alt="License">
9
+ <img src="https://img.shields.io/npm/v/rush-fs?style=flat-square" alt="NPM Version">
10
+ <img src="https://img.shields.io/npm/l/rush-fs?style=flat-square" alt="License">
11
+ <a href="https://github.com/CoderSerio/rush-fs/graphs/contributors"><img src="https://img.shields.io/github/contributors/CoderSerio/rush-fs?style=flat-square" alt="Contributors"></a>
7
12
  </p>
8
13
 
9
14
  <p align="center">
10
- A high-performance, drop-in replacement for Node.js <code>fs</code> module, powered by Rust.
15
+ API-aligned with Node.js <code>fs</code> for painless drop-in replacement in existing projects; get multi-fold performance in heavy file operations, powered by Rust.
11
16
  </p>
12
17
 
18
+ </div>
19
+
13
20
  ## Installation
14
21
 
15
22
  ```bash
16
- npm install hyper-fs
23
+ npm install rush-fs
17
24
  # or
18
- pnpm add hyper-fs
25
+ pnpm add rush-fs
26
+ ```
27
+
28
+ When you install `rush-fs`, the package manager should automatically install the **platform-specific native binding** for your OS/arch via `optionalDependencies` (e.g. `@rush-fs/rush-fs-darwin-arm64` on macOS ARM). If the native binding is missing and you see "Cannot find native binding", try:
29
+
30
+ 1. Remove `node_modules` and the lockfile (`package-lock.json` or `pnpm-lock.yaml`), then run `pnpm install` (or `npm i`) again.
31
+ 2. Or install the platform package explicitly:
32
+ **macOS ARM:** `pnpm add @rush-fs/rush-fs-darwin-arm64`
33
+ **macOS x64:** `pnpm add @rush-fs/rush-fs-darwin-x64`
34
+ **Windows x64:** `pnpm add @rush-fs/rush-fs-win32-x64-msvc`
35
+ **Linux x64 (glibc):** `pnpm add @rush-fs/rush-fs-linux-x64-gnu`
36
+
37
+ ## Usage
38
+
39
+ ```ts
40
+ import { readdir, stat, readFile, writeFile, mkdir, rm } from 'rush-fs'
41
+
42
+ // Read directory
43
+ const files = await readdir('./src')
44
+
45
+ // Recursive with file types
46
+ const entries = await readdir('./src', {
47
+ recursive: true,
48
+ withFileTypes: true,
49
+ })
50
+
51
+ // Read / write files
52
+ const content = await readFile('./package.json', { encoding: 'utf8' })
53
+ await writeFile('./output.txt', 'hello world')
54
+
55
+ // File stats
56
+ const s = await stat('./package.json')
57
+ console.log(s.size, s.isFile())
58
+
59
+ // Create directory
60
+ await mkdir('./new-dir', { recursive: true })
61
+
62
+ // Remove
63
+ await rm('./temp', { recursive: true, force: true })
64
+ ```
65
+
66
+ ## Benchmarks
67
+
68
+ > Tested on Apple Silicon (arm64), Node.js 24.0.2, release build with LTO.
69
+ > Run `pnpm build && pnpm bench` to reproduce.
70
+
71
+ ### Where Rush-FS Shines
72
+
73
+ These are the scenarios where Rust's parallelism and zero-copy I/O make a real difference:
74
+
75
+ | Scenario | Node.js | Rush-FS | Speedup |
76
+ | ------------------------------------------------ | --------- | -------- | --------- |
77
+ | `readdir` recursive (node_modules, ~30k entries) | 281 ms | 23 ms | **12x** |
78
+ | `glob` recursive (`**/*.rs`) | 25 ms | 1.46 ms | **17x** |
79
+ | `glob` recursive vs fast-glob | 102 ms | 1.46 ms | **70x** |
80
+ | `copyFile` 4 MB | 4.67 ms | 0.09 ms | **50x** |
81
+ | `readFile` 4 MB utf8 | 1.86 ms | 0.92 ms | **2x** |
82
+ | `readFile` 64 KB utf8 | 42 µs | 18 µs | **2.4x** |
83
+ | `rm` 2000 files (4 threads) | 92 ms | 53 ms | **1.75x** |
84
+ | `access` R_OK (directory) | 4.18 µs | 1.55 µs | **2.7x** |
85
+ | `cp` 500-file flat dir (4 threads) | 86.45 ms | 32.88 ms | **2.6x** |
86
+ | `cp` tree dir ~363 nodes (4 threads) | 108.73 ms | 46.88 ms | **2.3x** |
87
+
88
+ ### On Par with Node.js
89
+
90
+ Single-file operations have a ~0.3 µs napi bridge overhead, making them roughly equivalent:
91
+
92
+ | Scenario | Node.js | Rush-FS | Ratio |
93
+ | -------------------------- | ------- | ------- | ----- |
94
+ | `stat` (single file) | 1.45 µs | 1.77 µs | 1.2x |
95
+ | `readFile` small (Buffer) | 8.86 µs | 9.46 µs | 1.1x |
96
+ | `writeFile` small (string) | 74 µs | 66 µs | 0.9x |
97
+ | `writeFile` small (Buffer) | 115 µs | 103 µs | 0.9x |
98
+ | `appendFile` | 30 µs | 27 µs | 0.9x |
99
+
100
+ ### Where Node.js Wins
101
+
102
+ Lightweight built-in calls where napi overhead is proportionally large:
103
+
104
+ | Scenario | Node.js | Rush-FS | Note |
105
+ | ---------------------------- | ------- | ------- | --------------------------------- |
106
+ | `existsSync` (existing file) | 444 ns | 1.34 µs | Node.js internal fast path |
107
+ | `accessSync` F_OK | 456 ns | 1.46 µs | Same — napi overhead dominates |
108
+ | `writeFile` 4 MB string | 2.93 ms | 5.69 ms | Large string crossing napi bridge |
109
+
110
+ ### Parallelism
111
+
112
+ Rush-FS uses multi-threaded parallelism for operations that traverse the filesystem:
113
+
114
+ | API | Library | `concurrency` option | Default |
115
+ | --------------------- | ------------------------------------------------------------------------- | -------------------- | ------- |
116
+ | `readdir` (recursive) | [jwalk](https://github.com/Byron/jwalk) | ✅ | auto |
117
+ | `glob` | [ignore](https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore) | ✅ | 4 |
118
+ | `rm` (recursive) | [rayon](https://github.com/rayon-rs/rayon) | ✅ | 1 |
119
+ | `cp` (recursive) | [rayon](https://github.com/rayon-rs/rayon) | ✅ | 1 |
120
+
121
+ Single-file operations (`stat`, `readFile`, `writeFile`, `chmod`, etc.) are atomic syscalls — parallelism does not apply.
122
+
123
+ ### Key Takeaway
124
+
125
+ **Rush-FS excels at recursive / batch filesystem operations** (readdir, glob, rm, cp) where Rust's parallel walkers deliver 2–70x speedups. For single-file operations it performs on par with Node.js. The napi bridge adds a fixed ~0.3 µs overhead per call, which only matters for sub-microsecond operations like `existsSync`.
126
+
127
+ **`cp` benchmark detail** (Apple Silicon, release build):
128
+
129
+ | Scenario | Node.js | Rush-FS 1T | Rush-FS 4T | Rush-FS 8T |
130
+ | ----------------------------------------- | --------- | ---------- | ---------- | ---------- |
131
+ | Flat dir (500 files) | 86.45 ms | 61.56 ms | 32.88 ms | 36.67 ms |
132
+ | Tree dir (breadth=4, depth=3, ~84 nodes) | 23.80 ms | 16.94 ms | 10.62 ms | 9.76 ms |
133
+ | Tree dir (breadth=3, depth=5, ~363 nodes) | 108.73 ms | 75.39 ms | 46.88 ms | 46.18 ms |
134
+
135
+ Optimal concurrency for `cp` is **4 threads** on Apple Silicon — beyond that, I/O bandwidth becomes the bottleneck and diminishing returns set in.
136
+
137
+ ## How it works
138
+
139
+ For the original Node.js, it works serially and cost lots of memory to parse os object and string into JS style:
140
+
141
+ ```mermaid
142
+ graph TD
143
+ A["JS: readdir"] -->|Call| B("Node.js C++ Binding")
144
+ B -->|Submit Task| C{"Libuv Thread Pool"}
145
+
146
+ subgraph "Native Layer (Serial)"
147
+ C -->|"Syscall: getdents"| D[OS Kernel]
148
+ D -->|"Return File List"| C
149
+ C -->|"Process Paths"| C
150
+ end
151
+
152
+ C -->|"Results Ready"| E("V8 Main Thread")
153
+
154
+ subgraph "V8 Interaction (Heavy)"
155
+ E -->|"Create JS String 1"| F[V8 Heap]
156
+ E -->|"String 2"| F
157
+ E -->|"String N..."| F
158
+ F -->|"GC Pressure Rising"| F
159
+ end
160
+
161
+ E -->|"Return Array"| G["JS Callback/Promise"]
162
+ ```
163
+
164
+ But, it's saved with Rust now:
165
+
166
+ ```mermaid
167
+ graph TD
168
+ A["JS: readdir"] -->|"N-API Call"| B("Rust Wrapper")
169
+ B -->|"Spawn Thread/Task"| C{"Rust Thread Pool"}
170
+
171
+ subgraph "Rust 'Black Box'"
172
+ C -->|"Rayon: Parallel work"| D[OS Kernel]
173
+ D -->|"Syscall: getdents"| C
174
+ C -->|"Store as Rust Vec<String>"| H[Rust Heap]
175
+ H -->|"No V8 Interaction yet"| H
176
+ end
177
+
178
+ C -->|"All Done"| I("Convert to JS")
179
+
180
+ subgraph "N-API Bridge"
181
+ I -->|"Batch Create JS Array"| J[V8 Heap]
182
+ end
183
+
184
+ J -->|Return| K["JS Result"]
19
185
  ```
20
186
 
21
187
  ## Status & Roadmap
@@ -26,7 +192,7 @@ We are rewriting `fs` APIs one by one.
26
192
  >
27
193
  > - ✅: Fully Supported
28
194
  > - 🚧: Partially Supported / WIP
29
- > - ✨:New feature from hyper-fs
195
+ > - ✨: New feature from rush-fs
30
196
  > - ❌: Not Supported Yet
31
197
 
32
198
  ### `readdir`
@@ -309,109 +475,23 @@ We are rewriting `fs` APIs one by one.
309
475
 
310
476
  - **Status**: ❌
311
477
 
312
- ## Usage
313
-
314
- ```ts
315
- import { readdir, stat, readFile, writeFile, mkdir, rm } from 'hyper-fs'
316
-
317
- // Read directory
318
- const files = await readdir('./src')
319
-
320
- // Recursive with file types
321
- const entries = await readdir('./src', {
322
- recursive: true,
323
- withFileTypes: true,
324
- })
325
-
326
- // Read / write files
327
- const content = await readFile('./package.json', { encoding: 'utf8' })
328
- await writeFile('./output.txt', 'hello world')
329
-
330
- // File stats
331
- const s = await stat('./package.json')
332
- console.log(s.size, s.isFile())
333
-
334
- // Create directory
335
- await mkdir('./new-dir', { recursive: true })
336
-
337
- // Remove
338
- await rm('./temp', { recursive: true, force: true })
339
- ```
340
-
341
- ## Benchmarks
342
-
343
- > Tested on Apple Silicon (arm64), Node.js 24.0.2, release build with LTO.
344
- > Run `pnpm build && pnpm bench` to reproduce.
345
-
346
- ### Where Hyper-FS Shines
347
-
348
- These are the scenarios where Rust's parallelism and zero-copy I/O make a real difference:
349
-
350
- | Scenario | Node.js | Hyper-FS | Speedup |
351
- | ------------------------------------------------ | --------- | -------- | --------- |
352
- | `readdir` recursive (node_modules, ~30k entries) | 281 ms | 23 ms | **12x** |
353
- | `glob` recursive (`**/*.rs`) | 25 ms | 1.46 ms | **17x** |
354
- | `glob` recursive vs fast-glob | 102 ms | 1.46 ms | **70x** |
355
- | `copyFile` 4 MB | 4.67 ms | 0.09 ms | **50x** |
356
- | `readFile` 4 MB utf8 | 1.86 ms | 0.92 ms | **2x** |
357
- | `readFile` 64 KB utf8 | 42 µs | 18 µs | **2.4x** |
358
- | `rm` 2000 files (4 threads) | 92 ms | 53 ms | **1.75x** |
359
- | `access` R_OK (directory) | 4.18 µs | 1.55 µs | **2.7x** |
360
- | `cp` 500-file flat dir (4 threads) | 86.45 ms | 32.88 ms | **2.6x** |
361
- | `cp` tree dir ~363 nodes (4 threads) | 108.73 ms | 46.88 ms | **2.3x** |
362
-
363
- ### On Par with Node.js
364
-
365
- Single-file operations have a ~0.3 µs napi bridge overhead, making them roughly equivalent:
478
+ ## Changelog
366
479
 
367
- | Scenario | Node.js | Hyper-FS | Ratio |
368
- | -------------------------- | ------- | -------- | ----- |
369
- | `stat` (single file) | 1.45 µs | 1.77 µs | 1.2x |
370
- | `readFile` small (Buffer) | 8.86 µs | 9.46 µs | 1.1x |
371
- | `writeFile` small (string) | 74 µs | 66 µs | 0.9x |
372
- | `writeFile` small (Buffer) | 115 µs | 103 µs | 0.9x |
373
- | `appendFile` | 30 µs | 27 µs | 0.9x |
374
-
375
- ### Where Node.js Wins
480
+ See [CHANGELOG.md](./CHANGELOG.md) for a summary of changes in each version. Release tags are listed in [GitHub Releases](https://github.com/CoderSerio/rush-fs/releases).
376
481
 
377
- Lightweight built-in calls where napi overhead is proportionally large:
378
-
379
- | Scenario | Node.js | Hyper-FS | Note |
380
- | ---------------------------- | ------- | -------- | --------------------------------- |
381
- | `existsSync` (existing file) | 444 ns | 1.34 µs | Node.js internal fast path |
382
- | `accessSync` F_OK | 456 ns | 1.46 µs | Same — napi overhead dominates |
383
- | `writeFile` 4 MB string | 2.93 ms | 5.69 ms | Large string crossing napi bridge |
384
-
385
- ### Parallelism
386
-
387
- Hyper-FS uses multi-threaded parallelism for operations that traverse the filesystem:
388
-
389
- | API | Library | `concurrency` option | Default |
390
- | --------------------- | ------------------------------------------------------------------------- | -------------------- | ------- |
391
- | `readdir` (recursive) | [jwalk](https://github.com/Byron/jwalk) | ✅ | auto |
392
- | `glob` | [ignore](https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore) | ✅ | 4 |
393
- | `rm` (recursive) | [rayon](https://github.com/rayon-rs/rayon) | ✅ | 1 |
394
- | `cp` (recursive) | [rayon](https://github.com/rayon-rs/rayon) | ✅ | 1 |
395
-
396
- Single-file operations (`stat`, `readFile`, `writeFile`, `chmod`, etc.) are atomic syscalls — parallelism does not apply.
397
-
398
- ### Key Takeaway
482
+ ## Contributing
399
483
 
400
- **Hyper-FS excels at recursive / batch filesystem operations** (readdir, glob, rm, cp) where Rust's parallel walkers deliver 2–70x speedups. For single-file operations it performs on par with Node.js. The napi bridge adds a fixed ~0.3 µs overhead per call, which only matters for sub-microsecond operations like `existsSync`.
484
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full development guide: environment setup, Node.js reference, Rust implementation, testing, and benchmarking.
401
485
 
402
- **`cp` benchmark detail** (Apple Silicon, release build):
486
+ ## Publishing (Maintainers Only)
403
487
 
404
- | Scenario | Node.js | Hyper-FS 1T | Hyper-FS 4T | Hyper-FS 8T |
405
- | ----------------------------------------- | --------- | ----------- | ----------- | ----------- |
406
- | Flat dir (500 files) | 86.45 ms | 61.56 ms | 32.88 ms | 36.67 ms |
407
- | Tree dir (breadth=4, depth=3, ~84 nodes) | 23.80 ms | 16.94 ms | 10.62 ms | 9.76 ms |
408
- | Tree dir (breadth=3, depth=5, ~363 nodes) | 108.73 ms | 75.39 ms | 46.88 ms | 46.18 ms |
488
+ Releases are handled by the [Release workflow](.github/workflows/Release.yml): it builds native binaries for macOS (x64/arm64), Windows, and Linux, then publishes the platform packages and the main package to npm.
409
489
 
410
- Optimal concurrency for `cp` is **4 threads** on Apple Silicon beyond that, I/O bandwidth becomes the bottleneck and diminishing returns set in.
411
-
412
- ## Contributing
490
+ 1. **Secrets:** In the repo **Settings Secrets and variables Actions**, add **NPM_TOKEN** (npm Classic or Automation token with Publish permission).
491
+ 2. **Release:** Either run **Actions → Release → Run workflow** (uses the current `package.json` version on `main`), or bump version in `package.json` and `Cargo.toml`, push to `main`, then create and push a tag: `git tag v<version> && git push origin v<version>`.
492
+ 3. **Changelog:** Update [CHANGELOG.md](./CHANGELOG.md) before or right after the release (move entries from `[Unreleased]` to a new version heading and add the compare link).
413
493
 
414
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for the complete development guide from environment setup, referencing Node.js source, writing Rust implementations, to testing and benchmarking.
494
+ The workflow injects `optionalDependencies` and publishes all packages; no need to edit `package.json` manually for release.
415
495
 
416
496
  ## License
417
497
 
package/README.zh-CN.md CHANGED
@@ -1,23 +1,186 @@
1
- # Hyper-FS
1
+ <div align="center">
2
+
3
+ # Rush-FS
2
4
 
3
5
  [English](./README.md) | 中文
4
6
 
5
7
  <p align="center">
6
8
  <img src="https://img.shields.io/badge/Written%20in-Rust-orange?style=flat-square" alt="Written in Rust">
7
- <img src="https://img.shields.io/npm/v/hyper-fs?style=flat-square" alt="NPM Version">
8
- <img src="https://img.shields.io/npm/l/hyper-fs?style=flat-square" alt="License">
9
+ <img src="https://img.shields.io/npm/v/rush-fs?style=flat-square" alt="NPM Version">
10
+ <img src="https://img.shields.io/npm/l/rush-fs?style=flat-square" alt="License">
11
+ <a href="https://github.com/CoderSerio/rush-fs/graphs/contributors"><img src="https://img.shields.io/github/contributors/CoderSerio/rush-fs?style=flat-square" alt="Contributors"></a>
9
12
  </p>
10
13
 
11
14
  <p align="center">
12
- Rust 驱动的高性能 Node.js <code>fs</code> 模块「即插即用」替代品。
15
+ Node.js <code>fs</code> API 对齐,可无痛替换现有项目中的 fs;在海量文件操作场景下获得数倍于内置 fs 的性能,由 Rust 驱动。
13
16
  </p>
17
+ </div>
14
18
 
15
19
  ## 安装
16
20
 
17
21
  ```bash
18
- npm install hyper-fs
22
+ npm install rush-fs
19
23
  # or
20
- pnpm add hyper-fs
24
+ pnpm add rush-fs
25
+ ```
26
+
27
+ 安装 `rush-fs` 时,包管理器会通过 `optionalDependencies` 自动安装**当前平台**的本地绑定(例如 macOS ARM 上的 `@rush-fs/rush-fs-darwin-arm64`)。若未安装或出现「Cannot find native binding」:
28
+
29
+ 1. 删除 `node_modules` 和锁文件(`package-lock.json` 或 `pnpm-lock.yaml`)后重新执行 `pnpm install`(或 `npm i`)。
30
+ 2. 或手动安装对应平台包:
31
+ **macOS ARM:** `pnpm add @rush-fs/rush-fs-darwin-arm64`
32
+ **macOS x64:** `pnpm add @rush-fs/rush-fs-darwin-x64`
33
+ **Windows x64:** `pnpm add @rush-fs/rush-fs-win32-x64-msvc`
34
+ **Linux x64 (glibc):** `pnpm add @rush-fs/rush-fs-linux-x64-gnu`
35
+
36
+ ## 用法
37
+
38
+ ```ts
39
+ import { readdir, stat, readFile, writeFile, mkdir, rm } from 'rush-fs'
40
+
41
+ // 读取目录
42
+ const files = await readdir('./src')
43
+
44
+ // 递归 + 返回文件类型
45
+ const entries = await readdir('./src', {
46
+ recursive: true,
47
+ withFileTypes: true,
48
+ })
49
+
50
+ // 读写文件
51
+ const content = await readFile('./package.json', { encoding: 'utf8' })
52
+ await writeFile('./output.txt', 'hello world')
53
+
54
+ // 文件信息
55
+ const s = await stat('./package.json')
56
+ console.log(s.size, s.isFile())
57
+
58
+ // 创建目录
59
+ await mkdir('./new-dir', { recursive: true })
60
+
61
+ // 删除
62
+ await rm('./temp', { recursive: true, force: true })
63
+ ```
64
+
65
+ ## 性能基准
66
+
67
+ > 测试环境:Apple Silicon (arm64),Node.js 24.0.2,release 构建(开启 LTO)。
68
+ > 运行 `pnpm build && pnpm bench` 可复现。
69
+
70
+ ### Rush-FS 显著更快的场景
71
+
72
+ 这些场景中 Rust 的并行遍历和零拷贝 I/O 发挥了真正优势:
73
+
74
+ | 场景 | Node.js | Rush-FS | 加速比 |
75
+ | ------------------------------------------- | --------- | -------- | --------- |
76
+ | `readdir` 递归(node_modules,约 3 万条目) | 281 ms | 23 ms | **12x** |
77
+ | `glob` 递归(`**/*.rs`) | 25 ms | 1.46 ms | **17x** |
78
+ | `glob` 递归 vs fast-glob | 102 ms | 1.46 ms | **70x** |
79
+ | `copyFile` 4 MB | 4.67 ms | 0.09 ms | **50x** |
80
+ | `readFile` 4 MB utf8 | 1.86 ms | 0.92 ms | **2x** |
81
+ | `readFile` 64 KB utf8 | 42 µs | 18 µs | **2.4x** |
82
+ | `rm` 2000 个文件(4 线程) | 92 ms | 53 ms | **1.75x** |
83
+ | `access` R_OK(目录) | 4.18 µs | 1.55 µs | **2.7x** |
84
+ | `cp` 500 文件平铺目录(4 线程) | 86.45 ms | 32.88 ms | **2.6x** |
85
+ | `cp` 树形目录 ~363 节点(4 线程) | 108.73 ms | 46.88 ms | **2.3x** |
86
+
87
+ ### 与 Node.js 持平的场景
88
+
89
+ 单文件操作有约 0.3 µs 的 napi 桥接开销,整体表现基本一致:
90
+
91
+ | 场景 | Node.js | Rush-FS | 比率 |
92
+ | ---------------------------- | ------- | ------- | ---- |
93
+ | `stat`(单文件) | 1.45 µs | 1.77 µs | 1.2x |
94
+ | `readFile` 小文件(Buffer) | 8.86 µs | 9.46 µs | 1.1x |
95
+ | `writeFile` 小文件(string) | 74 µs | 66 µs | 0.9x |
96
+ | `writeFile` 小文件(Buffer) | 115 µs | 103 µs | 0.9x |
97
+ | `appendFile` | 30 µs | 27 µs | 0.9x |
98
+
99
+ ### Node.js 更快的场景
100
+
101
+ 极轻量级的内置调用,napi 开销占比较大:
102
+
103
+ | 场景 | Node.js | Rush-FS | 说明 |
104
+ | -------------------------- | ------- | ------- | ------------------------ |
105
+ | `existsSync`(已存在文件) | 444 ns | 1.34 µs | Node.js 内部有 fast path |
106
+ | `accessSync` F_OK | 456 ns | 1.46 µs | 同上——napi 开销占主导 |
107
+ | `writeFile` 4 MB string | 2.93 ms | 5.69 ms | 大字符串跨 napi 桥传输 |
108
+
109
+ ### 并行支持
110
+
111
+ Rush-FS 在文件系统遍历类操作中使用多线程并行:
112
+
113
+ | API | 并行库 | `concurrency` 选项 | 默认值 |
114
+ | ----------------- | ------------------------------------------------------------------------- | ------------------ | ------ |
115
+ | `readdir`(递归) | [jwalk](https://github.com/Byron/jwalk) | ✅ | auto |
116
+ | `glob` | [ignore](https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore) | ✅ | 4 |
117
+ | `rm`(递归) | [rayon](https://github.com/rayon-rs/rayon) | ✅ | 1 |
118
+ | `cp`(递归) | [rayon](https://github.com/rayon-rs/rayon) | ✅ | 1 |
119
+
120
+ 单文件操作(`stat`、`readFile`、`writeFile`、`chmod` 等)是原子系统调用,不适用并行化。
121
+
122
+ ### 核心结论
123
+
124
+ **Rush-FS 在递归/批量文件系统操作上表现卓越**(readdir、glob、rm、cp),Rust 的并行遍历器带来 2–70 倍加速。单文件操作与 Node.js 基本持平。napi 桥接带来固定约 0.3 µs 的每次调用开销,仅在亚微秒级操作(如 `existsSync`)中有感知。
125
+
126
+ **`cp` 基准详情**(Apple Silicon,release 构建):
127
+
128
+ | 场景 | Node.js | Rush-FS 1 线程 | Rush-FS 4 线程 | Rush-FS 8 线程 |
129
+ | ------------------------------------- | --------- | -------------- | -------------- | -------------- |
130
+ | 平铺目录(500 文件) | 86.45 ms | 61.56 ms | 32.88 ms | 36.67 ms |
131
+ | 树形目录(宽度=4,深度=3,~84 节点) | 23.80 ms | 16.94 ms | 10.62 ms | 9.76 ms |
132
+ | 树形目录(宽度=3,深度=5,~363 节点) | 108.73 ms | 75.39 ms | 46.88 ms | 46.18 ms |
133
+
134
+ `cp` 的最优并发数在 Apple Silicon 上为 **4 线程**——超过后受 I/O 带宽限制,收益趋于平稳。
135
+
136
+ ## 工作原理
137
+
138
+ Node.js 原生的 fs 在底层串行执行,且需要较多内存将系统对象与字符串解析为 JS 形式:
139
+
140
+ ```mermaid
141
+ graph TD
142
+ A["JS: readdir"] -->|Call| B("Node.js C++ Binding")
143
+ B -->|Submit Task| C{"Libuv Thread Pool"}
144
+
145
+ subgraph "Native Layer (Serial)"
146
+ C -->|"Syscall: getdents"| D[OS Kernel]
147
+ D -->|"Return File List"| C
148
+ C -->|"Process Paths"| C
149
+ end
150
+
151
+ C -->|"Results Ready"| E("V8 Main Thread")
152
+
153
+ subgraph "V8 Interaction (Heavy)"
154
+ E -->|"Create JS String 1"| F[V8 Heap]
155
+ E -->|"String 2"| F
156
+ E -->|"String N..."| F
157
+ F -->|"GC Pressure Rising"| F
158
+ end
159
+
160
+ E -->|"Return Array"| G["JS Callback/Promise"]
161
+ ```
162
+
163
+ Rust 实现则把重计算放在 Rust 侧,减少与 V8 的交互与 GC 压力:
164
+
165
+ ```mermaid
166
+ graph TD
167
+ A["JS: readdir"] -->|"N-API Call"| B("Rust Wrapper")
168
+ B -->|"Spawn Thread/Task"| C{"Rust Thread Pool"}
169
+
170
+ subgraph "Rust 'Black Box'"
171
+ C -->|"Rayon: Parallel work"| D[OS Kernel]
172
+ D -->|"Syscall: getdents"| C
173
+ C -->|"Store as Rust Vec<String>"| H[Rust Heap]
174
+ H -->|"No V8 Interaction yet"| H
175
+ end
176
+
177
+ C -->|"All Done"| I("Convert to JS")
178
+
179
+ subgraph "N-API Bridge"
180
+ I -->|"Batch Create JS Array"| J[V8 Heap]
181
+ end
182
+
183
+ J -->|Return| K["JS Result"]
21
184
  ```
22
185
 
23
186
  ## 状态与路线图
@@ -28,7 +191,7 @@ pnpm add hyper-fs
28
191
  >
29
192
  > - ✅:完全支持
30
193
  > - 🚧:部分支持 / 开发中
31
- > - ✨:hyper-fs 的新增能力
194
+ > - ✨:rush-fs 的新增能力
32
195
  > - ❌:暂未支持
33
196
 
34
197
  ### `readdir`
@@ -311,109 +474,23 @@ pnpm add hyper-fs
311
474
 
312
475
  - **状态**:❌
313
476
 
314
- ## 用法
315
-
316
- ```ts
317
- import { readdir, stat, readFile, writeFile, mkdir, rm } from 'hyper-fs'
318
-
319
- // 读取目录
320
- const files = await readdir('./src')
321
-
322
- // 递归 + 返回文件类型
323
- const entries = await readdir('./src', {
324
- recursive: true,
325
- withFileTypes: true,
326
- })
327
-
328
- // 读写文件
329
- const content = await readFile('./package.json', { encoding: 'utf8' })
330
- await writeFile('./output.txt', 'hello world')
331
-
332
- // 文件信息
333
- const s = await stat('./package.json')
334
- console.log(s.size, s.isFile())
335
-
336
- // 创建目录
337
- await mkdir('./new-dir', { recursive: true })
338
-
339
- // 删除
340
- await rm('./temp', { recursive: true, force: true })
341
- ```
342
-
343
- ## 性能基准
344
-
345
- > 测试环境:Apple Silicon (arm64),Node.js 24.0.2,release 构建(开启 LTO)。
346
- > 运行 `pnpm build && pnpm bench` 可复现。
477
+ ## 更新日志
347
478
 
348
- ### Hyper-FS 显著更快的场景
479
+ 各版本变更见 [CHANGELOG.md](./CHANGELOG.md)。发布 tag 列表见 [GitHub Releases](https://github.com/CoderSerio/rush-fs/releases)。
349
480
 
350
- 这些场景中 Rust 的并行遍历和零拷贝 I/O 发挥了真正优势:
351
-
352
- | 场景 | Node.js | Hyper-FS | 加速比 |
353
- | ------------------------------------------- | --------- | -------- | --------- |
354
- | `readdir` 递归(node_modules,约 3 万条目) | 281 ms | 23 ms | **12x** |
355
- | `glob` 递归(`**/*.rs`) | 25 ms | 1.46 ms | **17x** |
356
- | `glob` 递归 vs fast-glob | 102 ms | 1.46 ms | **70x** |
357
- | `copyFile` 4 MB | 4.67 ms | 0.09 ms | **50x** |
358
- | `readFile` 4 MB utf8 | 1.86 ms | 0.92 ms | **2x** |
359
- | `readFile` 64 KB utf8 | 42 µs | 18 µs | **2.4x** |
360
- | `rm` 2000 个文件(4 线程) | 92 ms | 53 ms | **1.75x** |
361
- | `access` R_OK(目录) | 4.18 µs | 1.55 µs | **2.7x** |
362
- | `cp` 500 文件平铺目录(4 线程) | 86.45 ms | 32.88 ms | **2.6x** |
363
- | `cp` 树形目录 ~363 节点(4 线程) | 108.73 ms | 46.88 ms | **2.3x** |
364
-
365
- ### 与 Node.js 持平的场景
366
-
367
- 单文件操作有约 0.3 µs 的 napi 桥接开销,整体表现基本一致:
368
-
369
- | 场景 | Node.js | Hyper-FS | 比率 |
370
- | ---------------------------- | ------- | -------- | ---- |
371
- | `stat`(单文件) | 1.45 µs | 1.77 µs | 1.2x |
372
- | `readFile` 小文件(Buffer) | 8.86 µs | 9.46 µs | 1.1x |
373
- | `writeFile` 小文件(string) | 74 µs | 66 µs | 0.9x |
374
- | `writeFile` 小文件(Buffer) | 115 µs | 103 µs | 0.9x |
375
- | `appendFile` | 30 µs | 27 µs | 0.9x |
376
-
377
- ### Node.js 更快的场景
378
-
379
- 极轻量级的内置调用,napi 开销占比较大:
380
-
381
- | 场景 | Node.js | Hyper-FS | 说明 |
382
- | -------------------------- | ------- | -------- | ------------------------ |
383
- | `existsSync`(已存在文件) | 444 ns | 1.34 µs | Node.js 内部有 fast path |
384
- | `accessSync` F_OK | 456 ns | 1.46 µs | 同上——napi 开销占主导 |
385
- | `writeFile` 4 MB string | 2.93 ms | 5.69 ms | 大字符串跨 napi 桥传输 |
386
-
387
- ### 并行支持
388
-
389
- Hyper-FS 在文件系统遍历类操作中使用多线程并行:
390
-
391
- | API | 并行库 | `concurrency` 选项 | 默认值 |
392
- | ----------------- | ------------------------------------------------------------------------- | ------------------ | ------ |
393
- | `readdir`(递归) | [jwalk](https://github.com/Byron/jwalk) | ✅ | auto |
394
- | `glob` | [ignore](https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore) | ✅ | 4 |
395
- | `rm`(递归) | [rayon](https://github.com/rayon-rs/rayon) | ✅ | 1 |
396
- | `cp`(递归) | [rayon](https://github.com/rayon-rs/rayon) | ✅ | 1 |
397
-
398
- 单文件操作(`stat`、`readFile`、`writeFile`、`chmod` 等)是原子系统调用,不适用并行化。
399
-
400
- ### 核心结论
481
+ ## 贡献
401
482
 
402
- **Hyper-FS 在递归/批量文件系统操作上表现卓越**(readdir、glob、rm、cp),Rust 的并行遍历器带来 2–70 倍加速。单文件操作与 Node.js 基本持平。napi 桥接带来固定约 0.3 µs 的每次调用开销,仅在亚微秒级操作(如 `existsSync`)中有感知。
483
+ 参阅 [CONTRIBUTING-CN.md](./CONTRIBUTING-CN.md) 获取完整开发指南:环境搭建、参考 Node.js 源码、编写 Rust 实现、测试与性能基准。
403
484
 
404
- **`cp` 基准详情**(Apple Silicon,release 构建):
485
+ ## 发布(维护者专用)
405
486
 
406
- | 场景 | Node.js | Hyper-FS 1 线程 | Hyper-FS 4 线程 | Hyper-FS 8 线程 |
407
- | ------------------------------------- | --------- | --------------- | --------------- | --------------- |
408
- | 平铺目录(500 文件) | 86.45 ms | 61.56 ms | 32.88 ms | 36.67 ms |
409
- | 树形目录(宽度=4,深度=3,~84 节点) | 23.80 ms | 16.94 ms | 10.62 ms | 9.76 ms |
410
- | 树形目录(宽度=3,深度=5,~363 节点) | 108.73 ms | 75.39 ms | 46.88 ms | 46.18 ms |
487
+ 发布由 [Release 工作流](.github/workflows/Release.yml) 完成:在 macOS(x64/arm64)、Windows、Linux 上构建原生二进制,并发布各平台包与主包到 npm。
411
488
 
412
- `cp` 的最优并发数在 Apple Silicon 上为 **4 线程**——超过后受 I/O 带宽限制,收益趋于平稳。
413
-
414
- ## 贡献
489
+ 1. **Secrets:** 在仓库 **Settings Secrets and variables → Actions** 中添加 **NPM_TOKEN**(npm Classic 或 Automation token,需具备 Publish 权限)。
490
+ 2. **发布:** 在 **Actions → Release → Run workflow** 中手动运行(使用当前 `main` 上的 `package.json` 版本),或先更新 `package.json` 与 `Cargo.toml` 中的版本号并推送到 `main`,再创建并推送 tag:`git tag v<版本号> && git push origin v<版本号>`。
491
+ 3. **更新日志:** 发布前或发布后更新 [CHANGELOG.md](./CHANGELOG.md)(将 `[Unreleased]` 下的条目移到新版本标题下并补充 compare 链接)。
415
492
 
416
- 参阅 [CONTRIBUTING.md](./CONTRIBUTING.md) 完整的开发指南,涵盖环境搭建、参考 Node.js 源码、编写 Rust 实现、测试与性能基准。
493
+ 工作流会自动注入 `optionalDependencies` 并发布所有包,无需在 `package.json` 中手动填写。
417
494
 
418
495
  ## 许可证
419
496
 
package/index.d.ts CHANGED
@@ -83,7 +83,7 @@ export interface CpOptions {
83
83
  dereference?: boolean
84
84
  verbatimSymlinks?: boolean
85
85
  /**
86
- * Hyper-FS extension: number of parallel threads for recursive copy.
86
+ * Rush-FS extension: number of parallel threads for recursive copy.
87
87
  * 0 or 1 means sequential; > 1 enables rayon parallel traversal.
88
88
  */
89
89
  concurrency?: number
@@ -200,7 +200,7 @@ export declare function rmdirSync(path: string): void
200
200
  * encountered, Node.js retries the operation with a linear backoff of `retryDelay` ms longer on
201
201
  * each try. This option represents the number of retries.
202
202
  * - `retryDelay`: The amount of time in milliseconds to wait between retries (default 100ms).
203
- * - `concurrency` (hyper-fs extension): Number of parallel threads for recursive removal.
203
+ * - `concurrency` (rush-fs extension): Number of parallel threads for recursive removal.
204
204
  */
205
205
  export interface RmOptions {
206
206
  force?: boolean