This commit is contained in:
Xiao 2025-10-03 12:18:59 +00:00 committed by GitHub
commit ec78a303e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 857 additions and 368 deletions

View File

@ -315,7 +315,8 @@
"spacek",
"thelarkinn",
"behaviour",
"WHATWG"
"WHATWG",
"systemvars"
],
"ignoreRegExpList": [
"/Author.+/",

View File

@ -47,6 +47,21 @@ export type DevServer =
* A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map).
*/
export type DevTool = (false | "eval") | string;
/**
* Enable and configure the Dotenv plugin to load environment variables from .env files.
*/
export type Dotenv =
| boolean
| {
/**
* The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.
*/
envDir?: string;
/**
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefixes?: string[] | string;
};
/**
* The entry point(s) of the compilation.
*/
@ -884,6 +899,10 @@ export interface WebpackOptions {
* A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map).
*/
devtool?: DevTool;
/**
* Enable and configure the Dotenv plugin to load environment variables from .env files.
*/
dotenv?: Dotenv;
/**
* The entry point(s) of the compilation.
*/
@ -3061,6 +3080,19 @@ export interface CssParserOptions {
*/
url?: CssParserUrl;
}
/**
* Options for Dotenv plugin.
*/
export interface DotenvPluginOptions {
/**
* The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.
*/
envDir?: string;
/**
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefixes?: string[] | string;
}
/**
* No generator options are supported for this module type.
*/
@ -3798,6 +3830,10 @@ export interface WebpackOptionsNormalized {
* A developer tool to enhance debugging (false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map).
*/
devtool?: DevTool;
/**
* Enable and configure the Dotenv plugin to load environment variables from .env files.
*/
dotenv?: Dotenv;
/**
* The entry point(s) of the compilation.
*/

36
declarations/plugins/DotenvPlugin.d.ts vendored Normal file
View File

@ -0,0 +1,36 @@
/*
* This file was automatically generated.
* DO NOT MODIFY BY HAND.
* Run `yarn fix:special` to update
*/
export interface DotenvPluginOptions {
/**
* Whether to allow empty strings in safe mode. If false, will throw an error if any env variables are empty (but only if safe mode is enabled).
*/
allowEmptyValues?: boolean;
/**
* Adds support for dotenv-defaults. If set to true, uses ./.env.defaults. If a string, uses that location for a defaults file.
*/
defaults?: boolean | string;
/**
* Allows your variables to be "expanded" for reusability within your .env file.
*/
expand?: boolean;
/**
* The path to your environment variables. This same path applies to the .env.example and .env.defaults files.
*/
path?: string;
/**
* The prefix to use before the name of your env variables.
*/
prefix?: string;
/**
* If true, load '.env.example' to verify the '.env' variables are all set. Can also be a string to a different file.
*/
safe?: boolean | string;
/**
* Set to true if you would rather load all system variables as well (useful for CI purposes).
*/
systemvars?: boolean;
}

423
lib/DotenvPlugin.js Normal file
View File

@ -0,0 +1,423 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Natsu @xiaoxiaojx
*/
"use strict";
const createSchemaValidation = require("./util/create-schema-validation");
const { join } = require("./util/fs");
/** @typedef {import("../declarations/WebpackOptions").DotenvPluginOptions} DotenvPluginOptions */
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
const DEFAULT_OPTIONS = {
prefixes: "WEBPACK_",
envDir: true
};
// Regex for parsing .env files
// ported from https://github.com/motdotla/dotenv/blob/master/lib/main.js#L32
const LINE =
/(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;
const PLUGIN_NAME = "DotenvPlugin";
const validate = createSchemaValidation(
undefined,
() => {
const { definitions } = require("../schemas/WebpackOptions.json");
return {
definitions,
oneOf: [{ $ref: "#/definitions/DotenvPluginOptions" }]
};
},
{
name: "Dotenv Plugin",
baseDataPath: "options"
}
);
/**
* Parse .env file content
* ported from https://github.com/motdotla/dotenv/blob/master/lib/main.js#L49
* @param {string|Buffer} src the source content to parse
* @returns {Record<string, string>} parsed environment variables object
*/
function parse(src) {
const obj = /** @type {Record<string, string>} */ ({});
// Convert buffer to string
let lines = src.toString();
// Convert line breaks to same format
lines = lines.replace(/\r\n?/gm, "\n");
let match;
while ((match = LINE.exec(lines)) !== null) {
const key = match[1];
// Default undefined or null to empty string
let value = match[2] || "";
// Remove whitespace
value = value.trim();
// Check if double quoted
const maybeQuote = value[0];
// Remove surrounding quotes
value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
// Expand newlines if double quoted
if (maybeQuote === '"') {
value = value.replace(/\\n/g, "\n");
value = value.replace(/\\r/g, "\r");
}
// Add to object
obj[key] = value;
}
return obj;
}
/**
* Resolve escape sequences
* ported from https://github.com/motdotla/dotenv-expand
* @param {string} value value to resolve
* @returns {string} resolved value
*/
function _resolveEscapeSequences(value) {
return value.replace(/\\\$/g, "$");
}
/**
* Expand environment variable value
* ported from https://github.com/motdotla/dotenv-expand
* @param {string} value value to expand
* @param {Record<string, string | undefined>} processEnv process.env object
* @param {Record<string, string>} runningParsed running parsed object
* @returns {string} expanded value
*/
function expandValue(value, processEnv, runningParsed) {
const env = { ...runningParsed, ...processEnv }; // process.env wins
const regex = /(?<!\\)\$\{([^{}]+)\}|(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)/g;
let result = value;
let match;
const seen = new Set(); // self-referential checker
while ((match = regex.exec(result)) !== null) {
seen.add(result);
const [template, bracedExpression, unbracedExpression] = match;
const expression = bracedExpression || unbracedExpression;
// match the operators `:+`, `+`, `:-`, and `-`
const opRegex = /(:\+|\+|:-|-)/;
// find first match
const opMatch = expression.match(opRegex);
const splitter = opMatch ? opMatch[0] : null;
const r = expression.split(/** @type {string} */ (splitter));
// const r = splitter ? expression.split(splitter) : [expression];
let defaultValue;
let value;
const key = r.shift();
if ([":+", "+"].includes(splitter || "")) {
defaultValue = env[key || ""] ? r.join(splitter || "") : "";
value = null;
} else {
defaultValue = r.join(splitter || "");
value = env[key || ""];
}
if (value) {
// self-referential check
result = seen.has(value)
? result.replace(template, defaultValue)
: result.replace(template, value);
} else {
result = result.replace(template, defaultValue);
}
// if the result equaled what was in process.env and runningParsed then stop expanding
if (result === runningParsed[key || ""]) {
break;
}
regex.lastIndex = 0; // reset regex search position to re-evaluate after each replacement
}
return result;
}
/**
* Expand environment variables in parsed object
* ported from https://github.com/motdotla/dotenv-expand
* @param {{ parsed: Record<string, string>, processEnv?: Record<string, string | undefined> }} options expand options
* @returns {{ parsed: Record<string, string> }} expanded options
*/
function expand(options) {
// for use with progressive expansion
const runningParsed = /** @type {Record<string, string>} */ ({});
let processEnv = process.env;
if (
options &&
options.processEnv !== null &&
options.processEnv !== undefined
) {
processEnv = options.processEnv;
}
// dotenv.config() ran before this so the assumption is process.env has already been set
for (const key in options.parsed) {
let value = options.parsed[key];
// short-circuit scenario: process.env was already set prior to the file value
value =
processEnv[key] && processEnv[key] !== value
? /** @type {string} */ (processEnv[key])
: expandValue(value, processEnv, runningParsed);
options.parsed[key] = _resolveEscapeSequences(value);
// for use with progressive expansion
runningParsed[key] = _resolveEscapeSequences(value);
}
for (const processKey in options.parsed) {
if (processEnv) {
processEnv[processKey] = options.parsed[processKey];
}
}
return options;
}
/**
* Resolve and validate env prefixes
* Similar to Vite's resolveEnvPrefix
* @param {string | string[] | undefined} rawPrefixes raw prefixes option
* @returns {string[]} normalized prefixes array
*/
const resolveEnvPrefix = (rawPrefixes) => {
const prefixes = Array.isArray(rawPrefixes)
? rawPrefixes
: [rawPrefixes || "WEBPACK_"];
// Check for empty prefix (security issue like Vite does)
if (prefixes.includes("")) {
throw new Error(
"prefixes option contains value '', which could lead to unexpected exposure of sensitive information."
);
}
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} envDir 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, envDir, mode) => {
if (envDir) {
return [
/** default file */ ".env",
/** local file */ ".env.local",
/** mode file */ `.env.${mode}`,
/** mode local file */ `.env.${mode}.local`
].map((file) => join(inputFileSystem, envDir, file));
}
return [];
};
/**
* Format environment variables as DefinePlugin definitions
* @param {Record<string, string>} env environment variables
* @returns {Record<string, string>} formatted definitions
*/
const formatDefinitions = (env) => {
const definitions = /** @type {Record<string, string>} */ ({});
for (const [key, value] of Object.entries(env)) {
// Always use process.env. prefix for DefinePlugin
definitions[`process.env.${key}`] = JSON.stringify(value);
}
return definitions;
};
class DotenvPlugin {
/**
* @param {DotenvPluginOptions=} options options object
*/
constructor(options = {}) {
validate(options);
this.config = { ...DEFAULT_OPTIONS, ...options };
}
/**
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
/** @type {string[] | undefined} */
let fileDependenciesCache;
compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, (_params, callback) => {
const inputFileSystem = /** @type {InputFileSystem} */ (
compiler.inputFileSystem
);
const context = compiler.context;
// Use webpack mode or fallback to NODE_ENV
const mode = /** @type {string | undefined} */ (
compiler.options.mode || process.env.NODE_ENV
);
this.loadEnv(
inputFileSystem,
mode,
context,
(err, env, fileDependencies) => {
if (err) return callback(err);
const definitions = formatDefinitions(env || {});
const DefinePlugin = compiler.webpack.DefinePlugin;
new DefinePlugin(definitions).apply(compiler);
fileDependenciesCache = fileDependencies;
callback();
}
);
});
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
compilation.fileDependencies.addAll(fileDependenciesCache || []);
});
}
/**
* Load environment variables from .env files
* Similar to Vite's loadEnv implementation
* @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<string, string>, fileDependencies?: string[]) => void} callback callback function
* @returns {void}
*/
loadEnv(fs, mode, context, callback) {
const { envDir: rawEnvDir, prefixes: rawPrefixes } =
/** @type {DotenvPluginOptions} */ (this.config);
let prefixes;
try {
prefixes = resolveEnvPrefix(rawPrefixes);
} catch (err) {
return callback(/** @type {Error} */ (err));
}
const getEnvDir = () => {
if (typeof rawEnvDir === "string") {
return join(fs, context, rawEnvDir);
}
if (rawEnvDir === true) {
return context;
}
return "";
};
const envDir = getEnvDir();
// Get env files to load
const envFiles = getEnvFilesForMode(fs, envDir, mode);
/** @type {string[]} */
const fileDependencies = [];
// Read all files
const readPromises = envFiles.map((filePath) =>
this.loadFile(fs, filePath).then(
(content) => {
fileDependencies.push(filePath);
return { content, filePath };
},
() =>
// File doesn't exist, skip it (this is normal)
({ content: "", filePath })
)
);
Promise.all(readPromises)
.then((results) => {
// Parse all files and merge (later files override earlier ones)
// Similar to Vite's implementation
const parsed = /** @type {Record<string, string>} */ ({});
for (const { content } of results) {
if (!content) continue;
const entries = parse(content);
for (const key in entries) {
parsed[key] = entries[key];
}
}
// Always expand environment variables (like Vite does)
// Make a copy of process.env so that dotenv-expand doesn't modify global process.env
const processEnv = { ...process.env };
expand({ parsed, processEnv });
// Filter by prefixes and prioritize process.env (like Vite)
const env = /** @type {Record<string, string>} */ ({});
// First, add filtered vars from parsed .env files
for (const [key, value] of Object.entries(parsed)) {
if (prefixes.some((prefix) => key.startsWith(prefix))) {
env[key] = value;
}
}
// Then, prioritize actual env variables starting with prefixes
// These are typically provided inline and should be prioritized (like Vite)
for (const key in process.env) {
if (prefixes.some((prefix) => key.startsWith(prefix))) {
env[key] = /** @type {string} */ (process.env[key]);
}
}
callback(null, env, fileDependencies);
})
.catch((err) => {
callback(err);
});
}
/**
* Load a file with proper path resolution
* @param {InputFileSystem} fs the input file system
* @param {string} file the file to load
* @returns {Promise<string>} the content of the file
*/
loadFile(fs, file) {
return new Promise((resolve, reject) => {
fs.readFile(file, "utf8", (err, content) => {
if (err) reject(err);
else resolve(content || "");
});
});
}
}
module.exports = DotenvPlugin;

View File

@ -294,6 +294,14 @@ class WebpackOptionsApply extends OptionsApply {
).apply(compiler);
}
if (options.dotenv) {
const DotenvPlugin = require("./DotenvPlugin");
new DotenvPlugin(
typeof options.dotenv === "boolean" ? {} : options.dotenv
).apply(compiler);
}
if (options.devtool) {
if (options.devtool.includes("source-map")) {
const hidden = options.devtool.includes("hidden");

View File

@ -202,6 +202,7 @@ const {
* & { performance: NonNullable<WebpackOptionsNormalized["performance"]> }
* & { recordsInputPath: NonNullable<WebpackOptionsNormalized["recordsInputPath"]> }
* & { recordsOutputPath: NonNullable<WebpackOptionsNormalized["recordsOutputPath"]>
* & { dotenv: NonNullable<WebpackOptionsNormalized["dotenv"]> }
* }} WebpackOptionsNormalizedWithDefaults
*/

View File

@ -178,6 +178,9 @@ const getNormalizedWebpackOptions = (config) => ({
return { ...devServer };
}),
devtool: config.devtool,
dotenv: optionalNestedConfig(config.dotenv, (dotenv) =>
dotenv === true ? {} : dotenv
),
entry:
config.entry === undefined
? { main: {} }

View File

@ -232,6 +232,9 @@ module.exports = mergeExports(fn, {
get DynamicEntryPlugin() {
return require("./DynamicEntryPlugin");
},
get DotenvPlugin() {
return require("./DotenvPlugin");
},
get EntryOptionPlugin() {
return require("./EntryOptionPlugin");
},

File diff suppressed because one or more lines are too long

View File

@ -629,6 +629,50 @@
"description": "Module namespace to use when interpolating filename template string for the sources array in a generated SourceMap. Defaults to `output.library` if not set. It's useful for avoiding runtime collisions in sourcemaps from multiple webpack projects built as libraries.",
"type": "string"
},
"Dotenv": {
"description": "Enable and configure the Dotenv plugin to load environment variables from .env files.",
"cli": {
"exclude": false
},
"anyOf": [
{
"description": "Enable Dotenv plugin with default options.",
"type": "boolean"
},
{
"$ref": "#/definitions/DotenvPluginOptions",
"description": "Options for Dotenv plugin."
}
]
},
"DotenvPluginOptions": {
"description": "Options for Dotenv plugin.",
"type": "object",
"additionalProperties": false,
"properties": {
"envDir": {
"description": "The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.",
"type": "string",
"minLength": 1
},
"prefixes": {
"description": "Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.",
"anyOf": [
{
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
{
"type": "string",
"minLength": 1
}
]
}
}
},
"EmptyGeneratorOptions": {
"description": "No generator options are supported for this module type.",
"type": "object",
@ -5800,6 +5844,9 @@
"devtool": {
"$ref": "#/definitions/DevTool"
},
"dotenv": {
"$ref": "#/definitions/Dotenv"
},
"entry": {
"$ref": "#/definitions/EntryNormalized"
},
@ -5950,6 +5997,9 @@
"devtool": {
"$ref": "#/definitions/DevTool"
},
"dotenv": {
"$ref": "#/definitions/Dotenv"
},
"entry": {
"$ref": "#/definitions/Entry"
},

View File

@ -465,6 +465,58 @@ Object {
"multiple": false,
"simpleType": "string",
},
"dotenv": Object {
"configs": Array [
Object {
"description": "Enable Dotenv plugin with default options.",
"multiple": false,
"path": "dotenv",
"type": "boolean",
},
],
"description": "Enable Dotenv plugin with default options.",
"multiple": false,
"simpleType": "boolean",
},
"dotenv-env-dir": Object {
"configs": Array [
Object {
"description": "The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.",
"multiple": false,
"path": "dotenv.envDir",
"type": "string",
},
],
"description": "The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.",
"multiple": false,
"simpleType": "string",
},
"dotenv-prefixes": Object {
"configs": Array [
Object {
"description": "Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.",
"multiple": true,
"path": "dotenv.prefixes[]",
"type": "string",
},
],
"description": "Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.",
"multiple": true,
"simpleType": "string",
},
"dotenv-prefixes-reset": Object {
"configs": Array [
Object {
"description": "Clear all items provided in 'dotenv.prefixes' configuration. Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.",
"multiple": false,
"path": "dotenv.prefixes",
"type": "reset",
},
],
"description": "Clear all items provided in 'dotenv.prefixes' configuration. Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.",
"multiple": false,
"simpleType": "boolean",
},
"entry": Object {
"configs": Array [
Object {

View File

@ -0,0 +1,13 @@
# Basic test
WEBPACK_API_URL=https://api.example.com
WEBPACK_MODE=test
SECRET_KEY=should-not-be-exposed
PRIVATE_VAR=also-hidden
# Expand test
WEBPACK_BASE=example.com
WEBPACK_FULL_URL=${WEBPACK_API_URL}/v1
WEBPACK_PORT=${PORT:-3000}
# Mode-specific base value
WEBPACK_ENV=development

View File

@ -0,0 +1,3 @@
# Production overrides
WEBPACK_API_URL=https://prod-api.example.com
WEBPACK_ENV=production

View File

@ -0,0 +1,10 @@
"use strict";
it("should expose only WEBPACK_ prefixed env vars", () => {
expect(process.env.WEBPACK_API_URL).toBe("https://api.example.com");
expect(process.env.WEBPACK_MODE).toBe("test");
// Non-prefixed vars should not be exposed
expect(typeof process.env.SECRET_KEY).toBe("undefined");
expect(typeof process.env.PRIVATE_VAR).toBe("undefined");
});

View File

@ -0,0 +1,7 @@
"use strict";
it("should load from custom envDir", () => {
expect(process.env.WEBPACK_FROM_ENVS).toBe("loaded-from-envs-dir");
expect(process.env.WEBPACK_API_URL).toBe("https://custom.example.com");
});

View File

@ -0,0 +1,13 @@
"use strict";
it("should expose only APP_ and CONFIG_ prefixed vars", () => {
expect(process.env.APP_NAME).toBe("MyApp");
expect(process.env.CONFIG_TIMEOUT).toBe("5000");
// WEBPACK_ prefixed should not be exposed
expect(typeof process.env.WEBPACK_API_URL).toBe("undefined");
// Non-prefixed should not be exposed
expect(typeof process.env.SECRET_KEY).toBe("undefined");
});

View File

@ -0,0 +1,2 @@
WEBPACK_FROM_ENVS=loaded-from-envs-dir
WEBPACK_API_URL=https://custom.example.com

View File

@ -0,0 +1,10 @@
"use strict";
it("should expand variables by default", () => {
expect(process.env.WEBPACK_BASE).toBe("example.com");
expect(process.env.WEBPACK_API_URL).toBe("https://api.example.com");
expect(process.env.WEBPACK_FULL_URL).toBe("https://api.example.com/v1");
// Test default value operator
expect(process.env.WEBPACK_PORT).toBe("3000");
});

View File

@ -0,0 +1,11 @@
"use strict";
it("should load .env.production and override .env values", () => {
// Value from .env.production should override .env
expect(process.env.WEBPACK_API_URL).toBe("https://prod-api.example.com");
expect(process.env.WEBPACK_ENV).toBe("production");
// Value only in .env
expect(process.env.WEBPACK_MODE).toBe("test");
});

View File

@ -0,0 +1,4 @@
APP_NAME=MyApp
CONFIG_TIMEOUT=5000
WEBPACK_API_URL=should-not-be-exposed
SECRET_KEY=also-hidden

View File

@ -0,0 +1,45 @@
"use strict";
/** @type {import("../../../../").Configuration[]} */
module.exports = [
// Test 1: Basic - default behavior with WEBPACK_ prefix
{
name: "basic",
mode: "development",
entry: "./basic.js",
dotenv: true
},
// Test 2: Expand - variables are always expanded
{
name: "expand",
mode: "development",
entry: "./expand.js",
dotenv: true
},
// Test 3: Custom envDir - load from different directory
{
name: "custom-envdir",
mode: "development",
entry: "./custom-envdir.js",
dotenv: {
envDir: "./envs"
}
},
// Test 4: Custom prefixes - multiple prefixes
{
name: "custom-prefixes",
mode: "development",
entry: "./custom-prefixes.js",
dotenv: {
envDir: "./prefixes-env",
prefixes: ["APP_", "CONFIG_"]
}
},
// Test 5: Mode-specific - .env.[mode] overrides
{
name: "mode-specific",
mode: "production",
entry: "./mode-specific.js",
dotenv: true
}
];

490
types.d.ts vendored
View File

@ -24,7 +24,7 @@ import {
ClassBody,
ClassDeclaration,
ClassExpression,
Comment as CommentImport,
Comment,
ConditionalExpression,
ContinueStatement,
DebuggerStatement,
@ -99,11 +99,9 @@ import {
} from "inspector";
import { JSONSchema4, JSONSchema6, JSONSchema7 } from "json-schema";
import { ListenOptions } from "net";
import {
ValidationErrorConfiguration,
validate as validateFunction
} from "schema-utils";
import { validate as validateFunction } from "schema-utils";
import { default as ValidationError } from "schema-utils/declarations/ValidationError";
import { ValidationErrorConfiguration } from "schema-utils/declarations/validate";
import {
AsArray,
AsyncParallelHook,
@ -116,8 +114,7 @@ import {
SyncBailHook,
SyncHook,
SyncWaterfallHook,
TapOptions,
TypedHookMap
TapOptions
} from "tapable";
import { SecureContextOptions, TlsOptions } from "tls";
import { URL } from "url";
@ -300,14 +297,6 @@ declare interface Asset {
*/
info: AssetInfo;
}
declare abstract class AssetBytesGenerator extends Generator {
generateError(
error: Error,
module: NormalModule,
generateContext: GenerateContext
): null | Source;
}
declare abstract class AssetBytesParser extends ParserClass {}
declare interface AssetDependencyMeta {
sourceType: "css-url";
}
@ -322,25 +311,6 @@ type AssetFilterItemTypes =
| string
| RegExp
| ((name: string, asset: StatsAsset) => boolean);
declare abstract class AssetGenerator extends Generator {
dataUrlOptions?:
| AssetGeneratorDataUrlOptions
| ((
source: string | Buffer,
context: { filename: string; module: Module }
) => string);
filename?: string | ((pathData: PathData, assetInfo?: AssetInfo) => string);
publicPath?: string | ((pathData: PathData, assetInfo?: AssetInfo) => string);
outputPath?: string | ((pathData: PathData, assetInfo?: AssetInfo) => string);
emit?: boolean;
getMimeType(module: NormalModule): string;
generateDataUri(module: NormalModule): string;
generateError(
error: Error,
module: NormalModule,
generateContext: GenerateContext
): null | Source;
}
/**
* Options object for data url generation.
@ -379,15 +349,6 @@ declare interface AssetInlineGeneratorOptions {
context: { filename: string; module: Module }
) => string);
}
declare abstract class AssetParser extends ParserClass {
dataUrlCondition?:
| boolean
| AssetParserDataUrlOptions
| ((
source: string | Buffer,
context: { filename: string; module: Module }
) => boolean);
}
/**
* Options object for DataUrl condition.
@ -443,14 +404,6 @@ declare interface AssetResourceGeneratorOptions {
*/
publicPath?: string | ((pathData: PathData, assetInfo?: AssetInfo) => string);
}
declare abstract class AssetSourceGenerator extends Generator {
generateError(
error: Error,
module: NormalModule,
generateContext: GenerateContext
): null | Source;
}
declare abstract class AssetSourceParser extends ParserClass {}
declare class AsyncDependenciesBlock extends DependenciesBlock {
constructor(
groupOptions:
@ -520,7 +473,6 @@ declare interface AsyncWebAssemblyModulesPluginOptions {
*/
mangleImports?: boolean;
}
declare abstract class AsyncWebAssemblyParser extends ParserClass {}
declare class AutomaticPrefetchPlugin {
constructor();
@ -2092,11 +2044,6 @@ declare interface ColorsOptions {
*/
useColor?: boolean;
}
declare interface CommentCssParser {
value: string;
range: [number, number];
loc: { start: Position; end: Position };
}
declare interface CommonJsImportSettings {
name?: string;
context: string;
@ -3000,6 +2947,22 @@ declare interface Configuration {
*/
devtool?: string | false;
/**
* Enable and configure the Dotenv plugin to load environment variables from .env files.
*/
dotenv?:
| boolean
| {
/**
* The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.
*/
envDir?: string;
/**
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefixes?: string | string[];
};
/**
* The entry point(s) of the compilation.
*/
@ -3611,23 +3574,6 @@ declare interface CssData {
*/
exports: Map<string, string>;
}
declare abstract class CssGenerator extends Generator {
convention?:
| "as-is"
| "camel-case"
| "camel-case-only"
| "dashes"
| "dashes-only"
| ((name: string) => string);
localIdentName?: string;
exportsOnly?: boolean;
esModule?: boolean;
generateError(
error: Error,
module: NormalModule,
generateContext: GenerateContext
): null | Source;
}
/**
* Generator options for css modules.
@ -3823,19 +3769,6 @@ declare class CssModulesPlugin {
): TemplatePath;
static chunkHasCss(chunk: Chunk, chunkGraph: ChunkGraph): boolean;
}
declare abstract class CssParser extends ParserClass {
defaultMode: "global" | "auto" | "pure" | "local";
import: boolean;
url: boolean;
namedExports: boolean;
comments?: CommentCssParser[];
magicCommentContext: Context;
getComments(range: [number, number]): CommentCssParser[];
parseCommentOptions(range: [number, number]): {
options: null | Record<string, any>;
errors: null | (Error & { comment: CommentCssParser })[];
};
}
/**
* Parser options for css modules.
@ -4419,6 +4352,55 @@ declare interface DllReferencePluginOptionsManifest {
| "jsonp"
| "system";
}
declare class DotenvPlugin {
constructor(options?: DotenvPluginOptions);
config: {
/**
* The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.
*/
envDir: string | boolean;
/**
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefixes: string | string[];
};
apply(compiler: Compiler): void;
/**
* Load environment variables from .env files
* Similar to Vite's loadEnv implementation
*/
loadEnv(
fs: InputFileSystem,
mode: undefined | string,
context: string,
callback: (
err: null | Error,
env?: Record<string, string>,
fileDependencies?: string[]
) => void
): void;
/**
* Load a file with proper path resolution
*/
loadFile(fs: InputFileSystem, file: string): Promise<string>;
}
/**
* Options for Dotenv plugin.
*/
declare interface DotenvPluginOptions {
/**
* The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.
*/
envDir?: string;
/**
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefixes?: string | string[];
}
declare class DynamicEntryPlugin {
constructor(context: string, entry: () => Promise<EntryStaticNormalized>);
context: string;
@ -6677,33 +6659,6 @@ declare interface IteratorObject<T, TReturn = unknown, TNext = unknown>
[Symbol.iterator](): IteratorObject<T, TReturn, TNext>;
[Symbol.dispose](): void;
}
declare abstract class JavascriptGenerator extends Generator {
generateError(
error: Error,
module: NormalModule,
generateContext: GenerateContext
): null | Source;
sourceModule(
module: Module,
initFragments: InitFragment<GenerateContext>[],
source: ReplaceSource,
generateContext: GenerateContext
): void;
sourceBlock(
module: Module,
block: DependenciesBlock,
initFragments: InitFragment<GenerateContext>[],
source: ReplaceSource,
generateContext: GenerateContext
): void;
sourceDependency(
module: Module,
dependency: Dependency,
initFragments: InitFragment<GenerateContext>[],
source: ReplaceSource,
generateContext: GenerateContext
): void;
}
declare class JavascriptModulesPlugin {
constructor(options?: object);
options: object;
@ -7188,15 +7143,15 @@ declare class JavascriptParser extends ParserClass {
[LogicalExpression],
boolean | void
>;
program: SyncBailHook<[Program, CommentImport[]], boolean | void>;
program: SyncBailHook<[Program, Comment[]], boolean | void>;
terminate: SyncBailHook<[ReturnStatement | ThrowStatement], boolean | void>;
finish: SyncBailHook<[Program, CommentImport[]], boolean | void>;
finish: SyncBailHook<[Program, Comment[]], boolean | void>;
unusedStatement: SyncBailHook<[Statement], boolean | void>;
}>;
sourceType: "module" | "auto" | "script";
scope: ScopeInfo;
state: ParserState;
comments?: CommentImport[];
comments?: Comment[];
semicolons?: Set<number>;
statementPath?: StatementPathItem[];
prevStatement?:
@ -8020,7 +7975,7 @@ declare class JavascriptParser extends ParserClass {
| MaybeNamedClassDeclaration,
commentsStartPos: number
): boolean;
getComments(range: [number, number]): CommentImport[];
getComments(range: [number, number]): Comment[];
isAsiPosition(pos: number): boolean;
setAsiPosition(pos: number): void;
unsetAsiPosition(pos: number): void;
@ -8056,7 +8011,7 @@ declare class JavascriptParser extends ParserClass {
evaluatedVariable(tagInfo: TagInfo): VariableInfo;
parseCommentOptions(range: [number, number]): {
options: null | Record<string, any>;
errors: null | (Error & { comment: CommentImport })[];
errors: null | (Error & { comment: Comment })[];
};
extractMemberExpressionChain(
expression:
@ -8408,14 +8363,6 @@ declare abstract class JsonData {
| JsonValueFs[];
updateHash(hash: Hash): void;
}
declare abstract class JsonGenerator extends Generator {
options: JsonGeneratorOptions;
generateError(
error: Error,
module: NormalModule,
generateContext: GenerateContext
): null | Source;
}
/**
* Generator options for json modules.
@ -8426,17 +8373,6 @@ declare interface JsonGeneratorOptions {
*/
JSONParse?: boolean;
}
declare interface JsonModulesPluginParserOptions {
/**
* The depth of json dependency flagged as `exportInfo`.
*/
exportsDepth?: number;
/**
* Function that executes for a module source string and should return json-compatible data.
*/
parse?: (input: string) => any;
}
declare interface JsonObjectFs {
[index: string]:
| undefined
@ -8457,9 +8393,6 @@ declare interface JsonObjectTypes {
| JsonObjectTypes
| JsonValueTypes[];
}
declare abstract class JsonParser extends ParserClass {
options: JsonModulesPluginParserOptions;
}
/**
* Parser options for JSON modules.
@ -11391,225 +11324,6 @@ declare abstract class NormalModuleFactory extends ModuleFactory {
],
Module
>;
createParser: TypedHookMap<
Record<
"javascript/auto",
SyncBailHook<[JavascriptParserOptions], JavascriptParser>
> &
Record<
"javascript/dynamic",
SyncBailHook<[JavascriptParserOptions], JavascriptParser>
> &
Record<
"javascript/esm",
SyncBailHook<[JavascriptParserOptions], JavascriptParser>
> &
Record<"json", SyncBailHook<[JsonParserOptions], JsonParser>> &
Record<"asset", SyncBailHook<[AssetParserOptions], AssetParser>> &
Record<
"asset/inline",
SyncBailHook<[EmptyParserOptions], AssetParser>
> &
Record<
"asset/resource",
SyncBailHook<[EmptyParserOptions], AssetParser>
> &
Record<
"asset/source",
SyncBailHook<[EmptyParserOptions], AssetSourceParser>
> &
Record<
"asset/bytes",
SyncBailHook<[EmptyParserOptions], AssetBytesParser>
> &
Record<
"webassembly/async",
SyncBailHook<[EmptyParserOptions], AsyncWebAssemblyParser>
> &
Record<
"webassembly/sync",
SyncBailHook<[EmptyParserOptions], WebAssemblyParser>
> &
Record<"css", SyncBailHook<[CssParserOptions], CssParser>> &
Record<"css/auto", SyncBailHook<[CssAutoParserOptions], CssParser>> &
Record<
"css/module",
SyncBailHook<[CssModuleParserOptions], CssParser>
> &
Record<
"css/global",
SyncBailHook<[CssGlobalParserOptions], CssParser>
> &
Record<string, SyncBailHook<[ParserOptions], ParserClass>>
>;
parser: TypedHookMap<
Record<
"javascript/auto",
SyncBailHook<[JavascriptParser, JavascriptParserOptions], void>
> &
Record<
"javascript/dynamic",
SyncBailHook<[JavascriptParser, JavascriptParserOptions], void>
> &
Record<
"javascript/esm",
SyncBailHook<[JavascriptParser, JavascriptParserOptions], void>
> &
Record<"json", SyncBailHook<[JsonParser, JsonParserOptions], void>> &
Record<"asset", SyncBailHook<[AssetParser, AssetParserOptions], void>> &
Record<
"asset/inline",
SyncBailHook<[AssetParser, EmptyParserOptions], void>
> &
Record<
"asset/resource",
SyncBailHook<[AssetParser, EmptyParserOptions], void>
> &
Record<
"asset/source",
SyncBailHook<[AssetSourceParser, EmptyParserOptions], void>
> &
Record<
"asset/bytes",
SyncBailHook<[AssetBytesParser, EmptyParserOptions], void>
> &
Record<
"webassembly/async",
SyncBailHook<[AsyncWebAssemblyParser, EmptyParserOptions], void>
> &
Record<
"webassembly/sync",
SyncBailHook<[WebAssemblyParser, EmptyParserOptions], void>
> &
Record<"css", SyncBailHook<[CssParser, CssParserOptions], void>> &
Record<
"css/auto",
SyncBailHook<[CssParser, CssAutoParserOptions], void>
> &
Record<
"css/module",
SyncBailHook<[CssParser, CssModuleParserOptions], void>
> &
Record<
"css/global",
SyncBailHook<[CssParser, CssGlobalParserOptions], void>
> &
Record<string, SyncBailHook<[ParserClass, ParserOptions], void>>
>;
createGenerator: TypedHookMap<
Record<
"javascript/auto",
SyncBailHook<[EmptyGeneratorOptions], JavascriptGenerator>
> &
Record<
"javascript/dynamic",
SyncBailHook<[EmptyGeneratorOptions], JavascriptGenerator>
> &
Record<
"javascript/esm",
SyncBailHook<[EmptyGeneratorOptions], JavascriptGenerator>
> &
Record<"json", SyncBailHook<[JsonGeneratorOptions], JsonGenerator>> &
Record<"asset", SyncBailHook<[AssetGeneratorOptions], AssetGenerator>> &
Record<
"asset/inline",
SyncBailHook<[AssetGeneratorOptions], AssetGenerator>
> &
Record<
"asset/resource",
SyncBailHook<[AssetGeneratorOptions], AssetGenerator>
> &
Record<
"asset/source",
SyncBailHook<[EmptyGeneratorOptions], AssetSourceGenerator>
> &
Record<
"asset/bytes",
SyncBailHook<[EmptyGeneratorOptions], AssetBytesGenerator>
> &
Record<
"webassembly/async",
SyncBailHook<[EmptyParserOptions], Generator>
> &
Record<
"webassembly/sync",
SyncBailHook<[EmptyParserOptions], Generator>
> &
Record<"css", SyncBailHook<[CssGeneratorOptions], CssGenerator>> &
Record<
"css/auto",
SyncBailHook<[CssAutoGeneratorOptions], CssGenerator>
> &
Record<
"css/module",
SyncBailHook<[CssModuleGeneratorOptions], CssGenerator>
> &
Record<
"css/global",
SyncBailHook<[CssGlobalGeneratorOptions], CssGenerator>
> &
Record<string, SyncBailHook<[GeneratorOptions], Generator>>
>;
generator: TypedHookMap<
Record<
"javascript/auto",
SyncBailHook<[JavascriptGenerator, EmptyGeneratorOptions], void>
> &
Record<
"javascript/dynamic",
SyncBailHook<[JavascriptGenerator, EmptyGeneratorOptions], void>
> &
Record<
"javascript/esm",
SyncBailHook<[JavascriptGenerator, EmptyGeneratorOptions], void>
> &
Record<
"json",
SyncBailHook<[JsonGenerator, JsonGeneratorOptions], void>
> &
Record<
"asset",
SyncBailHook<[AssetGenerator, AssetGeneratorOptions], void>
> &
Record<
"asset/inline",
SyncBailHook<[AssetGenerator, AssetGeneratorOptions], void>
> &
Record<
"asset/resource",
SyncBailHook<[AssetGenerator, AssetGeneratorOptions], void>
> &
Record<
"asset/source",
SyncBailHook<[AssetSourceGenerator, EmptyGeneratorOptions], void>
> &
Record<
"asset/bytes",
SyncBailHook<[AssetBytesGenerator, EmptyGeneratorOptions], void>
> &
Record<
"webassembly/async",
SyncBailHook<[Generator, EmptyParserOptions], void>
> &
Record<
"webassembly/sync",
SyncBailHook<[Generator, EmptyParserOptions], void>
> &
Record<"css", SyncBailHook<[CssGenerator, CssGeneratorOptions], void>> &
Record<
"css/auto",
SyncBailHook<[CssGenerator, CssAutoGeneratorOptions], void>
> &
Record<
"css/module",
SyncBailHook<[CssGenerator, CssModuleGeneratorOptions], void>
> &
Record<
"css/global",
SyncBailHook<[CssGenerator, CssGlobalGeneratorOptions], void>
> &
Record<string, SyncBailHook<[Generator, GeneratorOptions], void>>
>;
createModuleClass: HookMap<
SyncBailHook<
[
@ -13482,10 +13196,6 @@ declare interface PnpApi {
options: { considerBuiltins: boolean }
) => null | string;
}
declare interface Position {
line: number;
column: number;
}
declare class PrefetchPlugin {
constructor(context: string, request?: string);
context: null | string;
@ -18135,7 +17845,6 @@ declare abstract class WeakTupleMap<K extends any[], V> {
delete(...args: K): void;
clear(): void;
}
declare abstract class WebAssemblyParser extends ParserClass {}
declare interface WebAssemblyRenderContext {
/**
* the chunk
@ -18313,6 +18022,22 @@ declare interface WebpackOptionsNormalized {
*/
devtool?: string | false;
/**
* Enable and configure the Dotenv plugin to load environment variables from .env files.
*/
dotenv?:
| boolean
| {
/**
* The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.
*/
envDir?: string;
/**
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefixes?: string | string[];
};
/**
* The entry point(s) of the compilation.
*/
@ -18514,7 +18239,39 @@ type WebpackOptionsNormalizedWithDefaults = WebpackOptionsNormalized & {
} & { watch: NonNullable<undefined | boolean> } & {
performance: NonNullable<undefined | false | PerformanceOptions>;
} & { recordsInputPath: NonNullable<undefined | string | false> } & {
recordsOutputPath: NonNullable<undefined | string | false>;
recordsOutputPath:
| (string & {
dotenv: NonNullable<
| undefined
| boolean
| {
/**
* The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.
*/
envDir?: string;
/**
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefixes?: string | string[];
}
>;
})
| (false & {
dotenv: NonNullable<
| undefined
| boolean
| {
/**
* The directory from which .env files are loaded. Defaults to the webpack context. Loads .env, .env.local, .env.[mode], .env.[mode].local in order.
*/
envDir?: string;
/**
* Only expose environment variables that start with these prefixes. Defaults to 'WEBPACK_'.
*/
prefixes?: string | string[];
}
>;
});
};
/**
@ -19237,6 +18994,7 @@ declare namespace exports {
DllPlugin,
DllReferencePlugin,
DynamicEntryPlugin,
DotenvPlugin,
EntryOptionPlugin,
EntryPlugin,
EnvironmentPlugin,