| | |
| | | /** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptionsNormalized */ |
| | | /** @typedef {import("../WebpackError")} WebpackError */ |
| | | |
| | | /** |
| | | * Defines the webpack options interception type used by this module. |
| | | * @typedef {object} WebpackOptionsInterception |
| | | * @property {WebpackOptionsNormalized["devtool"]=} devtool |
| | | */ |
| | | |
| | | const handledDeprecatedNoEmitOnErrors = util.deprecate( |
| | | /** |
| | | * Handles the callback logic for this hook. |
| | | * @param {boolean} noEmitOnErrors no emit on errors |
| | | * @param {boolean | undefined} emitOnErrors emit on errors |
| | | * @returns {boolean} emit on errors |
| | |
| | | ); |
| | | |
| | | /** |
| | | * Returns result value. |
| | | * @template T |
| | | * @template R |
| | | * @param {T | undefined} value value or not |
| | |
| | | value === undefined ? fn(/** @type {T} */ ({})) : fn(value); |
| | | |
| | | /** |
| | | * Returns result value. |
| | | * @template T |
| | | * @param {T|undefined} value value or not |
| | | * @param {T | undefined} value value or not |
| | | * @returns {T} result value |
| | | */ |
| | | const cloneObject = (value) => /** @type {T} */ ({ ...value }); |
| | | /** |
| | | * Optional nested config. |
| | | * @template T |
| | | * @template R |
| | | * @param {T | undefined} value value or not |
| | |
| | | value === undefined ? undefined : fn(value); |
| | | |
| | | /** |
| | | * Returns cloned value. |
| | | * @template T |
| | | * @template R |
| | | * @param {T[] | undefined} value array or not |
| | |
| | | const nestedArray = (value, fn) => (Array.isArray(value) ? fn(value) : fn([])); |
| | | |
| | | /** |
| | | * Optional nested array. |
| | | * @template T |
| | | * @template R |
| | | * @param {T[] | undefined} value array or not |
| | |
| | | Array.isArray(value) ? fn(value) : undefined; |
| | | |
| | | /** |
| | | * Keyed nested config. |
| | | * @template T |
| | | * @template R |
| | | * @param {Record<string, T>|undefined} value value or not |
| | | * @param {Record<string, T> | undefined} value value or not |
| | | * @param {(value: T) => R} fn nested handler |
| | | * @param {Record<string, (value: T) => R>=} customKeys custom nested handler for some keys |
| | | * @returns {Record<string, R>} result value |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Gets normalized webpack options. |
| | | * @param {WebpackOptions} config input config |
| | | * @returns {WebpackOptionsNormalized} normalized options |
| | | */ |
| | |
| | | importFunctionName: output.importFunctionName, |
| | | importMetaName: output.importMetaName, |
| | | scriptType: output.scriptType, |
| | | // TODO webpack6 remove `libraryTarget`/`auxiliaryComment`/`amdContainer`/etc in favor of the `library` option |
| | | // TODO webpack 6 remove `libraryTarget`/`auxiliaryComment`/`amdContainer`/etc in favor of the `library` option |
| | | library: libraryBase && { |
| | | type: |
| | | output.libraryTarget !== undefined |
| | |
| | | return result; |
| | | }), |
| | | parallelism: config.parallelism, |
| | | validate: config.validate, |
| | | performance: optionalNestedConfig(config.performance, (performance) => { |
| | | if (performance === false) return false; |
| | | return { |
| | |
| | | }); |
| | | |
| | | /** |
| | | * Gets normalized entry static. |
| | | * @param {EntryStatic} entry static entry options |
| | | * @returns {EntryStaticNormalized} normalized static entry options |
| | | */ |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Gets normalized optimization runtime chunk. |
| | | * @param {OptimizationRuntimeChunk=} runtimeChunk runtimeChunk option |
| | | * @returns {OptimizationRuntimeChunkNormalized=} normalized runtimeChunk option |
| | | */ |
| | |
| | | }; |
| | | }; |
| | | |
| | | /** |
| | | * Apply webpack options interception. |
| | | * @param {WebpackOptionsNormalized} options options to be intercepted |
| | | * @returns {{ options: WebpackOptionsNormalized, interception?: WebpackOptionsInterception }} options and interception |
| | | */ |
| | | const applyWebpackOptionsInterception = (options) => { |
| | | // Return origin options when backCompat is disabled |
| | | if (options.experiments.futureDefaults) { |
| | | return { |
| | | options |
| | | }; |
| | | } |
| | | |
| | | // TODO webpack 6 - remove compatibility logic and move `devtools` fully into `devtool` with multi-type support |
| | | let _devtool = options.devtool; |
| | | /** @type {WebpackOptionsNormalized["devtool"]} */ |
| | | let cached; |
| | | |
| | | const devtoolBackCompat = () => { |
| | | if (Array.isArray(_devtool)) { |
| | | if (cached) return cached; |
| | | // Prefer `all`, then `javascript`, then `css` |
| | | const match = ["all", "javascript", "css"] |
| | | .map((type) => |
| | | /** @type {Extract<WebpackOptionsNormalized["devtool"], EXPECTED_ANY[]>} */ ( |
| | | _devtool |
| | | ).find((item) => item.type === type) |
| | | ) |
| | | .find(Boolean); |
| | | |
| | | // If `devtool: []` is specified, return `false` here |
| | | return (cached = match ? match.use : false); |
| | | } |
| | | return _devtool; |
| | | }; |
| | | |
| | | /** @type {ProxyHandler<WebpackOptionsNormalized>} */ |
| | | const handler = Object.create(null); |
| | | handler.get = (target, prop, receiver) => { |
| | | if (prop === "devtool") { |
| | | return devtoolBackCompat(); |
| | | } |
| | | return Reflect.get(target, prop, receiver); |
| | | }; |
| | | handler.set = (target, prop, value, receiver) => { |
| | | if (prop === "devtool") { |
| | | _devtool = value; |
| | | cached = undefined; |
| | | return true; |
| | | } |
| | | return Reflect.set(target, prop, value, receiver); |
| | | }; |
| | | handler.deleteProperty = (target, prop) => { |
| | | if (prop === "devtool") { |
| | | _devtool = undefined; |
| | | cached = undefined; |
| | | return true; |
| | | } |
| | | return Reflect.deleteProperty(target, prop); |
| | | }; |
| | | handler.defineProperty = (target, prop, descriptor) => { |
| | | if (prop === "devtool") { |
| | | _devtool = descriptor.value; |
| | | cached = undefined; |
| | | return true; |
| | | } |
| | | return Reflect.defineProperty(target, prop, descriptor); |
| | | }; |
| | | handler.getOwnPropertyDescriptor = (target, prop) => { |
| | | if (prop === "devtool") { |
| | | return { |
| | | configurable: true, |
| | | enumerable: true, |
| | | value: devtoolBackCompat(), |
| | | writable: true |
| | | }; |
| | | } |
| | | return Reflect.getOwnPropertyDescriptor(target, prop); |
| | | }; |
| | | |
| | | return { |
| | | options: new Proxy(options, handler), |
| | | interception: { |
| | | get devtool() { |
| | | return _devtool; |
| | | } |
| | | } |
| | | }; |
| | | }; |
| | | |
| | | module.exports.applyWebpackOptionsInterception = |
| | | applyWebpackOptionsInterception; |
| | | module.exports.getNormalizedWebpackOptions = getNormalizedWebpackOptions; |