@zenfs/core 0.2.1 → 0.2.2

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.
@@ -4,5 +4,5 @@ export * as promises from './promises.js';
4
4
  export * as constants from './constants.js';
5
5
  export * from './streams.js';
6
6
  export * from './dir.js';
7
- export { initialize, getMount, getMounts, mount, umount, _toUnixTimestamp } from './shared.js';
7
+ export { initialize, mounts, mount, umount, _toUnixTimestamp } from './shared.js';
8
8
  export { Stats, BigIntStats } from '../stats.js';
@@ -4,5 +4,5 @@ export * as promises from './promises.js';
4
4
  export * as constants from './constants.js';
5
5
  export * from './streams.js';
6
6
  export * from './dir.js';
7
- export { initialize, getMount, getMounts, mount, umount, _toUnixTimestamp } from './shared.js';
7
+ export { initialize, mounts, mount, umount, _toUnixTimestamp } from './shared.js';
8
8
  export { Stats, BigIntStats } from '../stats.js';
@@ -5,16 +5,38 @@ import type { File } from '../file.js';
5
5
  /**
6
6
  * converts Date or number to a integer UNIX timestamp
7
7
  * Grabbed from NodeJS sources (lib/fs.js)
8
+ *
9
+ * @internal
8
10
  */
9
11
  export declare function _toUnixTimestamp(time: Date | number): number;
12
+ /**
13
+ * Normalizes a mode
14
+ * @internal
15
+ */
10
16
  export declare function normalizeMode(mode: string | number | unknown, def?: number): number;
17
+ /**
18
+ * Normalizes a time
19
+ * @internal
20
+ */
11
21
  export declare function normalizeTime(time: string | number | Date): Date;
22
+ /**
23
+ * Normalizes a path
24
+ * @internal
25
+ */
12
26
  export declare function normalizePath(p: string): string;
13
- export declare function normalizeOptions(options: any, defEnc: string | null, defFlag: string, defMode: number | null): {
27
+ /**
28
+ * Normalizes options
29
+ * @internal
30
+ */
31
+ export declare function normalizeOptions(options: unknown, defEnc: string | null, defFlag: string, defMode: number | null): {
14
32
  encoding: BufferEncoding;
15
33
  flag: string;
16
34
  mode: number;
17
35
  };
36
+ /**
37
+ * Do nothing
38
+ * @internal
39
+ */
18
40
  export declare function nop(): void;
19
41
  export declare let cred: Cred;
20
42
  export declare function setCred(val: Cred): void;
@@ -24,15 +46,11 @@ export declare function fd2file(fd: number): File;
24
46
  export interface MountMapping {
25
47
  [point: string]: FileSystem;
26
48
  }
27
- export declare const mounts: Map<string, FileSystem>;
28
- /**
29
- * Gets the file system mounted at `mountPoint`
30
- */
31
- export declare function getMount(mountPoint: string): FileSystem;
32
49
  /**
33
- * Gets an object of mount points (keys) and filesystems (values)
50
+ * The map of mount points
51
+ * @internal
34
52
  */
35
- export declare function getMounts(): MountMapping;
53
+ export declare const mounts: Map<string, FileSystem>;
36
54
  /**
37
55
  * Mounts the file system at the given mount point.
38
56
  */
@@ -6,6 +6,8 @@ import { InMemory } from '../backends/InMemory.js';
6
6
  /**
7
7
  * converts Date or number to a integer UNIX timestamp
8
8
  * Grabbed from NodeJS sources (lib/fs.js)
9
+ *
10
+ * @internal
9
11
  */
10
12
  export function _toUnixTimestamp(time) {
11
13
  if (typeof time === 'number') {
@@ -16,6 +18,10 @@ export function _toUnixTimestamp(time) {
16
18
  }
17
19
  throw new Error('Cannot parse time: ' + time);
18
20
  }
21
+ /**
22
+ * Normalizes a mode
23
+ * @internal
24
+ */
19
25
  export function normalizeMode(mode, def) {
20
26
  switch (typeof mode) {
21
27
  case 'number':
@@ -33,6 +39,10 @@ export function normalizeMode(mode, def) {
33
39
  }
34
40
  throw new ApiError(ErrorCode.EINVAL, 'Invalid mode: ' + mode?.toString());
35
41
  }
42
+ /**
43
+ * Normalizes a time
44
+ * @internal
45
+ */
36
46
  export function normalizeTime(time) {
37
47
  if (time instanceof Date) {
38
48
  return time;
@@ -45,6 +55,10 @@ export function normalizeTime(time) {
45
55
  }
46
56
  throw new ApiError(ErrorCode.EINVAL, 'Invalid time.');
47
57
  }
58
+ /**
59
+ * Normalizes a path
60
+ * @internal
61
+ */
48
62
  export function normalizePath(p) {
49
63
  // Node doesn't allow null characters in paths.
50
64
  if (p.indexOf('\u0000') >= 0) {
@@ -56,6 +70,10 @@ export function normalizePath(p) {
56
70
  p = p.replaceAll(/\/+/g, '/');
57
71
  return resolve(p);
58
72
  }
73
+ /**
74
+ * Normalizes options
75
+ * @internal
76
+ */
59
77
  export function normalizeOptions(options, defEnc, defFlag, defMode) {
60
78
  // typeof null === 'object' so special-case handing is needed.
61
79
  switch (options === null ? 'null' : typeof options) {
@@ -83,6 +101,10 @@ export function normalizeOptions(options, defEnc, defFlag, defMode) {
83
101
  throw new TypeError(`"options" must be a string or an object, got ${typeof options} instead.`);
84
102
  }
85
103
  }
104
+ /**
105
+ * Do nothing
106
+ * @internal
107
+ */
86
108
  export function nop() {
87
109
  // do nothing
88
110
  }
@@ -105,23 +127,15 @@ export function fd2file(fd) {
105
127
  }
106
128
  return fdMap.get(fd);
107
129
  }
130
+ /**
131
+ * The map of mount points
132
+ * @internal
133
+ */
108
134
  export const mounts = new Map();
109
135
  /*
110
136
  Set a default root.
111
137
  */
112
138
  mount('/', InMemory.create({ name: 'root' }));
113
- /**
114
- * Gets the file system mounted at `mountPoint`
115
- */
116
- export function getMount(mountPoint) {
117
- return mounts.get(mountPoint);
118
- }
119
- /**
120
- * Gets an object of mount points (keys) and filesystems (values)
121
- */
122
- export function getMounts() {
123
- return Object.fromEntries(mounts.entries());
124
- }
125
139
  /**
126
140
  * Mounts the file system at the given mount point.
127
141
  */
@@ -171,6 +171,15 @@ export declare abstract class SyncFileSystem extends FileSystem {
171
171
  link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
172
172
  sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
173
173
  }
174
+ export declare abstract class ReadonlySyncFileSystem extends SyncFileSystem {
175
+ renameSync(oldPath: string, newPath: string, cred: Cred): void;
176
+ createFileSync(path: string, flag: FileFlag, mode: number, cred: Cred): File;
177
+ unlinkSync(path: string, cred: Cred): void;
178
+ rmdirSync(path: string, cred: Cred): void;
179
+ mkdirSync(path: string, mode: number, cred: Cred): void;
180
+ linkSync(srcpath: string, dstpath: string, cred: Cred): void;
181
+ syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
182
+ }
174
183
  export declare abstract class AsyncFileSystem extends FileSystem {
175
184
  renameSync(oldPath: string, newPath: string, cred: Cred): void;
176
185
  statSync(path: string, cred: Cred): Stats;
@@ -184,3 +193,12 @@ export declare abstract class AsyncFileSystem extends FileSystem {
184
193
  linkSync(srcpath: string, dstpath: string, cred: Cred): void;
185
194
  syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
186
195
  }
196
+ export declare abstract class ReadonlyAsyncFileSystem extends AsyncFileSystem {
197
+ rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
198
+ createFile(path: string, flag: FileFlag, mode: number, cred: Cred): Promise<File>;
199
+ unlink(path: string, cred: Cred): Promise<void>;
200
+ rmdir(path: string, cred: Cred): Promise<void>;
201
+ mkdir(path: string, mode: number, cred: Cred): Promise<void>;
202
+ link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
203
+ sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
204
+ }
@@ -94,6 +94,29 @@ export class SyncFileSystem extends FileSystem {
94
94
  return this.syncSync(path, data, stats);
95
95
  }
96
96
  }
97
+ export class ReadonlySyncFileSystem extends SyncFileSystem {
98
+ renameSync(oldPath, newPath, cred) {
99
+ throw new ApiError(ErrorCode.EROFS);
100
+ }
101
+ createFileSync(path, flag, mode, cred) {
102
+ throw new ApiError(ErrorCode.EROFS);
103
+ }
104
+ unlinkSync(path, cred) {
105
+ throw new ApiError(ErrorCode.EROFS);
106
+ }
107
+ rmdirSync(path, cred) {
108
+ throw new ApiError(ErrorCode.EROFS);
109
+ }
110
+ mkdirSync(path, mode, cred) {
111
+ throw new ApiError(ErrorCode.EROFS);
112
+ }
113
+ linkSync(srcpath, dstpath, cred) {
114
+ throw new ApiError(ErrorCode.EROFS);
115
+ }
116
+ syncSync(path, data, stats) {
117
+ throw new ApiError(ErrorCode.EROFS);
118
+ }
119
+ }
97
120
  export class AsyncFileSystem extends FileSystem {
98
121
  renameSync(oldPath, newPath, cred) {
99
122
  throw new ApiError(ErrorCode.ENOTSUP);
@@ -129,3 +152,26 @@ export class AsyncFileSystem extends FileSystem {
129
152
  throw new ApiError(ErrorCode.ENOTSUP);
130
153
  }
131
154
  }
155
+ export class ReadonlyAsyncFileSystem extends AsyncFileSystem {
156
+ async rename(oldPath, newPath, cred) {
157
+ throw new ApiError(ErrorCode.EROFS);
158
+ }
159
+ async createFile(path, flag, mode, cred) {
160
+ throw new ApiError(ErrorCode.EROFS);
161
+ }
162
+ async unlink(path, cred) {
163
+ throw new ApiError(ErrorCode.EROFS);
164
+ }
165
+ async rmdir(path, cred) {
166
+ throw new ApiError(ErrorCode.EROFS);
167
+ }
168
+ async mkdir(path, mode, cred) {
169
+ throw new ApiError(ErrorCode.EROFS);
170
+ }
171
+ async link(srcpath, dstpath, cred) {
172
+ throw new ApiError(ErrorCode.EROFS);
173
+ }
174
+ async sync(path, data, stats) {
175
+ throw new ApiError(ErrorCode.EROFS);
176
+ }
177
+ }
package/dist/index.d.ts CHANGED
@@ -31,7 +31,6 @@ export * from './backends/AsyncStore.js';
31
31
  export * from './backends/SyncStore.js';
32
32
  export * from './ApiError.js';
33
33
  export * from './cred.js';
34
- export * from './FileIndex.js';
35
34
  export * from './file.js';
36
35
  export * from './filesystem.js';
37
36
  export * from './inode.js';
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import { setCred } from './emulation/shared.js';
12
12
  */
13
13
  export function initialize(mounts, uid = 0, gid = 0) {
14
14
  setCred(new Cred(uid, gid, uid, gid, uid, gid));
15
- return fs.initialize(mounts);
15
+ fs.initialize(mounts);
16
16
  }
17
17
  /**
18
18
  * Creates filesystems with the given configuration, and initializes ZenFS with it.
@@ -39,14 +39,13 @@ export async function configure(config) {
39
39
  }
40
40
  config[point] = await resolveBackendConfig(value);
41
41
  }
42
- return initialize(config);
42
+ initialize(config);
43
43
  }
44
44
  export * from './backends/index.js';
45
45
  export * from './backends/AsyncStore.js';
46
46
  export * from './backends/SyncStore.js';
47
47
  export * from './ApiError.js';
48
48
  export * from './cred.js';
49
- export * from './FileIndex.js';
50
49
  export * from './file.js';
51
50
  export * from './filesystem.js';
52
51
  export * from './inode.js';
package/dist/utils.d.ts CHANGED
@@ -1,8 +1,5 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  /// <reference types="node" resolution-mode="require"/>
3
- /**
4
- * Grab bag of utility functions used across the code.
5
- */
6
3
  import { FileSystem } from './filesystem.js';
7
4
  import { Cred } from './cred.js';
8
5
  import type { TextDecoder as _TextDecoder, TextEncoder as _TextEncoder } from 'node:util';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "A filesystem in your browser",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist",
package/readme.md CHANGED
@@ -7,14 +7,13 @@ ZenFS is an in-browser file system that emulates the [Node JS file system API](h
7
7
  ZenFS is highly extensible, and includes many builtin filesystem backends:
8
8
 
9
9
  - `InMemory`: Stores files in-memory. It is a temporary file store that clears when the user navigates away.
10
- - `OverlayFS`: Mount a read-only file system as read-write by overlaying a writable file system on top of it. Like Docker's overlayfs, it will only write changed files to the writable file system.
10
+ - `Overlay`: Mount a read-only file system as read-write by overlaying a writable file system on top of it. Like Docker's overlayfs, it will only write changed files to the writable file system.
11
11
  - `AsyncMirror`: Use an asynchronous backend synchronously. Invaluable for Emscripten; let your Emscripten applications write to larger file stores with no additional effort!
12
12
  - `AsyncMirror` loads the entire contents of the async file system into a synchronous backend during construction. It performs operations synchronous file system and then queues them to be mirrored onto the asynchronous backend.
13
- - `FolderAdapter`: Wraps a file system, and scopes all interactions to a subfolder of that file system.
14
13
 
15
14
  More backends can be defined by separate libraries, so long as they extend they implement `ZenFS.FileSystem`. Multiple backends can be active at once at different locations in the directory hierarchy.
16
15
 
17
- ZenFS supports a number of other backends (as `@zenfs/fs-[name]`).
16
+ ZenFS supports a number of other backends (many are provided as seperate packages under `@zenfs`).
18
17
 
19
18
  For more information, see the [API documentation for ZenFS](https://zen-fs.github.io/core).
20
19
 
@@ -24,13 +23,6 @@ For more information, see the [API documentation for ZenFS](https://zen-fs.githu
24
23
  npm install @zenfs/core
25
24
  ```
26
25
 
27
- ## Building
28
-
29
- - Make sure you have Node and NPM installed. You must have Node v18 or newer.
30
- - Install dependencies with `npm install`
31
- - Build using `npm run build`
32
- - You can find the built code in `dist`.
33
-
34
26
  ## Usage
35
27
 
36
28
  > 🛈 The examples are written in ESM. If you are using CJS, you can `require` the package. If running in a browser you can add a script tag to your HTML pointing to the `browser.min.js` and use ZenFS via the global `ZenFS` object.
@@ -46,15 +38,13 @@ console.log(contents);
46
38
 
47
39
  #### Using different backends
48
40
 
49
- A `InMemory` backend is created by default. If you would like to use a different one, you must configure ZenFS. It is recommended to do so using the `configure` function. Here is an example using the `Storage` backend from `@zenfs/fs-dom`:
41
+ A `InMemory` backend is created by default. If you would like to use a different one, you must configure ZenFS. It is recommended to do so using the `configure` function. Here is an example using the `Storage` backend from `@zenfs/dom`:
50
42
 
51
43
  ```js
52
- import { configure, fs, registerBackend } from '@zenfs/core';
53
- import { StorageFileSystem } from '@zenfs/fs-dom';
54
- registerBackend(StorageFileSystem);
44
+ import { configure, fs } from '@zenfs/core';
45
+ import { StorageStore } from '@zenfs/dom';
55
46
 
56
- // you can also add a callback as the last parameter instead of using promises
57
- await configure({ fs: 'Storage' });
47
+ await configure({ backend: StorageStore });
58
48
 
59
49
  if (!fs.existsSync('/test.txt')) {
60
50
  fs.writeFileSync('/test.txt', 'This will persist across reloads!');
@@ -69,23 +59,19 @@ console.log(contents);
69
59
  You can use multiple backends by passing an object to `configure` which maps paths to file systems. The following example mounts a zip file to `/zip`, in-memory storage to `/tmp`, and IndexedDB storage to `/home` (note that `/` has the default in-memory backend):
70
60
 
71
61
  ```js
72
- import { configure, registerBackend } from '@zenfs/core';
73
- import { IndexedDBFileSystem } from '@zenfs/fs-dom';
74
- import { ZipFS } from '@zenfs/fs-zip';
75
- import Buffer from 'buffer';
76
- registerBackend(IndexedDBFileSystem, ZipFS);
62
+ import { configure } from '@zenfs/core';
63
+ import { IndexedDB } from '@zenfs/dom';
64
+ import { Zip } from '@zenfs/zip';
77
65
 
78
66
  const zipData = await (await fetch('mydata.zip')).arrayBuffer();
79
67
 
80
68
  await configure({
81
69
  '/mnt/zip': {
82
- fs: 'ZipFS',
83
- options: {
84
- zipData: Buffer.from(zipData)
85
- }
70
+ backend: Zip,
71
+ zipData: zipData,
86
72
  },
87
73
  '/tmp': 'InMemory',
88
- '/home': 'IndexedDB',
74
+ '/home': IndexedDB,
89
75
  };
90
76
  ```
91
77
 
@@ -94,11 +80,10 @@ await configure({
94
80
  The FS promises API is exposed as `promises`.
95
81
 
96
82
  ```js
97
- import { configure, promises, registerBackend } from '@zenfs/core';
98
- import { IndexedDBFileSystem } from '@zenfs/fs-dom';
99
- registerBackend(IndexedDBFileSystem);
83
+ import { configure, promises } from '@zenfs/core';
84
+ import { IndexedDB } from '@zenfs/dom';
100
85
 
101
- await configure({ '/': 'IndexedDB' });
86
+ await configure({ '/': IndexedDB });
102
87
 
103
88
  const exists = await promises.exists('/myfile.txt');
104
89
  if (!exists) {
@@ -106,46 +91,48 @@ if (!exists) {
106
91
  }
107
92
  ```
108
93
 
109
- ZenFS does _not_ provide a seperate method for importing promises in its built form. If you are using Typescript, you can import the promises API from source code (perhaps to reduce you bundle size). Doing so it not recommended as the files may be moved without notice.
94
+ ZenFS does _not_ provide a seperate public import for importing promises in its built form. If you are using ESM, you can import promises functions from `dist/emulation/promises`, though this may change at any time and is not recommended.
110
95
 
111
96
  #### Using asynchronous backends synchronously
112
97
 
113
- You may have noticed that attempting to use a synchronous method on an asynchronous backend (e.g. IndexedDB) results in a "not supplied" error (`ENOTSUP`). If you wish to use an asynchronous backend synchronously you need to wrap it in an `AsyncMirror`:
98
+ You may have noticed that attempting to use a synchronous function on an asynchronous backend (e.g. IndexedDB) results in a "not supplied" error (`ENOTSUP`). If you wish to use an asynchronous backend synchronously you need to wrap it in an `AsyncMirror`:
114
99
 
115
100
  ```js
116
101
  import { configure, fs } from '@zenfs/core';
117
- import { IndexedDBFileSystem } from '@zenfs/fs-dom';
118
- registerBackend(IndexedDBFileSystem);
102
+ import { IndexedDB } from '@zenfs/dom';
119
103
 
120
104
  await configure({
121
- '/': { fs: 'AsyncMirror', options: { sync: { fs: 'InMemory' }, async: { fs: 'IndexedDB' } } }
105
+ '/': {
106
+ backend: 'AsyncMirror',
107
+ sync: 'InMemory',
108
+ async: IndexedDB,
109
+ },
122
110
  });
123
111
 
124
- fs.writeFileSync('/persistant.txt', 'My persistant data'); // This fails if you configure the FS as IndexedDB
112
+ fs.writeFileSync('/persistant.txt', 'My persistant data'); // This fails if you configure with only IndexedDB
125
113
  ```
126
114
 
127
115
  ### Advanced usage
128
116
 
129
117
  #### Creating backends
130
118
 
131
- If you would like to create backends without configure, you may do so by importing the backend's class and calling its `Create` method. You can import the backend directly or with `backends`:
119
+ If you would like to create backends without configure, you may do so by importing the backend and calling `createBackend` with it. You can import the backend directly or with `backends`:
132
120
 
133
121
  ```js
134
122
  import { configure, backends, InMemory } from '@zenfs/core';
135
123
 
136
- console.log(backends.InMemory === InMemory) // they are the same
124
+ console.log(backends.InMemory === InMemory); // they are the same
137
125
 
138
- const inMemoryFS = await InMemory.Create();
126
+ const internalInMemoryFS = await createBackend(InMemory);
139
127
  ```
140
128
 
141
- > ⚠ Instances of backends follow the ***internal*** ZenFS API. You should never use a backend's method unless you are extending a backend.
129
+ > ⚠ Instances of backends follow the **_internal_** ZenFS API. You should never use a backend's methods unless you are extending a backend.
142
130
 
143
- Coming soon:
144
131
  ```js
145
132
  import { configure, InMemory } from '@zenfs/core';
146
133
 
147
- const inMemoryFS = new InMemory();
148
- await inMemoryFS.whenReady();
134
+ const internalInMemoryFS = new InMemory();
135
+ await internalInMemoryFS.ready();
149
136
  ```
150
137
 
151
138
  #### Mounting
@@ -155,9 +142,9 @@ If you would like to mount and unmount backends, you can do so using the `mount`
155
142
  ```js
156
143
  import { fs, InMemory } from '@zenfs/core';
157
144
 
158
- const inMemoryFS = await InMemory.Create(); // create an FS instance
145
+ const internalInMemoryFS = await createBackend(InMemory); // create an FS instance
159
146
 
160
- fs.mount('/tmp', inMemoryFS); // mount
147
+ fs.mount('/tmp', internalInMemoryFS); // mount
161
148
 
162
149
  fs.umount('/tmp'); // unmount /tmp
163
150
  ```
@@ -165,10 +152,8 @@ fs.umount('/tmp'); // unmount /tmp
165
152
  This could be used in the "multiple backends" example like so:
166
153
 
167
154
  ```js
168
- import { IndexedDBFileSystem } from '@zenfs/fs-dom';
169
- import { ZipFS } from '@zenfs/fs-zip';
170
- import Buffer from 'buffer';
171
- registerBackend(IndexedDBFileSystem);
155
+ import { IndexedDB } from '@zenfs/dom';
156
+ import { Zip } from '@zenfs/zip';
172
157
 
173
158
  await configure({
174
159
  '/tmp': 'InMemory',
@@ -178,8 +163,7 @@ await configure({
178
163
  fs.mkdirSync('/mnt');
179
164
 
180
165
  const res = await fetch('mydata.zip');
181
- const zipData = Buffer.from(await res.arrayBuffer());
182
- const zipFs = await ZipFS.Create({ zipData });
166
+ const zipFs = await createBackend(Zip, { zipData: await res.arrayBuffer() });
183
167
  fs.mount('/mnt/zip', zipFs);
184
168
 
185
169
  // do stuff with the mounted zip
@@ -191,64 +175,12 @@ fs.umount('/mnt/zip'); // finished using the zip
191
175
 
192
176
  ZenFS exports a drop-in for Node's `fs` module (up to the version of `@types/node` in package.json), so you can use it for your bundler of preference using the default export.
193
177
 
194
- #### ESBuild
195
-
196
- tsconfig.json
197
-
198
- ```json
199
- {
200
- ...
201
- "paths": {
202
- "fs": ["node_modules/zenfs/dist/index.js"]
203
- }
204
- ...
205
- }
206
- ```
207
-
208
- [Why tsconfig.json?](https://stackoverflow.com/a/71935037/17637456)
209
-
210
- Webpack:
211
-
212
- ```js
213
- module.exports = {
214
- // ...
215
- resolve: {
216
- alias: {
217
- fs: require.resolve('zenfs'),
218
- },
219
- },
220
- // ...
221
- };
222
- ```
223
-
224
- Rollup:
225
-
226
- ```js
227
- import alias from '@rollup/plugin-alias';
228
-
229
- export default {
230
- // ...
231
- plugins: [
232
- alias({
233
- entries: [{ find: 'fs', replacement: 'zenfs' }],
234
- }),
235
- ],
236
- // ...
237
- };
238
- ```
239
-
240
- ## Using with Emscripten
241
-
242
- You can use any _synchronous_ ZenFS file systems with Emscripten.
243
-
244
- ```js
245
- import { EmscriptenFSPlugin } from '@zenfs/fs-emscripten';
246
- const BFS = new EmscriptenFSPlugin(); // Create a ZenFS Emscripten FS plugin.
247
- FS.createFolder(FS.root, 'data', true, true); // Create the folder to turn into a mount point.
248
- FS.mount(BFS, { root: '/' }, '/data'); // Mount BFS's root folder into /data.
249
- ```
178
+ ## Building
250
179
 
251
- If you want to use an asynchronous backend, you must wrap it in an `AsyncMirror`.
180
+ - Make sure you have Node and NPM installed. You must have Node v18 or newer.
181
+ - Install dependencies with `npm install`
182
+ - Build using `npm run build`
183
+ - You can find the built code in `dist`.
252
184
 
253
185
  ### Testing
254
186