diff --git a/lib/fs.js b/lib/fs.js index 0031a2b085e..39a1ad6832c 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -52,7 +52,6 @@ const { } = errors.codes; const { FSReqWrap, statValues } = binding; -const { ReadStream, WriteStream } = require('internal/fs/streams'); const internalFS = require('internal/fs/utils'); const { getPathFromURL } = require('internal/url'); const internalUtil = require('internal/util'); @@ -94,6 +93,13 @@ let fs; let promises; let watchers; let ReadFileContext; +let ReadStream; +let WriteStream; + +// These have to be separate because of how graceful-fs happens to do it's +// monkeypatching. +let FileReadStream; +let FileWriteStream; const isWindows = process.platform === 'win32'; @@ -1702,11 +1708,20 @@ function copyFileSync(src, dest, flags) { handleErrorFromBinding(ctx); } +function lazyLoadStreams() { + if (!ReadStream) { + ({ ReadStream, WriteStream } = require('internal/fs/streams')); + [ FileReadStream, FileWriteStream ] = [ ReadStream, WriteStream ]; + } +} + function createReadStream(path, options) { + lazyLoadStreams(); return new ReadStream(path, options); } function createWriteStream(path, options) { + lazyLoadStreams(); return new WriteStream(path, options); } @@ -1790,12 +1805,43 @@ module.exports = fs = { Dirent, Stats, - // Stream constructors - ReadStream, - WriteStream, - // Legacy names... - FileReadStream: ReadStream, - FileWriteStream: WriteStream, + get ReadStream() { + lazyLoadStreams(); + return ReadStream; + }, + + set ReadStream(val) { + ReadStream = val; + }, + + get WriteStream() { + lazyLoadStreams(); + return WriteStream; + }, + + set WriteStream(val) { + WriteStream = val; + }, + + // Legacy names... these have to be separate because of how graceful-fs + // (and possibly other) modules monkey patch the values. + get FileReadStream() { + lazyLoadStreams(); + return FileReadStream; + }, + + set FileReadStream(val) { + FileReadStream = val; + }, + + get FileWriteStream() { + lazyLoadStreams(); + return FileWriteStream; + }, + + set FileWriteStream(val) { + FileWriteStream = val; + }, // For tests _toUnixTimestamp: toUnixTimestamp diff --git a/lib/internal/fs/streams.js b/lib/internal/fs/streams.js index 3eb802c3491..a36166a4b87 100644 --- a/lib/internal/fs/streams.js +++ b/lib/internal/fs/streams.js @@ -8,6 +8,7 @@ const { ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE } = require('internal/errors').codes; +const fs = require('fs'); const { Buffer } = require('buffer'); const { copyObject, @@ -17,13 +18,6 @@ const { Readable, Writable } = require('stream'); const { getPathFromURL } = require('internal/url'); const util = require('util'); -let fs; -function lazyFs() { - if (fs === undefined) - fs = require('fs'); - return fs; -} - const kMinPoolSpace = 128; let pool; @@ -107,7 +101,7 @@ function ReadStream(path, options) { util.inherits(ReadStream, Readable); ReadStream.prototype.open = function() { - lazyFs().open(this.path, this.flags, this.mode, (er, fd) => { + fs.open(this.path, this.flags, this.mode, (er, fd) => { if (er) { if (this.autoClose) { this.destroy(); @@ -157,7 +151,7 @@ ReadStream.prototype._read = function(n) { return this.push(null); // the actual read. - lazyFs().read(this.fd, pool, pool.used, toRead, this.pos, (er, bytesRead) => { + fs.read(this.fd, pool, pool.used, toRead, this.pos, (er, bytesRead) => { if (er) { if (this.autoClose) { this.destroy(); @@ -200,7 +194,7 @@ ReadStream.prototype._destroy = function(err, cb) { }; function closeFsStream(stream, cb, err) { - lazyFs().close(stream.fd, (er) => { + fs.close(stream.fd, (er) => { er = er || err; cb(er); stream.closed = true; @@ -265,7 +259,7 @@ WriteStream.prototype._final = function(callback) { }; WriteStream.prototype.open = function() { - lazyFs().open(this.path, this.flags, this.mode, (er, fd) => { + fs.open(this.path, this.flags, this.mode, (er, fd) => { if (er) { if (this.autoClose) { this.destroy(); @@ -293,7 +287,7 @@ WriteStream.prototype._write = function(data, encoding, cb) { }); } - lazyFs().write(this.fd, data, 0, data.length, this.pos, (er, bytes) => { + fs.write(this.fd, data, 0, data.length, this.pos, (er, bytes) => { if (er) { if (this.autoClose) { this.destroy();