Skip to content

Commit 5f62170

Browse files
committed
Add fs-extra/esm ESM named import module, with just fs-extra methods
Fixes #746
1 parent 572a1c9 commit 5f62170

File tree

4 files changed

+220
-4
lines changed

4 files changed

+220
-4
lines changed

README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Installation
2727
Usage
2828
-----
2929

30+
### CommonJS
31+
3032
`fs-extra` is a drop in replacement for native `fs`. All methods in `fs` are attached to `fs-extra`. All `fs` methods return promises if the callback isn't passed.
3133

3234
You don't ever need to include the original `fs` module again:
@@ -55,6 +57,31 @@ const fs = require('fs')
5557
const fse = require('fs-extra')
5658
```
5759

60+
### ESM
61+
62+
There is also an `fs-extra/esm` import, that supports both default and named exports. However, note that `fs` methods are not included in `fs-extra/esm`; you still need to import `fs` and/or `fs/promises` seperately:
63+
64+
```js
65+
import { readFileSync } from 'fs'
66+
import { readFile } from 'fs/promises'
67+
import { outputFile, outputFileSync } from 'fs-extra/esm'
68+
```
69+
70+
Default exports are supported:
71+
72+
```js
73+
import fs from 'fs'
74+
import fse from 'fs-extra/esm'
75+
// fse.readFileSync is not a function; must use fs.readFileSync
76+
```
77+
78+
but you probably want to just use regular `fs-extra` instead of `fs-extra/esm` for default exports:
79+
80+
```js
81+
import fs from 'fs-extra'
82+
// both fs and fs-extra methods are defined
83+
```
84+
5885
Sync vs Async vs Async/Await
5986
-------------
6087
Most methods are async by default. All async methods will return a promise if the callback isn't passed.
@@ -197,7 +224,8 @@ fs-extra contains hundreds of tests.
197224

198225
- `npm run lint`: runs the linter ([standard](http://standardjs.com/))
199226
- `npm run unit`: runs the unit tests
200-
- `npm test`: runs both the linter and the tests
227+
- `npm run unit-esm`: runs tests for `fs-extra/esm` exports
228+
- `npm test`: runs the linter and all tests
201229

202230

203231
### Windows

lib/esm.mjs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import _copy from './copy/index.js'
2+
import _empty from './empty/index.js'
3+
import _ensure from './ensure/index.js'
4+
import _json from './json/index.js'
5+
import _mkdirs from './mkdirs/index.js'
6+
import _move from './move/index.js'
7+
import _outputFile from './output-file/index.js'
8+
import _pathExists from './path-exists/index.js'
9+
import _remove from './remove/index.js'
10+
11+
// NOTE: Only exports fs-extra's functions; fs functions must be imported from "node:fs" or "node:fs/promises"
12+
13+
export const copy = _copy.copy
14+
export const copySync = _copy.copySync
15+
export const emptyDirSync = _empty.emptyDirSync
16+
export const emptydirSync = _empty.emptydirSync
17+
export const emptyDir = _empty.emptyDir
18+
export const emptydir = _empty.emptydir
19+
export const createFile = _ensure.createFile
20+
export const createFileSync = _ensure.createFileSync
21+
export const ensureFile = _ensure.ensureFile
22+
export const ensureFileSync = _ensure.ensureFileSync
23+
export const createLink = _ensure.createLink
24+
export const createLinkSync = _ensure.createLinkSync
25+
export const ensureLink = _ensure.ensureLink
26+
export const ensureLinkSync = _ensure.ensureLinkSync
27+
export const createSymlink = _ensure.createSymlink
28+
export const createSymlinkSync = _ensure.createSymlinkSync
29+
export const ensureSymlink = _ensure.ensureSymlink
30+
export const ensureSymlinkSync = _ensure.ensureSymlinkSync
31+
export const readJson = _json.readJson
32+
export const readJSON = _json.readJSON
33+
export const readJsonSync = _json.readJsonSync
34+
export const readJSONSync = _json.readJSONSync
35+
export const writeJson = _json.writeJson
36+
export const writeJSON = _json.writeJSON
37+
export const writeJsonSync = _json.writeJsonSync
38+
export const writeJSONSync = _json.writeJSONSync
39+
export const outputJson = _json.outputJson
40+
export const outputJSON = _json.outputJSON
41+
export const outputJsonSync = _json.outputJsonSync
42+
export const outputJSONSync = _json.outputJSONSync
43+
export const mkdirs = _mkdirs.mkdirs
44+
export const mkdirsSync = _mkdirs.mkdirsSync
45+
export const mkdirp = _mkdirs.mkdirp
46+
export const mkdirpSync = _mkdirs.mkdirpSync
47+
export const ensureDir = _mkdirs.ensureDir
48+
export const ensureDirSync = _mkdirs.ensureDirSync
49+
export const move = _move.move
50+
export const moveSync = _move.moveSync
51+
export const outputFile = _outputFile.outputFile
52+
export const outputFileSync = _outputFile.outputFileSync
53+
export const pathExists = _pathExists.pathExists
54+
export const pathExistsSync = _pathExists.pathExistsSync
55+
export const remove = _remove.remove
56+
export const removeSync = _remove.removeSync
57+
58+
export default {
59+
..._copy,
60+
..._empty,
61+
..._ensure,
62+
..._json,
63+
..._mkdirs,
64+
..._move,
65+
..._outputFile,
66+
..._pathExists,
67+
..._remove
68+
}

package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,20 @@
5151
"read-dir-files": "^0.1.1",
5252
"standard": "^16.0.3"
5353
},
54-
"exports": "./lib/index.js",
54+
"exports": {
55+
".": "./lib/index.js",
56+
"./esm": "./lib/esm.mjs"
57+
},
5558
"files": [
5659
"lib/",
5760
"!lib/**/__tests__/"
5861
],
5962
"scripts": {
6063
"lint": "standard",
6164
"test-find": "find ./lib/**/__tests__ -name *.test.js | xargs mocha",
62-
"test": "npm run lint && npm run unit",
63-
"unit": "nyc node test.js"
65+
"test": "npm run lint && npm run unit && npm run unit-esm",
66+
"unit": "nyc node test.js",
67+
"unit-esm": "node test.mjs"
6468
},
6569
"sideEffects": false
6670
}

test.mjs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import assert from 'node:assert/strict'
2+
import fsLegacy from './lib/index.js'
3+
// NOTE: eslint comments needed because we're importing the same file multiple times
4+
import fsDefault from './lib/esm.mjs' // eslint-disable-line
5+
import * as fsStar from './lib/esm.mjs'
6+
import {
7+
copy,
8+
copySync,
9+
emptyDirSync,
10+
emptydirSync,
11+
emptyDir,
12+
emptydir,
13+
createFile,
14+
createFileSync,
15+
ensureFile,
16+
ensureFileSync,
17+
createLink,
18+
createLinkSync,
19+
ensureLink,
20+
ensureLinkSync,
21+
createSymlink,
22+
createSymlinkSync,
23+
ensureSymlink,
24+
ensureSymlinkSync,
25+
readJson,
26+
readJsonSync,
27+
writeJson,
28+
writeJsonSync,
29+
outputJson,
30+
outputJsonSync,
31+
outputJSON,
32+
outputJSONSync,
33+
writeJSON,
34+
writeJSONSync,
35+
readJSON,
36+
readJSONSync,
37+
mkdirs,
38+
mkdirsSync,
39+
mkdirp,
40+
mkdirpSync,
41+
ensureDir,
42+
ensureDirSync,
43+
move,
44+
moveSync,
45+
outputFile,
46+
outputFileSync,
47+
pathExists,
48+
pathExistsSync,
49+
remove,
50+
removeSync
51+
} from './lib/esm.mjs' // eslint-disable-line
52+
const fsNamed = [
53+
copy,
54+
copySync,
55+
emptyDirSync,
56+
emptydirSync,
57+
emptyDir,
58+
emptydir,
59+
createFile,
60+
createFileSync,
61+
ensureFile,
62+
ensureFileSync,
63+
createLink,
64+
createLinkSync,
65+
ensureLink,
66+
ensureLinkSync,
67+
createSymlink,
68+
createSymlinkSync,
69+
ensureSymlink,
70+
ensureSymlinkSync,
71+
readJson,
72+
readJsonSync,
73+
writeJson,
74+
writeJsonSync,
75+
outputJson,
76+
outputJsonSync,
77+
outputJSON,
78+
outputJSONSync,
79+
writeJSON,
80+
writeJSONSync,
81+
readJSON,
82+
readJSONSync,
83+
mkdirs,
84+
mkdirsSync,
85+
mkdirp,
86+
mkdirpSync,
87+
ensureDir,
88+
ensureDirSync,
89+
move,
90+
moveSync,
91+
outputFile,
92+
outputFileSync,
93+
pathExists,
94+
pathExistsSync,
95+
remove,
96+
removeSync
97+
]
98+
99+
const keys = Object.keys(fsDefault)
100+
101+
assert.deepEqual(Object.values(fsDefault), fsNamed, 'named and default exports should match')
102+
assert.deepEqual(
103+
Object.entries(fsStar)
104+
.filter(([name]) => name !== 'default') // remove "default" property here
105+
.sort(([nameA], [nameB]) => keys.indexOf(nameA) - keys.indexOf(nameB)) // sort for exact match
106+
.map(([name, fn]) => fn),
107+
Object.values(fsDefault),
108+
'star and default exports should match'
109+
)
110+
111+
// default exports a subset of the legacy implementation, but functions are the same
112+
Object.entries(fsDefault).forEach(([name, fn]) => {
113+
assert.equal(fn, fsLegacy[name], `${name}() should match legacy implementation`)
114+
})
115+
116+
console.warn('ESM tests pass!')

0 commit comments

Comments
 (0)