@workleap/webpack-configs 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +35 -23
  2. package/README.md +2 -2
  3. package/dist/build.d.ts +18 -19
  4. package/dist/build.js +219 -3
  5. package/dist/build.js.map +1 -0
  6. package/dist/dev.d.ts +16 -17
  7. package/dist/dev.js +208 -3
  8. package/dist/dev.js.map +1 -0
  9. package/dist/index.d.ts +6 -12
  10. package/dist/index.js +15 -7
  11. package/dist/index.js.map +1 -0
  12. package/dist/transformers/applyTransformers.d.ts +4 -7
  13. package/dist/transformers/applyTransformers.js +20 -1
  14. package/dist/transformers/applyTransformers.js.map +1 -0
  15. package/dist/transformers/moduleRules.d.ts +15 -17
  16. package/dist/transformers/moduleRules.js +166 -1
  17. package/dist/transformers/moduleRules.js.map +1 -0
  18. package/dist/transformers/plugins.d.ts +11 -14
  19. package/dist/transformers/plugins.js +69 -1
  20. package/dist/transformers/plugins.js.map +1 -0
  21. package/dist/types.d.ts +1 -1
  22. package/dist/types.js +6 -1
  23. package/dist/types.js.map +1 -0
  24. package/dist/utils.d.ts +4 -6
  25. package/dist/utils.js +22 -1
  26. package/dist/utils.js.map +1 -0
  27. package/package.json +21 -24
  28. package/src/build.ts +240 -0
  29. package/src/dev.ts +233 -0
  30. package/src/index.ts +7 -0
  31. package/src/transformers/applyTransformers.ts +28 -0
  32. package/src/transformers/moduleRules.ts +229 -0
  33. package/src/transformers/plugins.ts +102 -0
  34. package/src/types.ts +1 -0
  35. package/src/utils.ts +19 -0
  36. package/dist/chunk-2YARCRX5.js +0 -15
  37. package/dist/chunk-34O5ZLZ6.js +0 -154
  38. package/dist/chunk-5ACA7GOB.js +0 -17
  39. package/dist/chunk-6F4PWJZI.js +0 -1
  40. package/dist/chunk-CW54GSNS.js +0 -197
  41. package/dist/chunk-JPURRV2F.js +0 -71
  42. package/dist/chunk-JU2EHEXW.js +0 -186
package/src/dev.ts ADDED
@@ -0,0 +1,233 @@
1
+ import ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin";
2
+ import type { ReactRefreshPluginOptions } from "@pmmmwh/react-refresh-webpack-plugin/types/lib/types.d.ts";
3
+ import type { Config as SvgrOptions } from "@svgr/core";
4
+ import type { Config as SwcConfig } from "@swc/core";
5
+ import HtmlWebpackPlugin from "html-webpack-plugin";
6
+ import { createRequire } from "node:module";
7
+ import path from "node:path";
8
+ import webpack from "webpack";
9
+ import type { ServerOptions } from "webpack-dev-server";
10
+ import { applyTransformers, type WebpackConfigTransformer } from "./transformers/applyTransformers.ts";
11
+ import { isNil, isObject } from "./utils.ts";
12
+
13
+ // Add the "devServer" option to WebpackConfig typings.
14
+ import "webpack-dev-server";
15
+ import type { WebpackConfig } from "./types.ts";
16
+
17
+ // Aliases
18
+ const DefinePlugin = webpack.DefinePlugin;
19
+
20
+ // Using node:module.createRequire until
21
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve
22
+ // is available
23
+ const require = createRequire(import.meta.url);
24
+
25
+ export function defineDevHtmlWebpackPluginConfig(options: HtmlWebpackPlugin.Options = {}): HtmlWebpackPlugin.Options {
26
+ const {
27
+ template = path.resolve("./public/index.html"),
28
+ ...rest
29
+ } = options;
30
+
31
+ return {
32
+ ...rest,
33
+ template
34
+ };
35
+ }
36
+
37
+ export function defineFastRefreshPluginConfig(options: ReactRefreshPluginOptions = {}) {
38
+ return options;
39
+ }
40
+
41
+ export interface DefineDevConfigOptions {
42
+ entry?: string;
43
+ https?: boolean | ServerOptions | undefined;
44
+ host?: string;
45
+ port?: number;
46
+ publicPath?: `${string}/` | "auto";
47
+ cache?: boolean;
48
+ moduleRules?: NonNullable<WebpackConfig["module"]>["rules"];
49
+ plugins?: WebpackConfig["plugins"];
50
+ htmlWebpackPlugin?: boolean | HtmlWebpackPlugin.Options;
51
+ fastRefresh?: boolean | ReactRefreshPluginOptions;
52
+ cssModules?: boolean;
53
+ overlay?: false;
54
+ svgr?: boolean | SvgrOptions;
55
+ environmentVariables?: Record<string, unknown>;
56
+ transformers?: WebpackConfigTransformer[];
57
+ verbose?: boolean;
58
+ }
59
+
60
+ function preflight() {
61
+ if (!require.resolve("webpack-dev-server")) {
62
+ throw new Error("[webpack-configs] To use the \"dev\" config, install https://www.npmjs.com/package/webpack-dev-server as a \"devDependency\".");
63
+ }
64
+ }
65
+
66
+ function trySetSwcFastRefresh(config: SwcConfig, enabled: boolean) {
67
+ if (config?.jsc?.transform?.react) {
68
+ config.jsc.transform.react.refresh = enabled;
69
+ }
70
+
71
+ return config;
72
+ }
73
+
74
+ function trySetFastRefreshOverlay(options: ReactRefreshPluginOptions, overlay?: boolean) {
75
+ if (overlay === false && isNil(options.overlay)) {
76
+ options.overlay = false;
77
+ }
78
+
79
+ return options;
80
+ }
81
+
82
+ export function defineDevConfig(swcConfig: SwcConfig, options: DefineDevConfigOptions = {}) {
83
+ preflight();
84
+
85
+ const {
86
+ entry = path.resolve("./src/index.tsx"),
87
+ https = false,
88
+ host = "localhost",
89
+ port = 8080,
90
+ publicPath,
91
+ cache = true,
92
+ moduleRules = [],
93
+ plugins = [],
94
+ htmlWebpackPlugin = defineDevHtmlWebpackPluginConfig(),
95
+ fastRefresh = true,
96
+ cssModules = false,
97
+ overlay,
98
+ svgr = true,
99
+ // Using an empty object literal as the default value to ensure
100
+ // "process.env" is always available.
101
+ environmentVariables = {},
102
+ transformers = [],
103
+ verbose = false
104
+ } = options;
105
+
106
+ const config: WebpackConfig = {
107
+ mode: "development",
108
+ target: "web",
109
+ devtool: "eval-cheap-module-source-map",
110
+ devServer: {
111
+ // According to the Fast Refresh plugin documentation, hot should be "true" to enable Fast Refresh:
112
+ // https://github.com/pmmmwh/react-refresh-webpack-plugin#usage.
113
+ hot: true,
114
+ host,
115
+ port,
116
+ historyApiFallback: true,
117
+ client: (overlay === false || fastRefresh) ? {
118
+ overlay: false
119
+ } : undefined,
120
+ server: https ? {
121
+ type: "https",
122
+ options: isObject(https) ? https : undefined
123
+ } : undefined
124
+ },
125
+ entry,
126
+ output: {
127
+ // The trailing / is very important, otherwise paths will not be resolved correctly.
128
+ publicPath: publicPath ?? `${https ? "https" : "http"}://${host}:${port}/`
129
+ },
130
+ cache: cache && {
131
+ type: "memory",
132
+ maxGenerations: 1
133
+ },
134
+ // See: https://webpack.js.org/guides/build-performance/#avoid-extra-optimization-steps
135
+ optimization: {
136
+ // Keep "runtimeChunk" to false, otherwise it breaks module federation
137
+ // (at least for the remote application).
138
+ runtimeChunk: false,
139
+ removeAvailableModules: false,
140
+ removeEmptyChunks: false,
141
+ splitChunks: false
142
+ },
143
+ infrastructureLogging: verbose ? {
144
+ appendOnly: true,
145
+ level: "verbose",
146
+ debug: /PackFileCache/
147
+ } : undefined,
148
+ module: {
149
+ rules: [
150
+ {
151
+ test: /\.(js|jsx|ts|tsx)$/i,
152
+ exclude: /node_modules/,
153
+ loader: require.resolve("swc-loader"),
154
+ options: trySetSwcFastRefresh(swcConfig, fastRefresh !== false)
155
+ },
156
+ {
157
+ // https://stackoverflow.com/questions/69427025/programmatic-webpack-jest-esm-cant-resolve-module-without-js-file-exten
158
+ test: /\.js$/i,
159
+ include: /node_modules/,
160
+ resolve: {
161
+ fullySpecified: false
162
+ }
163
+ },
164
+ {
165
+ test: /\.css$/i,
166
+ use: [
167
+ { loader: require.resolve("style-loader") },
168
+ {
169
+ loader: require.resolve("css-loader"),
170
+ options: cssModules
171
+ ? {
172
+ // Must match the number of loaders applied before this one.
173
+ importLoaders: 1,
174
+ modules: true
175
+ }
176
+ : undefined
177
+ },
178
+ { loader: require.resolve("postcss-loader") }
179
+ ]
180
+ },
181
+ ...(svgr
182
+ ? [
183
+ {
184
+ test: /\.svg$/i,
185
+ loader: require.resolve("@svgr/webpack"),
186
+ options: isObject(svgr) ? svgr : undefined
187
+ },
188
+ {
189
+ test: /\.(png|jpe?g|gif)$/i,
190
+ type: "asset/resource"
191
+ }
192
+ ]
193
+ : [
194
+ {
195
+ test: /\.(png|jpe?g|gif|svg)$/i,
196
+ type: "asset/resource"
197
+ }
198
+ ]),
199
+ ...moduleRules
200
+ ]
201
+ },
202
+ resolve: {
203
+ extensions: [".js", ".jsx", ".ts", ".tsx", ".css"],
204
+ alias: {
205
+ // Fixes Module not found: Error: Can't resolve '@swc/helpers/_/_class_private_field_init'.
206
+ // View https://github.com/vercel/next.js/pull/38174 for more information and https://github.com/vercel/next.js/issues/48593.
207
+ "@swc/helpers": path.dirname(require.resolve("@swc/helpers/package.json"))
208
+ }
209
+ },
210
+ plugins: [
211
+ htmlWebpackPlugin && new HtmlWebpackPlugin(isObject(htmlWebpackPlugin) ? htmlWebpackPlugin : defineDevHtmlWebpackPluginConfig()),
212
+ // Stringify the environment variables because the plugin does a direct text replacement. Otherwise, "production" would become production
213
+ // after replacement and cause an undefined var error.
214
+ // For more information, view: https://webpack.js.org/plugins/define-plugin/.
215
+ new DefinePlugin({
216
+ "process.env": Object.keys(environmentVariables).reduce((acc, key) => {
217
+ acc[key] = JSON.stringify(environmentVariables[key]);
218
+
219
+ return acc;
220
+ }, {} as Record<string, string>)
221
+ }),
222
+ fastRefresh && new ReactRefreshWebpackPlugin(trySetFastRefreshOverlay(isObject(fastRefresh) ? fastRefresh : defineFastRefreshPluginConfig(), overlay)),
223
+ ...plugins
224
+ ].filter(Boolean)
225
+ };
226
+
227
+ const transformedConfig = applyTransformers(config, transformers, {
228
+ environment: "dev",
229
+ verbose
230
+ });
231
+
232
+ return transformedConfig;
233
+ }
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from "./build.ts";
2
+ export * from "./dev.ts";
3
+ export type { WebpackConfigTransformer, WebpackConfigTransformerContext } from "./transformers/applyTransformers.ts";
4
+ export * from "./transformers/moduleRules.ts";
5
+ export * from "./transformers/plugins.ts";
6
+ export * from "./types.ts";
7
+
@@ -0,0 +1,28 @@
1
+ import type { WebpackConfig } from "../types.ts";
2
+
3
+ export interface WebpackConfigTransformerContext {
4
+ environment: "dev" | "build";
5
+ verbose: boolean;
6
+ }
7
+
8
+ export type WebpackConfigTransformer = (config: WebpackConfig, context: WebpackConfigTransformerContext) => WebpackConfig;
9
+
10
+ export function applyTransformers(config: WebpackConfig, transformers: WebpackConfigTransformer[], context: WebpackConfigTransformerContext) {
11
+ let count = 0;
12
+
13
+ const transformedConfig = transformers.reduce((acc, transformer) => {
14
+ const newConfig = transformer(acc, context);
15
+
16
+ count += 1;
17
+
18
+ return newConfig;
19
+ }, config);
20
+
21
+ if (context.verbose) {
22
+ if (count > 0) {
23
+ console.log(`[webpack-configs] Applied ${count} configuration transformers.`);
24
+ }
25
+ }
26
+
27
+ return transformedConfig;
28
+ }
@@ -0,0 +1,229 @@
1
+ import path from "node:path";
2
+ import type { RuleSetRule, RuleSetUseItem } from "webpack";
3
+ import type { WebpackConfig } from "../types.ts";
4
+
5
+ export type ModuleRuleMatcher = (moduleRule: RuleSetRule | RuleSetUseItem, index: number, array: RuleSetRule[] | RuleSetUseItem[]) => boolean;
6
+
7
+ export type WithModuleRuleMatcherInfo = {
8
+ info: {
9
+ type: string;
10
+ value: string;
11
+ };
12
+ } & ModuleRuleMatcher;
13
+
14
+ function isNameMatchingLoader(loader: string, name: string) {
15
+ return loader === name || loader.indexOf(`${path.sep}${name}${path.sep}`) !== -1 || loader.indexOf(`@${name}${path.sep}`) !== -1;
16
+ }
17
+
18
+ export function matchLoaderName(name: string): ModuleRuleMatcher {
19
+ const matcher: WithModuleRuleMatcherInfo = moduleRule => {
20
+ if (typeof moduleRule === "string") {
21
+ return isNameMatchingLoader(moduleRule, name);
22
+ } else {
23
+ if ("loader" in moduleRule && moduleRule.loader) {
24
+ return isNameMatchingLoader(moduleRule.loader, name);
25
+ }
26
+ }
27
+
28
+ return false;
29
+ };
30
+
31
+ // Add contextual information about the matcher for debugging.
32
+ matcher.info = {
33
+ type: matchLoaderName.name,
34
+ value: name
35
+ };
36
+
37
+ return matcher;
38
+ }
39
+
40
+ export type AssetModuleType =
41
+ | "javascript/auto"
42
+ | "javascript/dynamic"
43
+ | "javascript/esm"
44
+ | "json"
45
+ | "webassembly/sync"
46
+ | "webassembly/async"
47
+ | "asset"
48
+ | "asset/source"
49
+ | "asset/resource"
50
+ | "asset/inline";
51
+
52
+ export function matchAssetModuleType(type: AssetModuleType): ModuleRuleMatcher {
53
+ const matcher: WithModuleRuleMatcherInfo = moduleRule => {
54
+ if (typeof moduleRule !== "string" && "type" in moduleRule) {
55
+ return moduleRule.type === type;
56
+ }
57
+
58
+ return false;
59
+ };
60
+
61
+ // Add contextual information about the matcher for debugging.
62
+ matcher.info = {
63
+ type: matchAssetModuleType.name,
64
+ value: type
65
+ };
66
+
67
+ return matcher;
68
+ }
69
+
70
+ export function matchTest(test: string | RegExp): ModuleRuleMatcher {
71
+ const matcher: WithModuleRuleMatcherInfo = moduleRule => {
72
+ if (typeof moduleRule !== "string" && "test" in moduleRule) {
73
+ if (typeof moduleRule.test === "object" && typeof test === "object") {
74
+ // Assuming it's regular expressions.
75
+ return moduleRule.test.toString() === test.toString();
76
+ }
77
+
78
+ return moduleRule.test === test;
79
+ }
80
+
81
+ return false;
82
+ };
83
+
84
+ // Add contextual information about the matcher for debugging.
85
+ matcher.info = {
86
+ type: matchTest.name,
87
+ value: test.toString()
88
+ };
89
+
90
+ return matcher;
91
+ }
92
+
93
+ export interface ModuleRuleMatch {
94
+ moduleRule: RuleSetRule | RuleSetUseItem;
95
+ index: number;
96
+ parent: RuleSetRule[] | RuleSetUseItem[];
97
+ }
98
+
99
+ function toMatch(moduleRule: RuleSetRule | RuleSetUseItem, index: number, parent: RuleSetRule[] | RuleSetUseItem[]) {
100
+ return {
101
+ moduleRule,
102
+ index,
103
+ parent
104
+ };
105
+ }
106
+
107
+ function isRuleSetRule(value: RuleSetRule | RuleSetUseItem): value is RuleSetRule {
108
+ return (value as RuleSetRule).use !== undefined || (value as RuleSetRule).oneOf !== undefined;
109
+ }
110
+
111
+ function findModuleRulesRecursively(moduleRules: RuleSetRule[] | RuleSetUseItem[], matcher: ModuleRuleMatcher, parent: RuleSetRule[] | RuleSetUseItem[], matches: ModuleRuleMatch[]) {
112
+ moduleRules.forEach((x, index, array) => {
113
+ if (x) {
114
+ if (matcher(x, index, array)) {
115
+ matches.push(toMatch(x, index, parent));
116
+ } else {
117
+ if (isRuleSetRule(x)) {
118
+ if (x.use) {
119
+ findModuleRulesRecursively(x.use as RuleSetUseItem[], matcher, x.use as RuleSetUseItem[], matches);
120
+ } else if (x.oneOf) {
121
+ // This error seems to have been introduced by either TS 5.2. or webpack 5.88.1 (https://github.com/webpack/webpack/releases/tag/v5.88.1),
122
+ // I am not sure what changed thought.
123
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
124
+ // @ts-ignore
125
+ findModuleRulesRecursively(x.oneOf, matcher, x.oneOf, matches);
126
+ }
127
+ }
128
+ }
129
+ }
130
+ });
131
+ }
132
+
133
+ export function findModuleRule(config: WebpackConfig, matcher: ModuleRuleMatcher) {
134
+ const moduleRules = config.module?.rules;
135
+
136
+ if (!moduleRules) {
137
+ return;
138
+ }
139
+
140
+ const matches: ModuleRuleMatch[] = [];
141
+
142
+ findModuleRulesRecursively(moduleRules as RuleSetRule[], matcher, moduleRules as RuleSetRule[], matches);
143
+
144
+ if (matches.length > 1) {
145
+ const matcherInfo = (matcher as WithModuleRuleMatcherInfo).info;
146
+
147
+ throw new Error(`[webpack-configs] Found more than 1 matching module rule.\n[webpack-configs] Matcher: "${JSON.stringify(matcherInfo)}"\n[webpack-configs] Matches: "${JSON.stringify(matches.map(x => x.moduleRule))}"`);
148
+ }
149
+
150
+ return matches[0];
151
+ }
152
+
153
+ export function findModuleRules(config: WebpackConfig, matcher: ModuleRuleMatcher) {
154
+ const moduleRules = config.module?.rules;
155
+
156
+ if (!moduleRules) {
157
+ return;
158
+ }
159
+
160
+ const matches: ModuleRuleMatch[] = [];
161
+
162
+ findModuleRulesRecursively(moduleRules as RuleSetRule[], matcher, moduleRules as RuleSetRule[], matches);
163
+
164
+ return matches;
165
+ }
166
+
167
+ export function addBeforeModuleRule(config: WebpackConfig, matcher: ModuleRuleMatcher, newModuleRules: RuleSetRule[] | RuleSetUseItem[]) {
168
+ const match = findModuleRule(config, matcher);
169
+
170
+ if (match) {
171
+ match.parent.splice(match.index, 0, ...newModuleRules);
172
+ } else {
173
+ const matcherInfo = (matcher as WithModuleRuleMatcherInfo).info;
174
+
175
+ throw new Error(`[webpack-configs] Couldn't add the new module rules because no match has been found.\n[webpack-configs] Matcher: "${JSON.stringify(matcherInfo)}"`);
176
+ }
177
+ }
178
+
179
+ export function addAfterModuleRule(config: WebpackConfig, matcher: ModuleRuleMatcher, newModuleRules: RuleSetRule[] | RuleSetUseItem[]) {
180
+ const match = findModuleRule(config, matcher);
181
+
182
+ if (match) {
183
+ match.parent.splice(match.index + 1, 0, ...newModuleRules);
184
+ } else {
185
+ const matcherInfo = (matcher as WithModuleRuleMatcherInfo).info;
186
+
187
+ throw new Error(`[webpack-configs] Couldn't add the new module rules because no match has been found.\n[webpack-configs] Matcher: "${JSON.stringify(matcherInfo)}"`);
188
+ }
189
+ }
190
+
191
+ export function replaceModuleRule(config: WebpackConfig, matcher: ModuleRuleMatcher, newModuleRule: RuleSetRule | RuleSetUseItem) {
192
+ const match = findModuleRule(config, matcher);
193
+
194
+ if (match) {
195
+ match.parent[match.index] = newModuleRule;
196
+ } else {
197
+ const matcherInfo = (matcher as WithModuleRuleMatcherInfo).info;
198
+
199
+ throw new Error(`[webpack-configs] Couldn't replace the module rule because no match has been found.\n[webpack-configs] Matcher: "${JSON.stringify(matcherInfo)}"`);
200
+ }
201
+ }
202
+
203
+ export function removeModuleRules(config: WebpackConfig, matcher: ModuleRuleMatcher) {
204
+ const moduleRules = config.module?.rules;
205
+
206
+ if (!moduleRules) {
207
+ return;
208
+ }
209
+
210
+ const matches: ModuleRuleMatch[] = [];
211
+
212
+ findModuleRulesRecursively(moduleRules as RuleSetRule[], matcher, moduleRules as RuleSetRule[], matches);
213
+
214
+ if (matches.length > 0) {
215
+ // Must keep the initial parent arrays' length to calculate the adjustment
216
+ // once the first match has been deleted.
217
+ const initialParentLengths = new Map<RuleSetRule[] | RuleSetUseItem[], number>(matches.map(x => [x.parent, x.parent.length]));
218
+
219
+ matches.forEach(x => {
220
+ const positionAdjustment = initialParentLengths.get(x.parent)! - x.parent.length;
221
+
222
+ x.parent.splice(x.index - positionAdjustment, 1);
223
+ });
224
+ } else {
225
+ const matcherInfo = (matcher as WithModuleRuleMatcherInfo).info;
226
+
227
+ throw new Error(`[webpack-configs] Didn't remove any module rules because no match has been found.\n[webpack-configs] Matcher: "${matcherInfo}"`);
228
+ }
229
+ }
@@ -0,0 +1,102 @@
1
+ import type { WebpackConfig } from "../types.ts";
2
+
3
+ export type WebpackPlugin = NonNullable<WebpackConfig["plugins"]>[number];
4
+
5
+ export type PluginMatcher = (plugin: WebpackPlugin, index: number, array: WebpackPlugin[]) => boolean;
6
+
7
+ export type WithPluginMatcherInfo = {
8
+ info: {
9
+ type: string;
10
+ value: string;
11
+ };
12
+ } & PluginMatcher;
13
+
14
+ export function matchConstructorName(name: string): PluginMatcher {
15
+ const matcher: WithPluginMatcherInfo = plugin => {
16
+ return plugin?.constructor.name === name;
17
+ };
18
+
19
+ // Add contextual information about the matcher for debugging.
20
+ matcher.info = {
21
+ type: matchConstructorName.name,
22
+ value: name
23
+ };
24
+
25
+ return matcher;
26
+ }
27
+
28
+ export interface PluginMatch {
29
+ plugin: WebpackPlugin;
30
+ index: number;
31
+ }
32
+
33
+ export function findPlugin(config: WebpackConfig, matcher: PluginMatcher) {
34
+ const matches: PluginMatch[] = [];
35
+
36
+ config.plugins?.forEach((x, index, array) => {
37
+ if (matcher(x, index, array)) {
38
+ matches.push({
39
+ plugin: x,
40
+ index
41
+ });
42
+ }
43
+ });
44
+
45
+ if (matches.length > 1) {
46
+ const matcherInfo = (matcher as WithPluginMatcherInfo).info;
47
+
48
+ throw new Error(`[webpack-configs] Found more than 1 matching plugin.\n[webp-configs] Matcher: "${JSON.stringify(matcherInfo)}"\n[webpack-configs] Matches: "${JSON.stringify(matches.map(x => x.plugin))}"`);
49
+ }
50
+
51
+ return matches[0];
52
+ }
53
+
54
+ export function replacePlugin(config: WebpackConfig, matcher: PluginMatcher, newPlugin: WebpackPlugin) {
55
+ const match = findPlugin(config, matcher);
56
+
57
+ if (match) {
58
+ config.plugins![match.index] = newPlugin;
59
+ } else {
60
+ const matcherInfo = (matcher as WithPluginMatcherInfo).info;
61
+
62
+ throw new Error(`[webpack-configs] Couldn't replace the plugin because no match has been found.\n[webpack-configs] Matcher: "${JSON.stringify(matcherInfo)}"`);
63
+ }
64
+ }
65
+
66
+ export function addBeforePlugin(config: WebpackConfig, matcher: PluginMatcher, newPlugins: WebpackPlugin[]) {
67
+ const match = findPlugin(config, matcher);
68
+
69
+ if (match) {
70
+ config.plugins?.splice(match.index, 0, ...newPlugins);
71
+ } else {
72
+ const matcherInfo = (matcher as WithPluginMatcherInfo).info;
73
+
74
+ throw new Error(`[webpack-configs] Couldn't add the new plugins because no match has been found.\n[webpack-configs] Matcher: "${JSON.stringify(matcherInfo)}"`);
75
+ }
76
+ }
77
+
78
+ export function addAfterPlugin(config: WebpackConfig, matcher: PluginMatcher, newPlugins: WebpackPlugin[]) {
79
+ const match = findPlugin(config, matcher);
80
+
81
+ if (match) {
82
+ config.plugins?.splice(match.index + 1, 0, ...newPlugins);
83
+ } else {
84
+ const matcherInfo = (matcher as WithPluginMatcherInfo).info;
85
+
86
+ throw new Error(`[webpack-configs] Couldn't add the new plugins because no match has been found.\n[webpack-configs] Matcher: "${JSON.stringify(matcherInfo)}"`);
87
+ }
88
+ }
89
+
90
+ export function removePlugin(config: WebpackConfig, matcher: PluginMatcher) {
91
+ const countBefore = config.plugins?.length ?? 0;
92
+
93
+ config.plugins = config.plugins?.filter((...args) => !matcher(...args));
94
+
95
+ const countAfter = config.plugins?.length ?? 0;
96
+
97
+ if (countBefore === countAfter) {
98
+ const matcherInfo = (matcher as WithPluginMatcherInfo).info;
99
+
100
+ throw new Error(`[webpack-configs] Didn't remove any plugin because no match has been found.\n[webpack-configs] Matcher: "${JSON.stringify(matcherInfo)}"`);
101
+ }
102
+ }
package/src/types.ts ADDED
@@ -0,0 +1 @@
1
+ export type { Configuration as WebpackConfig } from "webpack";
package/src/utils.ts ADDED
@@ -0,0 +1,19 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ export function isObject(value: any): value is Record<string, unknown> {
3
+ return typeof value === "object" && !Array.isArray(value) && value != null;
4
+ }
5
+
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ export function isNull(value: any): value is null {
8
+ return value == null;
9
+ }
10
+
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ export function isUndefined(value: any): value is undefined {
13
+ return typeof value === "undefined" || value === undefined;
14
+ }
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ export function isNil(value: any): value is null | undefined {
18
+ return isNull(value) || isUndefined(value);
19
+ }
@@ -1,15 +0,0 @@
1
- // src/utils.ts
2
- function isObject(value) {
3
- return typeof value === "object" && !Array.isArray(value) && value != null;
4
- }
5
- function isNull(value) {
6
- return value == null;
7
- }
8
- function isUndefined(value) {
9
- return typeof value === "undefined" || value === void 0;
10
- }
11
- function isNil(value) {
12
- return isNull(value) || isUndefined(value);
13
- }
14
-
15
- export { isNil, isNull, isObject, isUndefined };