webpack-v5-chain
Version:
Use a chaining API to generate and simplify the modification of webpack 5 configurations.
449 lines (402 loc) • 18.7 kB
TypeScript
import Webpack from 'webpack';
import { Configuration } from 'webpack-dev-server';
/* eslint-disable @typescript-eslint/no-explicit-any */
interface Orderable {
before(name: string): this;
after(name: string): this;
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
declare class Chained<Parent> {
batch(handler: (chained: this) => void): this;
end(): Parent;
}
declare class TypedChainedMap<Parent, OptionsType> extends Chained<Parent> {
clear(): this;
delete(key: string): this;
has(key: string): boolean;
get<T extends keyof OptionsType>(key: T): OptionsType[T];
getOrCompute<T extends keyof OptionsType>(
key: T,
compute: () => OptionsType[T],
): OptionsType[T];
set<T extends keyof OptionsType>(key: T, value: OptionsType[T]): this;
merge(obj: Partial<OptionsType>): this;
entries(): OptionsType;
values<T extends keyof OptionsType>(): [OptionsType[T]][];
when(
condition: boolean,
trueHandler: (obj: this) => void,
falseHandler?: (obj: this) => void,
): this;
}
declare class ChainedMap<Parent> extends TypedChainedMap<Parent, any> {}
declare class TypedChainedSet<Parent, Value> extends Chained<Parent> {
add(value: Value): this;
prepend(value: Value): this;
clear(): this;
delete(key: string): this;
has(key: string): boolean;
merge(arr: Value[]): this;
values(): Value[];
when(
condition: boolean,
trueHandler: (obj: this) => void,
falseHandler?: (obj: this) => void,
): this;
}
declare class ChainedSet<Parent> extends TypedChainedSet<Parent, any> {}
/* eslint-disable @typescript-eslint/no-explicit-any */
type WebpackConfig = Required<Webpack.Configuration>;
declare class Config extends ChainedMap<void> {
entryPoints: TypedChainedMap<Config, Record<string, EntryPoint>>;
output: Output;
module: Module;
optimization: Optimization;
performance: Performance & ((value: boolean) => this);
plugins: Plugins<this, Webpack.WebpackPluginInstance>;
resolve: Resolve;
resolveLoader: ResolveLoader;
devServer: DevServer;
entry(name: string): EntryPoint;
plugin(name: string): Plugin<this, Webpack.WebpackPluginInstance>;
context(value: WebpackConfig["context"]): this;
mode(value: WebpackConfig["mode"]): this;
cache(value: WebpackConfig["cache"]): this;
devtool(value: WebpackConfig["devtool"]): this;
target(value: WebpackConfig["target"]): this;
watch(value: WebpackConfig["watch"]): this;
watchOptions(value: WebpackConfig["watchOptions"]): this;
externals(value: WebpackConfig["externals"]): this;
externalsType(value: WebpackConfig["externalsType"]): this;
externalsPresets(value: WebpackConfig["externalsPresets"]): this;
node(value: WebpackConfig["node"]): this;
stats(value: WebpackConfig["stats"]): this;
experiments(value: WebpackConfig["experiments"]): this;
infrastructureLogging(value: WebpackConfig["infrastructureLogging"]): this;
amd(value: WebpackConfig["amd"]): this;
bail(value: WebpackConfig["bail"]): this;
dependencies(value: WebpackConfig["dependencies"]): this;
ignoreWarnings(value: WebpackConfig["ignoreWarnings"]): this;
loader(value: WebpackConfig["loader"]): this;
name(value: WebpackConfig["name"]): this;
parallelism(value: WebpackConfig["parallelism"]): this;
profile(value: WebpackConfig["profile"]): this;
recordsInputPath(value: WebpackConfig["recordsInputPath"]): this;
recordsOutputPath(value: WebpackConfig["recordsOutputPath"]): this;
recordsPath(value: WebpackConfig["recordsPath"]): this;
snapshot(value: WebpackConfig["snapshot"]): this;
toConfig(): Webpack.Configuration;
}
declare class Plugins<
Parent,
PluginType extends Webpack.WebpackPluginInstance,
> extends TypedChainedMap<Parent, Record<string, Plugin<Parent, PluginType>>> {}
declare class Plugin<
Parent,
PluginType extends Webpack.WebpackPluginInstance | ResolvePlugin,
>
extends ChainedMap<Parent>
implements Orderable
{
init<P extends PluginType | PluginClass<PluginType>>(
value: (
plugin: P,
args: P extends PluginClass<PluginType>
? ConstructorParameters<P>
: any[],
) => PluginType,
): this;
use<P extends string | PluginType | PluginClass<PluginType>>(
plugin: P,
args?: P extends PluginClass<PluginType> ? ConstructorParameters<P> : any[],
): this;
tap<P extends PluginClass<PluginType>>(
f: (args: ConstructorParameters<P>) => ConstructorParameters<P>,
): this;
// Orderable
before(name: string): this;
after(name: string): this;
}
type WebpackEntry = NonNullable<Webpack.Configuration["entry"]>;
type WebpackEntryObject = Exclude<
WebpackEntry,
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
string | string[] | Function
>[string];
declare class EntryPoint extends TypedChainedSet<Config, WebpackEntryObject> {}
type WebpackModule = Required<NonNullable<Webpack.Configuration["module"]>>;
declare class Module extends ChainedMap<Config> {
rules: TypedChainedMap<this, Record<string, Rule>>;
generator: ChainedMap<this>;
parser: ChainedMap<this>;
rule(name: string): Rule;
noParse(value: WebpackModule["noParse"]): this;
unsafeCache(value: WebpackModule["unsafeCache"]): this;
exprContextCritical(value: WebpackModule["exprContextCritical"]): this;
exprContextRecursive(value: WebpackModule["exprContextRecursive"]): this;
exprContextRegExp(value: WebpackModule["exprContextRegExp"]): this;
unknownContextCritical(value: WebpackModule["unknownContextCritical"]): this;
unknownContextRecursive(
value: WebpackModule["unknownContextRecursive"],
): this;
unknownContextRegExp(value: WebpackModule["unknownContextRegExp"]): this;
unknownContextRequest(value: WebpackModule["unknownContextRequest"]): this;
wrappedContextCritical(value: WebpackModule["wrappedContextCritical"]): this;
wrappedContextRecursive(
value: WebpackModule["wrappedContextRecursive"],
): this;
wrappedContextRegExp(value: WebpackModule["wrappedContextRegExp"]): this;
strictExportPresence(value: WebpackModule["strictExportPresence"]): this;
}
type WebpackOutput = Required<NonNullable<Webpack.Configuration["output"]>>;
declare class Output extends ChainedMap<Config> {
assetModuleFilename(value: WebpackOutput["assetModuleFilename"]): this;
asyncChunks(value: WebpackOutput["asyncChunks"]): this;
auxiliaryComment(value: WebpackOutput["auxiliaryComment"]): this;
charset(value: WebpackOutput["charset"]): this;
chunkFilename(value: WebpackOutput["chunkFilename"]): this;
chunkFormat(value: WebpackOutput["chunkFormat"]): this;
chunkLoadTimeout(value: WebpackOutput["chunkLoadTimeout"]): this;
chunkLoadingGlobal(value: WebpackOutput["chunkLoadingGlobal"]): this;
chunkLoading(value: WebpackOutput["chunkLoading"]): this;
clean(value: WebpackOutput["clean"]): this;
compareBeforeEmit(value: WebpackOutput["compareBeforeEmit"]): this;
crossOriginLoading(value: WebpackOutput["crossOriginLoading"]): this;
cssChunkFilename(value: WebpackOutput["cssChunkFilename"]): this;
cssFilename(value: WebpackOutput["cssFilename"]): this;
devtoolFallbackModuleFilenameTemplate(
value: WebpackOutput["devtoolFallbackModuleFilenameTemplate"],
): this;
devtoolModuleFilenameTemplate(
value: WebpackOutput["devtoolModuleFilenameTemplate"],
): this;
devtoolNamespace(value: WebpackOutput["devtoolNamespace"]): this;
enabledChunkLoadingTypes(
value: WebpackOutput["enabledChunkLoadingTypes"],
): this;
enabledLibraryTypes(value: WebpackOutput["enabledLibraryTypes"]): this;
enabledWasmLoadingTypes(
value: WebpackOutput["enabledWasmLoadingTypes"],
): this;
environment(value: WebpackOutput["environment"]): this;
filename(value: WebpackOutput["filename"]): this;
globalObject(value: WebpackOutput["globalObject"]): this;
hashDigest(value: WebpackOutput["hashDigest"]): this;
hashDigestLength(value: WebpackOutput["hashDigestLength"]): this;
hashFunction(value: WebpackOutput["hashFunction"]): this;
hashSalt(value: WebpackOutput["hashSalt"]): this;
hotUpdateChunkFilename(value: WebpackOutput["hotUpdateChunkFilename"]): this;
hotUpdateGlobal(value: WebpackOutput["hotUpdateGlobal"]): this;
hotUpdateMainFilename(value: WebpackOutput["hotUpdateMainFilename"]): this;
iife(value: WebpackOutput["iife"]): this;
ignoreBrowserWarnings(value: WebpackOutput["ignoreBrowserWarnings"]): this;
importFunctionName(value: WebpackOutput["importFunctionName"]): this;
importMetaName(value: WebpackOutput["importMetaName"]): this;
library(value: WebpackOutput["library"]): this;
libraryExport(value: WebpackOutput["libraryExport"]): this;
libraryTarget(value: WebpackOutput["libraryTarget"]): this;
module(value: WebpackOutput["module"]): this;
path(value: WebpackOutput["path"]): this;
pathinfo(value: WebpackOutput["pathinfo"]): this;
publicPath(value: WebpackOutput["publicPath"]): this;
scriptType(value: WebpackOutput["scriptType"]): this;
sourceMapFilename(value: WebpackOutput["sourceMapFilename"]): this;
sourcePrefix(value: WebpackOutput["sourcePrefix"]): this;
strictModuleErrorHandling(
value: WebpackOutput["strictModuleErrorHandling"],
): this;
strictModuleExceptionHandling(
value: WebpackOutput["strictModuleExceptionHandling"],
): this;
trustedTypes(value: WebpackOutput["trustedTypes"]): this;
umdNamedDefine(value: WebpackOutput["umdNamedDefine"]): this;
uniqueName(value: WebpackOutput["uniqueName"]): this;
wasmLoading(value: WebpackOutput["wasmLoading"]): this;
webassemblyModuleFilename(
value: WebpackOutput["webassemblyModuleFilename"],
): this;
workerChunkLoading(value: WebpackOutput["workerChunkLoading"]): this;
workerPublicPath(value: WebpackOutput["workerPublicPath"]): this;
workerWasmLoading(value: WebpackOutput["workerWasmLoading"]): this;
}
type DevServerOptions = Configuration;
// await for @types/webpack-dev-server update do v4 to remove all any
declare class DevServer extends ChainedMap<Config> {
allowedHosts: TypedChainedSet<this, string>;
after(
value: (app: any, server: any, compiler: Webpack.Compiler) => void,
): this;
before(
value: (app: any, server: any, compiler: Webpack.Compiler) => void,
): this;
app(value: DevServerOptions["app"]): this;
bonjour(value: DevServerOptions["bonjour"]): this;
client(value: DevServerOptions["client"]): this;
compress(value: DevServerOptions["compress"]): this;
devMiddleware(value: DevServerOptions["devMiddleware"]): this;
headers(value: DevServerOptions["headers"]): this;
historyApiFallback(value: DevServerOptions["historyApiFallback"]): this;
host(value: DevServerOptions["host"]): this;
hot(value: DevServerOptions["hot"]): this;
ipc(value: DevServerOptions["ipc"]): this;
liveReload(value: DevServerOptions["liveReload"]): this;
onListening(value: DevServerOptions["onListening"]): this;
open(value: DevServerOptions["open"]): this;
port(value: DevServerOptions["port"]): this;
proxy(value: DevServerOptions["proxy"]): this;
server(value: DevServerOptions["server"]): this;
setupExitSignals(value: DevServerOptions["setupExitSignals"]): this;
setupMiddlewares(value: DevServerOptions["setupMiddlewares"]): this;
static(value: DevServerOptions["static"]): this;
watchFiles(value: DevServerOptions["watchFiles"]): this;
webSocketServer(value: DevServerOptions["webSocketServer"]): this;
}
type WebpackPerformance = Exclude<
Required<NonNullable<Webpack.Configuration["performance"]>>,
false
>;
declare class Performance extends ChainedMap<Config> {
hints(value: WebpackPerformance["hints"]): this;
maxEntrypointSize(value: WebpackPerformance["maxEntrypointSize"]): this;
maxAssetSize(value: WebpackPerformance["maxAssetSize"]): this;
assetFilter(value: WebpackPerformance["assetFilter"]): this;
}
type WebpackResolve = Required<NonNullable<Webpack.Configuration["resolve"]>>;
type ResolvePlugin = Exclude<
NonNullable<Webpack.ResolveOptions["plugins"]>[number],
"..."
>;
declare class Resolve<T = Config> extends ChainedMap<T> {
alias: TypedChainedMap<this, Record<string, string | false | string[]>>;
aliasFields: TypedChainedSet<this, WebpackResolve["aliasFields"][number]>;
byDependency: TypedChainedMap<this, WebpackResolve["byDependency"]>;
conditionNames: TypedChainedSet<
this,
WebpackResolve["conditionNames"][number]
>;
descriptionFiles: TypedChainedSet<
this,
WebpackResolve["descriptionFiles"][number]
>;
exportsFields: TypedChainedSet<this, WebpackResolve["exportsFields"][number]>;
extensionAlias: TypedChainedMap<this, WebpackResolve["extensionAlias"]>;
extensions: TypedChainedSet<this, WebpackResolve["extensions"][number]>;
fallback: TypedChainedMap<this, Record<string, string | false | string[]>>;
importsFields: TypedChainedSet<this, WebpackResolve["importsFields"][number]>;
mainFields: TypedChainedSet<this, WebpackResolve["mainFields"][number]>;
mainFiles: TypedChainedSet<this, WebpackResolve["mainFiles"][number]>;
modules: TypedChainedSet<this, WebpackResolve["modules"][number]>;
plugins: TypedChainedMap<
this,
Record<string, Plugin<Resolve, ResolvePlugin>>
>;
restrictions: TypedChainedSet<this, WebpackResolve["restrictions"][number]>;
roots: TypedChainedSet<this, WebpackResolve["roots"][number]>;
plugin(name: string): Plugin<this, ResolvePlugin>;
cache(value: WebpackResolve["cache"]): this;
cachePredicate(value: WebpackResolve["cachePredicate"]): this;
cacheWithContext(value: WebpackResolve["cacheWithContext"]): this;
enforceExtension(value: WebpackResolve["enforceExtension"]): this;
fullySpecified(value: WebpackResolve["fullySpecified"]): this;
preferAbsolute(value: WebpackResolve["preferAbsolute"]): this;
preferRelative(value: WebpackResolve["preferRelative"]): this;
symlinks(value: WebpackResolve["symlinks"]): this;
unsafeCache(value: WebpackResolve["unsafeCache"]): this;
useSyncFileSystemCalls(value: WebpackResolve["useSyncFileSystemCalls"]): this;
}
declare class RuleResolve<T = Config> extends Resolve<T> {
fullySpecified(value: boolean): this;
}
declare class ResolveLoader extends Resolve {
modules: ChainedSet<this>;
moduleExtensions: ChainedSet<this>;
packageMains: ChainedSet<this>;
}
type WebpackRuleSet = Required<Webpack.RuleSetRule>;
declare class Rule<T = Module> extends ChainedMap<T> implements Orderable {
uses: TypedChainedMap<this, Record<string, Use>>;
include: TypedChainedSet<this, WebpackRuleSet["include"]>;
exclude: TypedChainedSet<this, WebpackRuleSet["exclude"]>;
rules: TypedChainedMap<this, Record<string, Rule<Rule>>>;
oneOfs: TypedChainedMap<this, Record<string, Rule<Rule>>>;
resolve: RuleResolve<Rule<T>>;
assert(value: WebpackRuleSet["assert"]): this;
compiler(value: WebpackRuleSet["compiler"]): this;
enforce(value: WebpackRuleSet["enforce"]): this;
issuer(value: WebpackRuleSet["issuer"]): this;
issuerLayer(value: WebpackRuleSet["issuerLayer"]): this;
layer(value: WebpackRuleSet["layer"]): this;
mimetype(value: WebpackRuleSet["mimetype"]): this;
parser(value: WebpackRuleSet["parser"]): this;
generator(value: WebpackRuleSet["generator"]): this;
resource(value: WebpackRuleSet["resource"]): this;
resourceQuery(value: WebpackRuleSet["resourceQuery"]): this;
scheme(value: WebpackRuleSet["scheme"]): this;
sideEffects(value: WebpackRuleSet["sideEffects"]): this;
test(value: WebpackRuleSet["test"]): this;
type(value: WebpackRuleSet["type"]): this;
with(value: WebpackRuleSet["with"]): this;
use(name: string): Use<this>;
rule(name: string): Rule<Rule>;
oneOf(name: string): Rule<Rule>;
pre(): this;
post(): this;
before(name: string): this;
after(name: string): this;
}
type WebpackOptimization = Required<
NonNullable<Webpack.Configuration["optimization"]>
>;
type SplitChunksObject = Exclude<WebpackOptimization["splitChunks"], false>;
declare class Optimization extends ChainedMap<Config> {
checkWasmTypes(value: WebpackOptimization["checkWasmTypes"]): this;
chunkIds(value: WebpackOptimization["chunkIds"]): this;
concatenateModules(value: WebpackOptimization["concatenateModules"]): this;
emitOnErrors(value: WebpackOptimization["emitOnErrors"]): this;
avoidEntryIife(value: WebpackOptimization["avoidEntryIife"]): this;
flagIncludedChunks(value: WebpackOptimization["flagIncludedChunks"]): this;
innerGraph(value: WebpackOptimization["innerGraph"]): this;
mangleExports(value: WebpackOptimization["mangleExports"]): this;
mangleWasmImports(value: WebpackOptimization["mangleWasmImports"]): this;
mergeDuplicateChunks(
value: WebpackOptimization["mergeDuplicateChunks"],
): this;
minimize(value: WebpackOptimization["minimize"]): this;
minimizer(name: string): Plugin<this, Webpack.WebpackPluginInstance>;
moduleIds(value: WebpackOptimization["moduleIds"]): this;
nodeEnv(value: WebpackOptimization["nodeEnv"]): this;
portableRecords(value: WebpackOptimization["portableRecords"]): this;
providedExports(value: WebpackOptimization["providedExports"]): this;
realContentHash(value: WebpackOptimization["realContentHash"]): this;
removeAvailableModules(
value: WebpackOptimization["removeAvailableModules"],
): this;
removeEmptyChunks(value: WebpackOptimization["removeEmptyChunks"]): this;
runtimeChunk(value: WebpackOptimization["runtimeChunk"]): this;
sideEffects(value: WebpackOptimization["sideEffects"]): this;
splitChunks: TypedChainedMap<this, SplitChunksObject> &
((value: SplitChunksObject | false) => this);
usedExports(value: WebpackOptimization["usedExports"]): this;
}
interface RuntimeChunk {
name: string | RuntimeChunkFunction;
}
type RuntimeChunkFunction = (entryPoint: EntryPoint) => string;
type SplitChunksOptions = Record<string, any>;
type LoaderOptions = Record<string, any>;
declare class Use<Parent = Rule>
extends ChainedMap<Parent>
implements Orderable
{
loader(value: string): this;
options(value: LoaderOptions): this;
tap(f: (options: LoaderOptions) => LoaderOptions): this;
// Orderable
before(name: string): this;
after(name: string): this;
}
type PluginClass<
PluginType extends Webpack.WebpackPluginInstance | ResolvePlugin,
> = new (...opts: any[]) => PluginType;
export { Config, DevServer, EntryPoint, Module, Optimization, Output, Performance, Plugin, Plugins, Resolve, ResolveLoader, Rule, RuleResolve, Use };
export type { DevServerOptions, LoaderOptions, PluginClass, ResolvePlugin, RuntimeChunk, RuntimeChunkFunction, SplitChunksObject, SplitChunksOptions, WebpackConfig, WebpackEntry, WebpackEntryObject, WebpackModule, WebpackOptimization, WebpackOutput, WebpackPerformance, WebpackResolve, WebpackRuleSet };