Compare commits

..

3 Commits

Author SHA1 Message Date
Xiao 34737a8a26
Merge 08625a84d7 into 9f98d803c0 2025-10-04 23:16:32 +08:00
xiaoxiaojx 08625a84d7 feat: add DotenvPlugin 2025-10-04 23:16:08 +08:00
Alexander Akait 9f98d803c0
fix: javascript parser options types (#19980)
Github Actions / lint (push) Has been cancelled Details
Github Actions / validate-legacy-node (push) Has been cancelled Details
Github Actions / benchmark (1/4) (push) Has been cancelled Details
Github Actions / benchmark (2/4) (push) Has been cancelled Details
Github Actions / benchmark (3/4) (push) Has been cancelled Details
Github Actions / benchmark (4/4) (push) Has been cancelled Details
Github Actions / basic (push) Has been cancelled Details
Github Actions / unit (push) Has been cancelled Details
Github Actions / integration (10.x, macos-latest, a) (push) Has been cancelled Details
Github Actions / integration (10.x, macos-latest, b) (push) Has been cancelled Details
Github Actions / integration (10.x, ubuntu-latest, a) (push) Has been cancelled Details
Github Actions / integration (10.x, ubuntu-latest, b) (push) Has been cancelled Details
Github Actions / integration (10.x, windows-latest, a) (push) Has been cancelled Details
Github Actions / integration (10.x, windows-latest, b) (push) Has been cancelled Details
Github Actions / integration (12.x, ubuntu-latest, a) (push) Has been cancelled Details
Github Actions / integration (14.x, ubuntu-latest, a) (push) Has been cancelled Details
Github Actions / integration (16.x, ubuntu-latest, a) (push) Has been cancelled Details
Github Actions / integration (18.x, ubuntu-latest, a) (push) Has been cancelled Details
Github Actions / integration (20.x, macos-latest, a) (push) Has been cancelled Details
Github Actions / integration (20.x, macos-latest, b) (push) Has been cancelled Details
Github Actions / integration (20.x, ubuntu-latest, a) (push) Has been cancelled Details
Github Actions / integration (20.x, ubuntu-latest, b) (push) Has been cancelled Details
Github Actions / integration (20.x, windows-latest, a) (push) Has been cancelled Details
Github Actions / integration (20.x, windows-latest, b) (push) Has been cancelled Details
Github Actions / integration (22.x, macos-latest, a) (push) Has been cancelled Details
Github Actions / integration (22.x, macos-latest, b) (push) Has been cancelled Details
Github Actions / integration (22.x, ubuntu-latest, a) (push) Has been cancelled Details
Github Actions / integration (22.x, ubuntu-latest, b) (push) Has been cancelled Details
Github Actions / integration (22.x, windows-latest, a) (push) Has been cancelled Details
Github Actions / integration (22.x, windows-latest, b) (push) Has been cancelled Details
Github Actions / integration (24.x, macos-latest, a) (push) Has been cancelled Details
Github Actions / integration (24.x, macos-latest, b) (push) Has been cancelled Details
Github Actions / integration (24.x, ubuntu-latest, a) (push) Has been cancelled Details
Github Actions / integration (24.x, ubuntu-latest, b) (push) Has been cancelled Details
Github Actions / integration (24.x, windows-latest, a) (push) Has been cancelled Details
Github Actions / integration (24.x, windows-latest, b) (push) Has been cancelled Details
Github Actions / integration (lts/*, ubuntu-latest, a, 1) (push) Has been cancelled Details
Github Actions / integration (lts/*, ubuntu-latest, b, 1) (push) Has been cancelled Details
Update examples / examples (push) Has been cancelled Details
2025-10-04 14:58:38 +03:00
12 changed files with 120 additions and 35 deletions

View File

@ -1128,6 +1128,10 @@ export interface DotenvPluginOptions {
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefix?: string[] | string;
/**
* Template patterns for .env file names. Use [mode] as placeholder for the webpack mode. Defaults to ['.env', '.env.local', '.env.[mode]', '.env.[mode].local'].
*/
template?: string[];
}
/**
* Multiple entry bundles are created. The key is the entry name. The value can be a string, an array or an entry description object.
@ -3370,7 +3374,6 @@ export interface JavascriptParserOptions {
* Set the inner regular expression for partial dynamic dependencies.
*/
wrappedContextRegExp?: RegExp;
[k: string]: any;
}
/**
* Generator options for json modules.

View File

@ -15,7 +15,8 @@ const { join } = require("./util/fs");
/** @type {DotenvPluginOptions} */
const DEFAULT_OPTIONS = {
prefix: "WEBPACK_",
dir: true
dir: true,
template: [".env", ".env.local", ".env.[mode]", ".env.[mode].local"]
};
// Regex for parsing .env files
@ -225,27 +226,6 @@ const resolveEnvPrefix = (rawPrefix) => {
return prefixes;
};
/**
* Get list of env files to load based on mode
* Similar to Vite's getEnvFilesForMode
* @param {InputFileSystem} inputFileSystem the input file system
* @param {string} dir the directory containing .env files
* @param {string | undefined} mode the mode (e.g., 'production', 'development')
* @returns {string[]} array of file paths to load
*/
const getEnvFilesForMode = (inputFileSystem, dir, mode) => {
if (dir) {
return [
/** default file */ ".env",
/** local file */ ".env.local",
/** mode file */ `.env.${mode}`,
/** mode local file */ `.env.${mode}.local`
].map((file) => join(inputFileSystem, dir, file));
}
return [];
};
/**
* Format environment variables as DefinePlugin definitions
* @param {Record<string, string>} env environment variables
@ -281,7 +261,7 @@ class DotenvPlugin {
/** @type {string[] | undefined} */
let fileDependenciesCache;
compiler.hooks.beforeRun.tapAsync(PLUGIN_NAME, (_params, callback) => {
compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, (_params, callback) => {
const inputFileSystem = /** @type {InputFileSystem} */ (
compiler.inputFileSystem
);
@ -314,6 +294,27 @@ class DotenvPlugin {
definePlugin.apply(compiler);
}
/**
* Get list of env files to load based on mode and template
* Similar to Vite's getEnvFilesForMode
* @param {InputFileSystem} inputFileSystem the input file system
* @param {string} dir the directory containing .env files
* @param {string | undefined} mode the mode (e.g., 'production', 'development')
* @returns {string[]} array of file paths to load
*/
getEnvFilesForMode(inputFileSystem, dir, mode) {
if (!dir) {
return [];
}
const { template } = /** @type {DotenvPluginOptions} */ (this.config);
const templates = template || [];
return templates
.map((pattern) => pattern.replace(/\[mode\]/g, mode || "development"))
.map((file) => join(inputFileSystem, dir, file));
}
/**
* Load environment variables from .env files
* Similar to Vite's loadEnv implementation
@ -333,7 +334,6 @@ class DotenvPlugin {
} catch (err) {
return callback(/** @type {Error} */ (err));
}
const getDir = () => {
if (typeof rawDir === "string") {
return join(fs, context, rawDir);
@ -341,16 +341,13 @@ class DotenvPlugin {
if (rawDir === true) {
return context;
}
if (rawDir === false) {
return "";
}
return "";
};
/** @type {string} */
const dir = getDir();
// Get env files to load
const envFiles = getEnvFilesForMode(fs, dir, mode);
const envFiles = this.getEnvFilesForMode(fs, dir, mode);
/** @type {string[]} */
const fileDependencies = [];

File diff suppressed because one or more lines are too long

View File

@ -677,6 +677,15 @@
"minLength": 1
}
]
},
"template": {
"description": "Template patterns for .env file names. Use [mode] as placeholder for the webpack mode. Defaults to ['.env', '.env.local', '.env.[mode]', '.env.[mode].local'].",
"type": "array",
"items": {
"description": "A template pattern for .env file names.",
"type": "string",
"minLength": 1
}
}
}
},
@ -1837,7 +1846,7 @@
"JavascriptParserOptions": {
"description": "Parser options for javascript modules.",
"type": "object",
"additionalProperties": true,
"additionalProperties": false,
"properties": {
"amd": {
"$ref": "#/definitions/Amd"

View File

@ -523,6 +523,32 @@ Object {
"multiple": false,
"simpleType": "boolean",
},
"dotenv-template": Object {
"configs": Array [
Object {
"description": "A template pattern for .env file names.",
"multiple": true,
"path": "dotenv.template[]",
"type": "string",
},
],
"description": "A template pattern for .env file names.",
"multiple": true,
"simpleType": "string",
},
"dotenv-template-reset": Object {
"configs": Array [
Object {
"description": "Clear all items provided in 'dotenv.template' configuration. Template patterns for .env file names. Use [mode] as placeholder for the webpack mode. Defaults to ['.env', '.env.local', '.env.[mode]', '.env.[mode].local'].",
"multiple": false,
"path": "dotenv.template",
"type": "reset",
},
],
"description": "Clear all items provided in 'dotenv.template' configuration. Template patterns for .env file names. Use [mode] as placeholder for the webpack mode. Defaults to ['.env', '.env.local', '.env.[mode]', '.env.[mode].local'].",
"multiple": false,
"simpleType": "boolean",
},
"entry": Object {
"configs": Array [
Object {

View File

@ -671,4 +671,4 @@ Before we started using OpenCollective, donations were made anonymously. Now tha
[dependency-review-url]: https://github.com/webpack/webpack/actions/workflows/dependency-review.yml
[dependency-review]: https://github.com/webpack/webpack/actions/workflows/dependency-review.yml/badge.svg
[cover]: https://codecov.io/gh/webpack/webpack/graph/badge.svg?token=mDP3mQJNnn
[cover-url]: https://codecov.io/gh/webpack/webpack
[cover-url]: https://codecov.io/gh/webpack/webpack

View File

@ -11,3 +11,6 @@ WEBPACK_PORT=${PORT:-3000}
# Mode-specific base value
WEBPACK_ENV=development
# Custom template test - base value
WEBPACK_OVERRIDE_VAR=base-value

View File

@ -0,0 +1,3 @@
# Custom template test - myLocal file
WEBPACK_CUSTOM_VAR=from-myLocal
WEBPACK_OVERRIDE_VAR=myLocal-value

View File

@ -0,0 +1,2 @@
# Custom template test - production.myLocal file
WEBPACK_PROD_CUSTOM=from-production-myLocal

View File

@ -0,0 +1,16 @@
"use strict";
it("should load env files based on custom template", () => {
// Should load from .env.myLocal (custom template)
expect(process.env.WEBPACK_CUSTOM_VAR).toBe("from-myLocal");
// Should load from .env.production.myLocal (custom mode-specific template)
expect(process.env.WEBPACK_PROD_CUSTOM).toBe("from-production-myLocal");
// Should also load from standard .env
expect(process.env.WEBPACK_API_URL).toBe("https://prod-api.example.com");
// Custom template files should override .env values
expect(process.env.WEBPACK_OVERRIDE_VAR).toBe("myLocal-value");
});

View File

@ -50,5 +50,14 @@ module.exports = [
dotenv: {
dir: false
}
},
// Test 7: Custom template - load files based on custom template patterns
{
name: "custom-template",
mode: "production",
entry: "./custom-template.js",
dotenv: {
template: [".env", ".env.myLocal", ".env.[mode]", ".env.[mode].myLocal"]
}
}
];

21
types.d.ts vendored
View File

@ -4435,9 +4435,23 @@ declare class DotenvPlugin {
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefix?: string | string[];
/**
* Template patterns for .env file names. Use [mode] as placeholder for the webpack mode. Defaults to ['.env', '.env.local', '.env.[mode]', '.env.[mode].local'].
*/
template?: string[];
};
apply(compiler: Compiler): void;
/**
* Get list of env files to load based on mode and template
* Similar to Vite's getEnvFilesForMode
*/
getEnvFilesForMode(
inputFileSystem: InputFileSystem,
dir: string,
mode?: string
): string[];
/**
* Load environment variables from .env files
* Similar to Vite's loadEnv implementation
@ -4472,6 +4486,11 @@ declare interface DotenvPluginOptions {
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefix?: string | string[];
/**
* Template patterns for .env file names. Use [mode] as placeholder for the webpack mode. Defaults to ['.env', '.env.local', '.env.[mode]', '.env.[mode].local'].
*/
template?: string[];
}
declare class DynamicEntryPlugin {
constructor(context: string, entry: () => Promise<EntryStaticNormalized>);
@ -8249,8 +8268,6 @@ declare class JavascriptParser extends ParserClass {
* Parser options for javascript modules.
*/
declare interface JavascriptParserOptions {
[index: string]: any;
/**
* Set the value of `require.amd` and `define.amd`. Or disable AMD support.
*/