From ff90a3ab44117c65e3ecd2d35030f1d81ca5e187 Mon Sep 17 00:00:00 2001 From: Christian Mortaro Date: Sat, 4 Mar 2023 17:01:25 -0300 Subject: [PATCH] fix: add writeToDisk support for clean: true --- src/index.js | 4 +-- src/utils/setupWriteToDisk.js | 14 +++++++++ test/utils/setupWriteToDisk.test.js | 44 +++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 0d6d6dec0..92760a763 100644 --- a/src/index.js +++ b/src/index.js @@ -183,12 +183,12 @@ function wdm(compiler, options = {}) { setupHooks(context); + setupOutputFileSystem(context); + if (options.writeToDisk) { setupWriteToDisk(context); } - setupOutputFileSystem(context); - // Start watching if (/** @type {Compiler} */ (context.compiler).watching) { context.watching = /** @type {Compiler} */ (context.compiler).watching; diff --git a/src/utils/setupWriteToDisk.js b/src/utils/setupWriteToDisk.js index 4ac3af302..1a9caebc3 100644 --- a/src/utils/setupWriteToDisk.js +++ b/src/utils/setupWriteToDisk.js @@ -21,6 +21,20 @@ function setupWriteToDisk(context) { (context.compiler).compilers || [context.compiler]; for (const compiler of compilers) { + if (compiler.outputFileSystem && compiler.options.output.clean) { + /** @type {Compiler["outputFileSystem"]} */ + const { unlink: originalUnlink } = compiler.outputFileSystem; + if (originalUnlink) { + compiler.outputFileSystem.unlink = ( + /** @type {String} */ originalPath, + /** @type {(arg0?: null | NodeJS.ErrnoException) => void} */ originalCallback + ) => { + fs.unlink(originalPath, () => {}); + originalUnlink(originalPath, originalCallback); + }; + } + } + compiler.hooks.emit.tap( "DevMiddleware", /** diff --git a/test/utils/setupWriteToDisk.test.js b/test/utils/setupWriteToDisk.test.js index 74a281609..e409d013f 100644 --- a/test/utils/setupWriteToDisk.test.js +++ b/test/utils/setupWriteToDisk.test.js @@ -5,6 +5,7 @@ import setupWriteToDisk from "../../src/utils/setupWriteToDisk"; const mkdirSpy = jest.spyOn(fs, "mkdir"); const writeFileSpy = jest.spyOn(fs, "writeFile"); +const unlinkFileSpy = jest.spyOn(fs, "unlink"); describe("setupWriteToDisk", () => { let context; @@ -41,6 +42,7 @@ describe("setupWriteToDisk", () => { getPath.mockClear(); mkdirSpy.mockClear(); writeFileSpy.mockClear(); + unlinkFileSpy.mockClear(); }); const runAssetEmitted = (...args) => { @@ -180,4 +182,46 @@ describe("setupWriteToDisk", () => { expect(cb.mock.calls).toMatchSnapshot(); }); }); + + const cleanOptions = [ + { + title: "true", + value: true, + }, + { + title: "false", + value: false, + }, + { + title: "an object", + value: { keep: () => true }, + }, + ]; + + cleanOptions.forEach((cleanOption) => { + it(`calls node fs unlink when using memfs and clean is ${cleanOption.title}`, (done) => { + const unlink = jest.fn((_, callback) => callback()); + context.compiler.outputFileSystem = { unlink }; + context.compiler.options = { + output: { + clean: cleanOption.value, + }, + }; + context.options = { + writeToDisk: true, + }; + setupWriteToDisk(context); + + context.compiler.outputFileSystem.unlink("/target/path/file", () => { + // the memfs unlink should always be called + expect(unlink.mock.calls.length).toEqual(1); + + // the fs unlink should be called when the clean value is truthy + const expectedCallCount = cleanOption.value ? 1 : 0; + expect(unlinkFileSpy.mock.calls.length).toEqual(expectedCallCount); + + done(); + }); + }); + }); });