fs: restore fs patchability in ESM loader#62835
fs: restore fs patchability in ESM loader#62835joyeecheung wants to merge 1 commit intonodejs:mainfrom
Conversation
Temporarily restore fs patchability in ESM loader as a workaround for helping downstream projects that depend on this undocumented hidden contract transition into using hook proper APIs. This patch intentionally avoids adding a test and instead adds warning comments to hopefully steer new code away from depending on it.
|
Review requested:
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #62835 +/- ##
==========================================
- Coverage 89.81% 89.63% -0.19%
==========================================
Files 699 706 +7
Lines 216379 219148 +2769
Branches 41366 41981 +615
==========================================
+ Hits 194340 196424 +2084
- Misses 14139 14617 +478
- Partials 7900 8107 +207
🚀 New features to boost your workflow:
|
| // If you are reading this code to figure out how to patch Node.js module loading | ||
| // behavior - DO NOT depend on the patchability in new code: Node.js | ||
| // internals may stop going through the JavaScript fs module entirely. | ||
| // Prefer module.registerHooks() or other more formal fs hooks released in the future. | ||
| source = fs.readFileSync(url); |
There was a problem hiding this comment.
Is this saying that any developer that needs to verify code flowing through fs will need to devise a hook?
test('does not call fs.close on stdout stream', (t) => {
t.plan(2)
const destination = pino.destination({ minLength: 4096, sync: true })
const prettyDestination = pinoPretty({ destination, colorize: false })
const log = pino(prettyDestination)
log.info('this message has been buffered')
const chunks = []
const { close, writeSync } = fs
let closeCalled = false
fs.close = new Proxy(close, {
apply: (target, self, args) => {
closeCalled = true
}
})
fs.writeSync = new Proxy(writeSync, {
apply: (target, self, args) => {
chunks.push(args[1])
return args[1].length
}
})
destination.end()
Object.assign(fs, { close, writeSync })
t.assert.match(chunks.join(''), /INFO .+: this message has been buffered/)
t.assert.strictEqual(closeCalled, false)
})This is inlined and easy to read. I imagine that requiring the same test to go through a hook will be much more difficult to follow and implement.
There was a problem hiding this comment.
This is about module loaders picking up fs or not. In the example you raise the question is whether pino picks up fs or not and that would be orthogonal to our comments here. But yes in general you can't count on random external code to always use certain fs methods for fs operations. Just like Node.js module loaders could be re-written in C++ and there won't be any guarantee that it must reuse any user-patchable public JS APIs in the implementation (for example it already doesn't use any public APIs to read package.json). Only the module hooks are guaranteed to be invoked no matter how the underlying implementation changes.
Temporarily restore fs patchability in ESM loader as a workaround for helping downstream projects that depend on this undocumented hidden contract transition into using hook proper APIs. This patch intentionally avoids adding a test and instead adds warning comments to hopefully steer new code away from depending on it.
Refs: #62012