From fc406b758dc5faa459139d5cb9b3ec2bc9545cd1 Mon Sep 17 00:00:00 2001 From: xiaoxiaojx <784487301@qq.com> Date: Tue, 7 Oct 2025 01:46:08 +0800 Subject: [PATCH] add missingDependencies --- lib/DotenvPlugin.js | 27 ++++++++++++------- .../plugins/dotenv-plugin/2/index.js | 8 ++++++ .../plugins/dotenv-plugin/3/.env.myLocal | 1 + .../plugins/dotenv-plugin/webpack.config.js | 8 +++--- types.d.ts | 3 ++- 5 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 test/watchCases/plugins/dotenv-plugin/3/.env.myLocal diff --git a/lib/DotenvPlugin.js b/lib/DotenvPlugin.js index d215cb1e0..80266db41 100644 --- a/lib/DotenvPlugin.js +++ b/lib/DotenvPlugin.js @@ -260,6 +260,8 @@ class DotenvPlugin { /** @type {string[] | undefined} */ let fileDependenciesCache; + /** @type {string[] | undefined} */ + let missingDependenciesCache; compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, (_params, callback) => { const inputFileSystem = /** @type {InputFileSystem} */ ( @@ -272,7 +274,7 @@ class DotenvPlugin { inputFileSystem, mode, context, - (err, env, fileDependencies) => { + (err, env, fileDependencies, missingDependencies) => { if (err) return callback(err); const definitions = envToDefinitions(env || {}); @@ -281,6 +283,8 @@ class DotenvPlugin { definePlugin.definitions = definitions; // update the file dependencies fileDependenciesCache = fileDependencies; + // update the missing dependencies + missingDependenciesCache = missingDependencies; callback(); } @@ -289,6 +293,7 @@ class DotenvPlugin { compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => { compilation.fileDependencies.addAll(fileDependenciesCache || []); + compilation.missingDependencies.addAll(missingDependenciesCache || []); }); definePlugin.apply(compiler); @@ -321,7 +326,7 @@ class DotenvPlugin { * @param {InputFileSystem} fs the input file system * @param {string | undefined} mode the mode * @param {string} context the compiler context - * @param {(err: Error | null, env?: Record, fileDependencies?: string[]) => void} callback callback function + * @param {(err: Error | null, env?: Record, fileDependencies?: string[], missingDependencies?: string[]) => void} callback callback function * @returns {void} */ loadEnv(fs, mode, context, callback) { @@ -353,26 +358,30 @@ class DotenvPlugin { const envFiles = this.getEnvFilesForMode(fs, dir, mode); /** @type {string[]} */ const fileDependencies = []; + /** @type {string[]} */ + const missingDependencies = []; // Read all files const readPromises = envFiles.map((filePath) => this.loadFile(fs, filePath).then( (content) => { fileDependencies.push(filePath); - return { content, filePath }; + return content; }, - () => - // File doesn't exist, skip it (this is normal) - ({ content: "", filePath }) + () => { + // File doesn't exist, add to missingDependencies (this is normal) + missingDependencies.push(filePath); + return ""; + } ) ); Promise.all(readPromises) - .then((results) => { + .then((contents) => { // Parse all files and merge (later files override earlier ones) // Similar to Vite's implementation const parsed = /** @type {Record} */ ({}); - for (const { content } of results) { + for (const content of contents) { if (!content) continue; const entries = parse(content); for (const key in entries) { @@ -403,7 +412,7 @@ class DotenvPlugin { } } - callback(null, env, fileDependencies); + callback(null, env, fileDependencies, missingDependencies); }) .catch((err) => { callback(err); diff --git a/test/watchCases/plugins/dotenv-plugin/2/index.js b/test/watchCases/plugins/dotenv-plugin/2/index.js index b73b55598..f160eb908 100644 --- a/test/watchCases/plugins/dotenv-plugin/2/index.js +++ b/test/watchCases/plugins/dotenv-plugin/2/index.js @@ -5,4 +5,12 @@ it("should override .env values with .env.development in step 2", function () { expect(process.env.WEBPACK_NEW_VAR).toBe("added-in-step-1"); // New variable from .env.development expect(process.env.WEBPACK_DEV_ONLY).toBe("development-value"); + // missingDependencies test + if (WATCH_STEP === "3") { + // In step 3, .env.myLocal from missingDependencies was created, so it has a value + expect(process.env.WEBPACK_MY_LOCAL).toBe("3"); + } else { + // In step 2, .env.myLocal doesn't exist yet + expect(process.env.WEBPACK_MY_LOCAL).toBeUndefined(); + } }); diff --git a/test/watchCases/plugins/dotenv-plugin/3/.env.myLocal b/test/watchCases/plugins/dotenv-plugin/3/.env.myLocal new file mode 100644 index 000000000..430b11418 --- /dev/null +++ b/test/watchCases/plugins/dotenv-plugin/3/.env.myLocal @@ -0,0 +1 @@ +WEBPACK_MY_LOCAL=3 diff --git a/test/watchCases/plugins/dotenv-plugin/webpack.config.js b/test/watchCases/plugins/dotenv-plugin/webpack.config.js index 66ef5a5fe..586bc2407 100644 --- a/test/watchCases/plugins/dotenv-plugin/webpack.config.js +++ b/test/watchCases/plugins/dotenv-plugin/webpack.config.js @@ -1,6 +1,5 @@ "use strict"; -const path = require("path"); const DotenvPlugin = require("../../../../").DotenvPlugin; /** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration} */ @@ -8,14 +7,14 @@ const DotenvPlugin = require("../../../../").DotenvPlugin; module.exports = (env, { srcPath, testPath }) => { const dotenvPlugin = new DotenvPlugin({ prefix: "WEBPACK_", - dir: "" + dir: "", + template: [".env", ".env.myLocal", ".env.[mode]", ".env.[mode].myLocal"] }); return { mode: "development", dotenv: false, plugins: [ (compiler) => { - let i = 0; // Update dotenvPlugin.config.dir before each compile // Use beforeCompile with stage -1 to run before DotenvPlugin compiler.hooks.beforeCompile.tap( @@ -24,8 +23,7 @@ module.exports = (env, { srcPath, testPath }) => { stage: -1 }, () => { - dotenvPlugin.config.dir = path.join(__dirname, String(i)); - i++; + dotenvPlugin.config.dir = srcPath; } ); }, diff --git a/types.d.ts b/types.d.ts index 2e87cc852..1e66c1985 100644 --- a/types.d.ts +++ b/types.d.ts @@ -4463,7 +4463,8 @@ declare class DotenvPlugin { callback: ( err: null | Error, env?: Record, - fileDependencies?: string[] + fileDependencies?: string[], + missingDependencies?: string[] ) => void ): void;