diff --git a/docs/generated/packages/rspack/executors/rspack.json b/docs/generated/packages/rspack/executors/rspack.json index 3a8bc36d6d..21d9dec4ae 100644 --- a/docs/generated/packages/rspack/executors/rspack.json +++ b/docs/generated/packages/rspack/executors/rspack.json @@ -151,6 +151,203 @@ "generatePackageJson": { "type": "boolean", "description": "Generates a `package.json` and pruned lock file with the project's `node_module` dependencies populated for installing in a container. If a `package.json` exists in the project's directory, it will be reused with dependencies populated." + }, + "additionalEntryPoints": { + "type": "array", + "items": { + "type": "object", + "properties": { + "entryName": { + "type": "string", + "description": "Name of the additional entry file." + }, + "entryPath": { + "type": "string", + "description": "Path to the additional entry file.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.js|.ts)" + } + } + } + }, + "buildLibsFromSource": { + "type": "boolean", + "description": "Read buildable libraries from source instead of building them separately. If set to `false`, the `tsConfig` option must also be set to remap paths.", + "default": true + }, + "extractCss": { + "type": "boolean", + "description": "Extract CSS into a `.css` file." + }, + "externalDependencies": { + "oneOf": [ + { "type": "string", "enum": ["none", "all"] }, + { "type": "array", "items": { "type": "string" } } + ], + "description": "Dependencies to keep external to the bundle. (`all` (default), `none`, or an array of module names)" + }, + "generateIndexHtml": { + "type": "boolean", + "description": "Generates `index.html` file to the output path. This can be turned off if using a webpack plugin to generate HTML such as `html-webpack-plugin`." + }, + "memoryLimit": { + "type": "number", + "description": "Memory limit for type checking service process in `MB`." + }, + "namedChunks": { + "type": "boolean", + "description": "Names the produced bundles according to their entry file." + }, + "outputHashing": { + "type": "string", + "description": "Define the output filename cache-busting hashing mode.", + "enum": ["none", "all", "media", "bundles"] + }, + "poll": { + "type": "number", + "description": "Enable and define the file watching poll time period." + }, + "polyfills": { + "type": "string", + "description": "Polyfills to load before application", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.js|.ts|.tsx)" + }, + "postcssConfig": { + "type": "string", + "description": "Set a path to PostCSS config that applies to the app and all libs. Defaults to `undefined`, which auto-detects postcss.config.js files in each `app`/`lib` directory." + }, + "progress": { + "type": "boolean", + "description": "Log progress to the console while building." + }, + "publicPath": { + "type": "string", + "description": "Set a public path for assets resources with absolute paths." + }, + "rebaseRootRelative": { + "type": "boolean", + "description": "Whether to rebase absolute path for assets in postcss cli resources." + }, + "runtimeChunk": { + "type": "boolean", + "description": "Use a separate bundle containing the runtime." + }, + "scripts": { + "type": "array", + "description": "External Scripts which will be included before the main application entry.", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "The file to include.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)" + }, + "bundleName": { + "type": "string", + "description": "The bundle name for this extra entry point." + }, + "inject": { + "type": "boolean", + "description": "If the bundle will be referenced in the HTML file.", + "default": true + } + }, + "additionalProperties": false, + "required": ["input"] + }, + { + "type": "string", + "description": "The file to include.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)" + } + ] + } + }, + "standardRspackConfigFunction": { + "type": "boolean", + "description": "Set to true if the rspack config exports a standard rspack function, not an Nx-specific one. See: https://rspack.dev/config/", + "default": false + }, + "statsJson": { + "type": "boolean", + "description": "Generates a 'stats.json' file which can be analyzed using tools such as: 'webpack-bundle-analyzer' See: https://rspack.dev/guide/optimization/analysis" + }, + "stylePreprocessorOptions": { + "description": "Options to pass to style preprocessors.", + "type": "object", + "properties": { + "includePaths": { + "description": "Paths to include. Paths will be resolved to project root.", + "type": "array", + "items": { "type": "string" } + } + }, + "additionalProperties": false + }, + "styles": { + "type": "array", + "description": "External Styles which will be included with the application", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "The file to include.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)" + }, + "bundleName": { + "type": "string", + "description": "The bundle name for this extra entry point." + }, + "inject": { + "type": "boolean", + "description": "If the bundle will be referenced in the HTML file.", + "default": true + } + }, + "additionalProperties": false, + "required": ["input"] + }, + { + "type": "string", + "description": "The file to include.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)" + } + ] + } + }, + "transformers": { + "type": "array", + "description": "List of TypeScript Compiler Transfomers Plugins.", + "aliases": ["tsPlugins"], + "items": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "properties": { + "name": { "type": "string" }, + "options": { "type": "object", "additionalProperties": true } + }, + "additionalProperties": false, + "required": ["name"] + } + ] + } + }, + "vendorChunk": { + "type": "boolean", + "description": "Use a separate bundle containing only vendor libraries." } }, "required": ["rspackConfig"], @@ -188,6 +385,52 @@ }, { "type": "string" } ] + }, + "extraEntryPoint": { + "oneOf": [ + { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "The file to include.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)" + }, + "bundleName": { + "type": "string", + "description": "The bundle name for this extra entry point." + }, + "inject": { + "type": "boolean", + "description": "If the bundle will be referenced in the HTML file.", + "default": true + } + }, + "additionalProperties": false, + "required": ["input"] + }, + { + "type": "string", + "description": "The file to include.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)" + } + ] + }, + "transformerPattern": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "properties": { + "name": { "type": "string" }, + "options": { "type": "object", "additionalProperties": true } + }, + "additionalProperties": false, + "required": ["name"] + } + ] } }, "presets": [] diff --git a/docs/generated/packages/webpack/executors/webpack.json b/docs/generated/packages/webpack/executors/webpack.json index c78900b81f..238f02803e 100644 --- a/docs/generated/packages/webpack/executors/webpack.json +++ b/docs/generated/packages/webpack/executors/webpack.json @@ -73,6 +73,11 @@ "type": "boolean", "description": "Use a separate bundle containing the runtime." }, + "skipTypeChecking": { + "alias": "typeCheck", + "type": "boolean", + "description": "Skip the type checking. Default is `false`." + }, "sourceMap": { "description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.", "oneOf": [{ "type": "boolean" }, { "type": "string" }] @@ -81,6 +86,10 @@ "type": "boolean", "description": "Log progress to the console while building." }, + "poll": { + "type": "number", + "description": "Enable and define the file watching poll time period." + }, "assets": { "type": "array", "description": "List of static application assets.", diff --git a/packages/rspack/src/executors/rspack/lib/config.ts b/packages/rspack/src/executors/rspack/lib/config.ts new file mode 100644 index 0000000000..8e5f3154c2 --- /dev/null +++ b/packages/rspack/src/executors/rspack/lib/config.ts @@ -0,0 +1,55 @@ +import { join } from 'path'; +import { ExecutorContext } from '@nx/devkit'; +import { type Configuration } from '@rspack/core'; +import { + composePluginsSync, + isNxRspackComposablePlugin, +} from '../../../utils/config'; +import { resolveUserDefinedRspackConfig } from '../../../utils/resolve-user-defined-rspack-config'; +import { withNx } from '../../../utils/with-nx'; +import { withWeb } from '../../../utils/with-web'; +import { type NormalizedRspackExecutorSchema } from '../schema'; + +export async function getRspackConfigs( + options: NormalizedRspackExecutorSchema & { devServer?: any }, + context: ExecutorContext +): Promise { + let userDefinedConfig = resolveUserDefinedRspackConfig( + options.rspackConfig, + options.tsConfig + ); + + if (typeof userDefinedConfig.then === 'function') { + userDefinedConfig = await userDefinedConfig; + } + + const config = ( + options.target === 'web' + ? composePluginsSync(withNx(options), withWeb(options)) + : withNx(options) + )({}, { options, context }); + + if ( + (typeof userDefinedConfig === 'function' && + isNxRspackComposablePlugin(userDefinedConfig)) || + !options.standardRspackConfigFunction + ) { + // Old behavior, call the Nx-specific rspack config function that user exports + return await userDefinedConfig(config, { + options, + context, + configuration: context.configurationName, + }); + } else if (userDefinedConfig) { + if (typeof userDefinedConfig === 'function') { + // assume it's an async standard rspack config function which operates similar to webpack + // https://webpack.js.org/configuration/configuration-types/#exporting-a-promise + return await userDefinedConfig(process.env.NODE_ENV, {}); + } + // New behavior, we want the rspack config to export object + return userDefinedConfig; + } else { + // Fallback case, if we cannot find a rspack config path + return config; + } +} diff --git a/packages/rspack/src/executors/rspack/rspack.impl.ts b/packages/rspack/src/executors/rspack/rspack.impl.ts index b25211cea6..b42001f319 100644 --- a/packages/rspack/src/executors/rspack/rspack.impl.ts +++ b/packages/rspack/src/executors/rspack/rspack.impl.ts @@ -3,11 +3,11 @@ import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable'; import { printDiagnostics, runTypeCheck } from '@nx/js'; import { Compiler, MultiCompiler, MultiStats, Stats } from '@rspack/core'; import { rmSync } from 'fs'; -import * as path from 'path'; import { createCompiler, isMultiCompiler } from '../../utils/create-compiler'; import { isMode } from '../../utils/mode-utils'; import { RspackExecutorSchema } from './schema'; import { normalizeOptions } from './lib/normalize-options'; +import { join, resolve } from 'path'; export default async function* runExecutor( options: RspackExecutorSchema, @@ -16,21 +16,9 @@ export default async function* runExecutor( process.env.NODE_ENV ??= options.mode ?? 'production'; options.target ??= 'web'; - if (isMode(process.env.NODE_ENV)) { - options.mode = process.env.NODE_ENV; - } - - if (options.typeCheck) { - await executeTypeCheck(options, context); - } - - // Mimic --clean from webpack. - rmSync(path.join(context.root, options.outputPath), { - force: true, - recursive: true, - }); const metadata = context.projectsConfigurations.projects[context.projectName]; const sourceRoot = metadata.sourceRoot; + const normalizedOptions = normalizeOptions( options, context.root, @@ -38,6 +26,20 @@ export default async function* runExecutor( sourceRoot ); + if (isMode(process.env.NODE_ENV)) { + normalizedOptions.mode = process.env.NODE_ENV; + } + + if (normalizedOptions.typeCheck) { + await executeTypeCheck(normalizedOptions, context); + } + + // Mimic --clean from webpack. + rmSync(join(context.root, normalizedOptions.outputPath), { + force: true, + recursive: true, + }); + const compiler = await createCompiler(normalizedOptions, context); const iterable = createAsyncIterable<{ @@ -67,7 +69,7 @@ export default async function* runExecutor( } next({ success: !stats.hasErrors(), - outfile: path.resolve( + outfile: resolve( context.root, normalizedOptions.outputPath, 'main.js' @@ -103,7 +105,7 @@ export default async function* runExecutor( } next({ success: !stats.hasErrors(), - outfile: path.resolve( + outfile: resolve( context.root, normalizedOptions.outputPath, 'main.js' @@ -139,7 +141,7 @@ async function executeTypeCheck( const projectConfiguration = context.projectGraph.nodes[context.projectName].data; const result = await runTypeCheck({ - workspaceRoot: path.resolve(projectConfiguration.root), + workspaceRoot: resolve(projectConfiguration.root), tsConfigPath: options.tsConfig, mode: 'noEmit', }); diff --git a/packages/rspack/src/executors/rspack/schema.d.ts b/packages/rspack/src/executors/rspack/schema.d.ts index f1362a3d98..dfbff63a98 100644 --- a/packages/rspack/src/executors/rspack/schema.d.ts +++ b/packages/rspack/src/executors/rspack/schema.d.ts @@ -1,28 +1,49 @@ import type { Mode } from '@rspack/core'; export interface RspackExecutorSchema { - target?: 'web' | 'node'; - main?: string; - index?: string; - tsConfig?: string; - typeCheck?: boolean; - skipTypeChecking?: boolean; - outputPath?: string; - outputFileName?: string; + additionalEntryPoints?: AdditionalEntryPoint[]; + assets?: Array; + baseHref?: string; + buildLibsFromSource?: boolean; + deployUrl?: string; + extractCss?: boolean; + extractLicenses?: boolean; + externalDependencies?: 'all' | 'none' | string[]; + fileReplacements?: FileReplacement[]; + generateIndexHtml?: boolean; + generatePackageJson?: boolean; index?: string; indexHtml?: string; + main?: string; + memoryLimit?: number; mode?: Mode; - watch?: boolean; - baseHref?: string; - deployUrl?: string; - - rspackConfig: string; + namedChunks?: boolean; optimization?: boolean | OptimizationOptions; + outputFileName?: string; + outputHashing?: any; + outputPath?: string; + poll?: number; + polyfills?: string; + postcssConfig?: string; + progress?: boolean; + publicPath?: string; + rebaseRootRelative?: boolean; + rspackConfig: string; + runtimeChunk?: boolean; + scripts?: Array; + skipTypeChecking?: boolean; sourceMap?: boolean | string; - assets?: any[]; - extractLicenses?: boolean; - fileReplacements?: FileReplacement[]; - generatePackageJson?: boolean; + standardRspackConfigFunction?: boolean; + statsJson?: boolean; + stylePreprocessorOptions?: any; + styles?: Array; + target?: 'web' | 'node'; + transformers?: TransformerEntry[]; + tsConfig?: string; + typeCheck?: boolean; + verbose?: boolean; + vendorChunk?: boolean; + watch?: boolean; } export interface AssetGlobPattern { diff --git a/packages/rspack/src/executors/rspack/schema.json b/packages/rspack/src/executors/rspack/schema.json index 9d2410269b..8a2ccb1ab5 100644 --- a/packages/rspack/src/executors/rspack/schema.json +++ b/packages/rspack/src/executors/rspack/schema.json @@ -129,6 +129,144 @@ "generatePackageJson": { "type": "boolean", "description": "Generates a `package.json` and pruned lock file with the project's `node_module` dependencies populated for installing in a container. If a `package.json` exists in the project's directory, it will be reused with dependencies populated." + }, + "additionalEntryPoints": { + "type": "array", + "items": { + "type": "object", + "properties": { + "entryName": { + "type": "string", + "description": "Name of the additional entry file." + }, + "entryPath": { + "type": "string", + "description": "Path to the additional entry file.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.js|.ts)" + } + } + } + }, + "buildLibsFromSource": { + "type": "boolean", + "description": "Read buildable libraries from source instead of building them separately. If set to `false`, the `tsConfig` option must also be set to remap paths.", + "default": true + }, + "extractCss": { + "type": "boolean", + "description": "Extract CSS into a `.css` file." + }, + "externalDependencies": { + "oneOf": [ + { + "type": "string", + "enum": ["none", "all"] + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Dependencies to keep external to the bundle. (`all` (default), `none`, or an array of module names)" + }, + "generateIndexHtml": { + "type": "boolean", + "description": "Generates `index.html` file to the output path. This can be turned off if using a webpack plugin to generate HTML such as `html-webpack-plugin`." + }, + "memoryLimit": { + "type": "number", + "description": "Memory limit for type checking service process in `MB`." + }, + "namedChunks": { + "type": "boolean", + "description": "Names the produced bundles according to their entry file." + }, + "outputHashing": { + "type": "string", + "description": "Define the output filename cache-busting hashing mode.", + "enum": ["none", "all", "media", "bundles"] + }, + "poll": { + "type": "number", + "description": "Enable and define the file watching poll time period." + }, + "polyfills": { + "type": "string", + "description": "Polyfills to load before application", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.js|.ts|.tsx)" + }, + "postcssConfig": { + "type": "string", + "description": "Set a path to PostCSS config that applies to the app and all libs. Defaults to `undefined`, which auto-detects postcss.config.js files in each `app`/`lib` directory." + }, + "progress": { + "type": "boolean", + "description": "Log progress to the console while building." + }, + "publicPath": { + "type": "string", + "description": "Set a public path for assets resources with absolute paths." + }, + "rebaseRootRelative": { + "type": "boolean", + "description": "Whether to rebase absolute path for assets in postcss cli resources." + }, + "runtimeChunk": { + "type": "boolean", + "description": "Use a separate bundle containing the runtime." + }, + "scripts": { + "type": "array", + "description": "External Scripts which will be included before the main application entry.", + "items": { + "$ref": "#/definitions/extraEntryPoint" + } + }, + "standardRspackConfigFunction": { + "type": "boolean", + "description": "Set to true if the rspack config exports a standard rspack function, not an Nx-specific one. See: https://rspack.dev/config/", + "default": false + }, + "statsJson": { + "type": "boolean", + "description": "Generates a 'stats.json' file which can be analyzed using tools such as: 'webpack-bundle-analyzer' See: https://rspack.dev/guide/optimization/analysis" + }, + "stylePreprocessorOptions": { + "description": "Options to pass to style preprocessors.", + "type": "object", + "properties": { + "includePaths": { + "description": "Paths to include. Paths will be resolved to project root.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "styles": { + "type": "array", + "description": "External Styles which will be included with the application", + "items": { + "$ref": "#/definitions/extraEntryPoint" + } + }, + "transformers": { + "type": "array", + "description": "List of TypeScript Compiler Transfomers Plugins.", + "aliases": ["tsPlugins"], + "items": { + "$ref": "#/definitions/transformerPattern" + } + }, + "vendorChunk": { + "type": "boolean", + "description": "Use a separate bundle containing only vendor libraries." } }, "required": ["rspackConfig"], @@ -170,6 +308,59 @@ "type": "string" } ] + }, + "extraEntryPoint": { + "oneOf": [ + { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "The file to include.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)" + }, + "bundleName": { + "type": "string", + "description": "The bundle name for this extra entry point." + }, + "inject": { + "type": "boolean", + "description": "If the bundle will be referenced in the HTML file.", + "default": true + } + }, + "additionalProperties": false, + "required": ["input"] + }, + { + "type": "string", + "description": "The file to include.", + "x-completion-type": "file", + "x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)" + } + ] + }, + "transformerPattern": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "options": { + "type": "object", + "additionalProperties": true + } + }, + "additionalProperties": false, + "required": ["name"] + } + ] } } } diff --git a/packages/rspack/src/plugins/utils/apply-base-config.ts b/packages/rspack/src/plugins/utils/apply-base-config.ts index 565a1422e5..6e309ccc7b 100644 --- a/packages/rspack/src/plugins/utils/apply-base-config.ts +++ b/packages/rspack/src/plugins/utils/apply-base-config.ts @@ -8,7 +8,6 @@ import { SwcJsMinimizerRspackPlugin, CopyRspackPlugin, RspackOptionsNormalized, - ExternalItem, } from '@rspack/core'; import { getRootTsConfigPath } from '@nx/js'; diff --git a/packages/rspack/src/utils/create-compiler.ts b/packages/rspack/src/utils/create-compiler.ts index 0f3a821bbe..be046c9934 100644 --- a/packages/rspack/src/utils/create-compiler.ts +++ b/packages/rspack/src/utils/create-compiler.ts @@ -5,41 +5,17 @@ import { MultiCompiler, rspack, } from '@rspack/core'; -import * as path from 'path'; -import { RspackExecutorSchema } from '../executors/rspack/schema'; -import { resolveUserDefinedRspackConfig } from './resolve-user-defined-rspack-config'; + +import { NormalizedRspackExecutorSchema } from '../executors/rspack/schema'; +import { getRspackConfigs } from '../executors/rspack/lib/config'; export async function createCompiler( - options: RspackExecutorSchema & { + options: NormalizedRspackExecutorSchema & { devServer?: any; }, context: ExecutorContext ): Promise { - const pathToConfig = options.rspackConfig; - let userDefinedConfig: any = {}; - if (options.tsConfig) { - userDefinedConfig = resolveUserDefinedRspackConfig( - pathToConfig, - options.tsConfig - ); - } else { - userDefinedConfig = await import(pathToConfig).then((x) => x.default || x); - } - - if (typeof userDefinedConfig.then === 'function') { - userDefinedConfig = await userDefinedConfig; - } - - let config: Configuration = {}; - if (typeof userDefinedConfig === 'function') { - config = await userDefinedConfig( - { devServer: options.devServer }, - { options, context } - ); - } else { - config = userDefinedConfig; - config.devServer ??= options.devServer; - } + const config = await getRspackConfigs(options, context); validateConfig(config); @@ -52,15 +28,17 @@ export function isMultiCompiler( return 'compilers' in compiler; } -function validateConfig(config: Configuration) { - if (!config.entry) { - throw new Error( - 'Entry is required. Please set the `main` option in the executor or the `entry` property in the rspack config.' - ); - } - if (!config.output) { - throw new Error( - 'Output is required. Please set the `outputPath` option in the executor or the `output` property in the rspack config.' - ); - } +function validateConfig(config: Configuration | Configuration[]) { + [config].flat().forEach((config) => { + if (!config.entry) { + throw new Error( + 'Entry is required. Please set the `main` option in the executor or the `entry` property in the rspack config.' + ); + } + if (!config.output) { + throw new Error( + 'Output is required. Please set the `outputPath` option in the executor or the `output` property in the rspack config.' + ); + } + }); } diff --git a/packages/webpack/src/executors/webpack/schema.json b/packages/webpack/src/executors/webpack/schema.json index 0beb2cc190..c7e63e86d8 100644 --- a/packages/webpack/src/executors/webpack/schema.json +++ b/packages/webpack/src/executors/webpack/schema.json @@ -70,6 +70,11 @@ "type": "boolean", "description": "Use a separate bundle containing the runtime." }, + "skipTypeChecking": { + "alias": "typeCheck", + "type": "boolean", + "description": "Skip the type checking. Default is `false`." + }, "sourceMap": { "description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.", "oneOf": [ @@ -85,6 +90,10 @@ "type": "boolean", "description": "Log progress to the console while building." }, + "poll": { + "type": "number", + "description": "Enable and define the file watching poll time period." + }, "assets": { "type": "array", "description": "List of static application assets.", diff --git a/packages/webpack/src/executors/webpack/webpack.impl.ts b/packages/webpack/src/executors/webpack/webpack.impl.ts index 270c043a28..310246b16c 100644 --- a/packages/webpack/src/executors/webpack/webpack.impl.ts +++ b/packages/webpack/src/executors/webpack/webpack.impl.ts @@ -15,10 +15,6 @@ import { tap, } from 'rxjs/operators'; import { resolve } from 'path'; -import { - calculateProjectBuildableDependencies, - createTmpTsConfig, -} from '@nx/js/src/utils/buildable-libs-utils'; import { runWebpack } from './lib/run-webpack'; import { deleteOutputDir } from '../../utils/fs'; import { resolveUserDefinedWebpackConfig } from '../../utils/webpack/resolve-user-defined-webpack-config';