| | |
| | | const Generator = require("../Generator"); |
| | | const { |
| | | ASSET_AND_CSS_URL_TYPES, |
| | | ASSET_AND_JS_AND_CSS_URL_TYPES, |
| | | ASSET_AND_JS_TYPES, |
| | | ASSET_AND_JAVASCRIPT_AND_CSS_URL_TYPES, |
| | | ASSET_AND_JAVASCRIPT_TYPES, |
| | | ASSET_TYPES, |
| | | CSS_TYPE, |
| | | CSS_URL_TYPE, |
| | | CSS_URL_TYPES, |
| | | JS_AND_CSS_URL_TYPES, |
| | | JS_TYPES, |
| | | JAVASCRIPT_AND_CSS_URL_TYPES, |
| | | JAVASCRIPT_TYPE, |
| | | JAVASCRIPT_TYPES, |
| | | NO_TYPES |
| | | } = require("../ModuleSourceTypesConstants"); |
| | | } = require("../ModuleSourceTypeConstants"); |
| | | const { ASSET_MODULE_TYPE } = require("../ModuleTypeConstants"); |
| | | const RuntimeGlobals = require("../RuntimeGlobals"); |
| | | const CssUrlDependency = require("../dependencies/CssUrlDependency"); |
| | |
| | | const memoize = require("../util/memoize"); |
| | | const nonNumericOnlyHash = require("../util/nonNumericOnlyHash"); |
| | | |
| | | const getMimeTypes = memoize(() => require("mime-types")); |
| | | const getMimeTypes = memoize(() => require("../util/mimeTypes")); |
| | | |
| | | /** @typedef {import("webpack-sources").Source} Source */ |
| | | /** @typedef {import("../../declarations/WebpackOptions").AssetGeneratorDataUrlOptions} AssetGeneratorDataUrlOptions */ |
| | |
| | | /** @typedef {import("../Compilation").AssetInfo} AssetInfo */ |
| | | /** @typedef {import("../Generator").GenerateContext} GenerateContext */ |
| | | /** @typedef {import("../Generator").UpdateHashContext} UpdateHashContext */ |
| | | /** @typedef {import("../Module")} Module */ |
| | | /** @typedef {import("../Module").NameForCondition} NameForCondition */ |
| | | /** @typedef {import("../Module").BuildInfo} BuildInfo */ |
| | | /** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */ |
| | | /** @typedef {import("../Module").SourceType} SourceType */ |
| | | /** @typedef {import("../Module").SourceTypes} SourceTypes */ |
| | | /** @typedef {import("../ModuleGraph")} ModuleGraph */ |
| | | /** @typedef {import("../NormalModule")} NormalModule */ |
| | |
| | | /** @typedef {import("../util/Hash")} Hash */ |
| | | /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */ |
| | | |
| | | /** @typedef {(source: string | Buffer, context: { filename: string, module: Module }) => string} DataUrlFunction */ |
| | | |
| | | /** |
| | | * Merges maybe arrays. |
| | | * @template T |
| | | * @template U |
| | | * @param {null | string | T[] | Set<T> | undefined} a a |
| | |
| | | * @returns {T[] & U[]} array |
| | | */ |
| | | const mergeMaybeArrays = (a, b) => { |
| | | /** @type {Set<T | U | null | undefined | string | Set<T> | Set<U>>} */ |
| | | const set = new Set(); |
| | | if (Array.isArray(a)) for (const item of a) set.add(item); |
| | | else set.add(a); |
| | | if (Array.isArray(b)) for (const item of b) set.add(item); |
| | | else set.add(b); |
| | | return [...set]; |
| | | return /** @type {T[] & U[]} */ ([.../** @type {Set<T | U>} */ (set)]); |
| | | }; |
| | | |
| | | /** |
| | | * Merges the provided values into a single result. |
| | | * @param {AssetInfo} a a |
| | | * @param {AssetInfo} b b |
| | | * @returns {AssetInfo} object |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Merges related info. |
| | | * @param {NonNullable<AssetInfo["related"]>} a a |
| | | * @param {NonNullable<AssetInfo["related"]>} b b |
| | | * @returns {NonNullable<AssetInfo["related"]>} object |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Encodes the provided encoding. |
| | | * @param {"base64" | false} encoding encoding |
| | | * @param {Source} source source |
| | | * @returns {string} encoded data |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Decodes data uri content. |
| | | * @param {"base64" | false} encoding encoding |
| | | * @param {string} content content |
| | | * @returns {Buffer} decoded content |
| | |
| | | |
| | | class AssetGenerator extends Generator { |
| | | /** |
| | | * Creates an instance of AssetGenerator. |
| | | * @param {ModuleGraph} moduleGraph the module graph |
| | | * @param {AssetGeneratorOptions["dataUrl"]=} dataUrlOptions the options for the data url |
| | | * @param {AssetModuleFilename=} filename override for output.assetModuleFilename |
| | |
| | | emit |
| | | ) { |
| | | super(); |
| | | /** @type {AssetGeneratorOptions["dataUrl"] | undefined} */ |
| | | this.dataUrlOptions = dataUrlOptions; |
| | | /** @type {AssetModuleFilename | undefined} */ |
| | | this.filename = filename; |
| | | /** @type {RawPublicPath | undefined} */ |
| | | this.publicPath = publicPath; |
| | | /** @type {AssetModuleOutputPath | undefined} */ |
| | | this.outputPath = outputPath; |
| | | /** @type {boolean | undefined} */ |
| | | this.emit = emit; |
| | | /** @type {ModuleGraph} */ |
| | | this._moduleGraph = moduleGraph; |
| | | } |
| | | |
| | | /** |
| | | * Gets source file name. |
| | | * @param {NormalModule} module module |
| | | * @param {RuntimeTemplate} runtimeTemplate runtime template |
| | | * @returns {string} source file name |
| | |
| | | } |
| | | |
| | | /** |
| | | * Gets full content hash. |
| | | * @param {NormalModule} module module |
| | | * @param {RuntimeTemplate} runtimeTemplate runtime template |
| | | * @returns {[string, string]} return full hash and non-numeric full hash |
| | |
| | | } |
| | | |
| | | /** |
| | | * Gets filename with info. |
| | | * @param {NormalModule} module module for which the code should be generated |
| | | * @param {Pick<AssetResourceGeneratorOptions, "filename" | "outputPath">} generatorOptions generator options |
| | | * @param {{ runtime: RuntimeSpec, runtimeTemplate: RuntimeTemplate, chunkGraph: ChunkGraph }} generateContext context for generate |
| | |
| | | } |
| | | |
| | | /** |
| | | * Gets asset path with info. |
| | | * @param {NormalModule} module module for which the code should be generated |
| | | * @param {Pick<AssetResourceGeneratorOptions, "publicPath">} generatorOptions generator options |
| | | * @param {GenerateContext} generateContext context for generate |
| | |
| | | runtimeTemplate |
| | | ); |
| | | |
| | | /** @type {undefined | string} */ |
| | | let assetPath; |
| | | |
| | | if (generatorOptions.publicPath !== undefined && type === "javascript") { |
| | | if (generatorOptions.publicPath !== undefined && type === JAVASCRIPT_TYPE) { |
| | | const { path, info } = runtimeTemplate.compilation.getAssetPathWithInfo( |
| | | generatorOptions.publicPath, |
| | | { |
| | |
| | | assetPath = JSON.stringify(path + filename); |
| | | } else if ( |
| | | generatorOptions.publicPath !== undefined && |
| | | type === "css-url" |
| | | type === CSS_URL_TYPE |
| | | ) { |
| | | const { path, info } = runtimeTemplate.compilation.getAssetPathWithInfo( |
| | | generatorOptions.publicPath, |
| | |
| | | ); |
| | | assetInfo = mergeAssetInfo(assetInfo, info); |
| | | assetPath = path + filename; |
| | | } else if (type === "javascript") { |
| | | } else if (type === JAVASCRIPT_TYPE) { |
| | | // add __webpack_require__.p |
| | | runtimeRequirements.add(RuntimeGlobals.publicPath); |
| | | assetPath = runtimeTemplate.concatenation( |
| | | { expr: RuntimeGlobals.publicPath }, |
| | | filename |
| | | ); |
| | | } else if (type === "css-url") { |
| | | } else if (type === CSS_URL_TYPE) { |
| | | const compilation = runtimeTemplate.compilation; |
| | | const path = |
| | | compilation.outputOptions.publicPath === "auto" |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the reason this module cannot be concatenated, when one exists. |
| | | * @param {NormalModule} module module for which the bailout reason should be determined |
| | | * @param {ConcatenationBailoutReasonContext} context context |
| | | * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns mime type. |
| | | * @param {NormalModule} module module |
| | | * @returns {string} mime type |
| | | */ |
| | |
| | | ); |
| | | } |
| | | |
| | | /** @type {string | boolean | undefined} */ |
| | | /** @type {string | undefined} */ |
| | | let mimeType = |
| | | /** @type {AssetGeneratorDataUrlOptions} */ |
| | | (this.dataUrlOptions).mimetype; |
| | |
| | | } |
| | | |
| | | /** |
| | | * Generates data uri. |
| | | * @param {NormalModule} module module for which the code should be generated |
| | | * @returns {string} DataURI |
| | | */ |
| | | generateDataUri(module) { |
| | | const source = /** @type {Source} */ (module.originalSource()); |
| | | |
| | | /** @type {string} */ |
| | | let encodedSource; |
| | | |
| | | if (typeof this.dataUrlOptions === "function") { |
| | |
| | | } |
| | | const mimeType = this.getMimeType(module); |
| | | |
| | | /** @type {string} */ |
| | | let encodedContent; |
| | | |
| | | if ( |
| | |
| | | /** @type {string} */ (module.resourceResolveData.encodedContent) |
| | | ).equals(source.buffer()) |
| | | ) { |
| | | encodedContent = module.resourceResolveData.encodedContent; |
| | | encodedContent = |
| | | /** @type {string} */ |
| | | (module.resourceResolveData.encodedContent); |
| | | } else { |
| | | encodedContent = encodeDataUri( |
| | | /** @type {"base64" | false} */ (encoding), |
| | |
| | | } |
| | | |
| | | /** |
| | | * Generates generated code for this runtime module. |
| | | * @param {NormalModule} module module for which the code should be generated |
| | | * @param {GenerateContext} generateContext context for generate |
| | | * @returns {Source | null} generated code |
| | |
| | | concatenationScope |
| | | } = generateContext; |
| | | |
| | | /** @type {string} */ |
| | | let content; |
| | | |
| | | const needContent = type === "javascript" || type === "css-url"; |
| | | |
| | | const needContent = type === JAVASCRIPT_TYPE || type === CSS_URL_TYPE; |
| | | const data = getData ? getData() : undefined; |
| | | |
| | | if ( |
| | |
| | | ) { |
| | | const encodedSource = this.generateDataUri(module); |
| | | content = |
| | | type === "javascript" ? JSON.stringify(encodedSource) : encodedSource; |
| | | type === JAVASCRIPT_TYPE |
| | | ? JSON.stringify(encodedSource) |
| | | : encodedSource; |
| | | |
| | | if (data) { |
| | | data.set("url", { [type]: content, ...data.get("url") }); |
| | |
| | | contentHash |
| | | ); |
| | | |
| | | if (data && (type === "javascript" || type === "css-url")) { |
| | | if (data && (type === JAVASCRIPT_TYPE || type === CSS_URL_TYPE)) { |
| | | data.set("url", { [type]: assetPath, ...data.get("url") }); |
| | | } |
| | | |
| | |
| | | content = assetPath; |
| | | } |
| | | |
| | | if (type === "javascript") { |
| | | if (type === JAVASCRIPT_TYPE) { |
| | | if (concatenationScope) { |
| | | concatenationScope.registerNamespaceExport( |
| | | ConcatenationScope.NAMESPACE_OBJECT_EXPORT |
| | |
| | | runtimeRequirements.add(RuntimeGlobals.module); |
| | | |
| | | return new RawSource(`${module.moduleArgument}.exports = ${content};`); |
| | | } else if (type === "css-url") { |
| | | } else if (type === CSS_URL_TYPE) { |
| | | return null; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Generates fallback output for the provided error condition. |
| | | * @param {Error} error the error |
| | | * @param {NormalModule} module module for which the code should be generated |
| | | * @param {GenerateContext} generateContext context for generate |
| | |
| | | case "asset": { |
| | | return new RawSource(error.message); |
| | | } |
| | | case "javascript": { |
| | | case JAVASCRIPT_TYPE: { |
| | | return new RawSource( |
| | | `throw new Error(${JSON.stringify(error.message)});` |
| | | ); |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the source types available for this module. |
| | | * @param {NormalModule} module fresh module |
| | | * @returns {SourceTypes} available types (do not mutate) |
| | | */ |
| | |
| | | |
| | | if ((module.buildInfo && module.buildInfo.dataUrl) || this.emit === false) { |
| | | if (sourceTypes.size > 0) { |
| | | if (sourceTypes.has("javascript") && sourceTypes.has("css")) { |
| | | return JS_AND_CSS_URL_TYPES; |
| | | } else if (sourceTypes.has("css")) { |
| | | if (sourceTypes.has(JAVASCRIPT_TYPE) && sourceTypes.has(CSS_TYPE)) { |
| | | return JAVASCRIPT_AND_CSS_URL_TYPES; |
| | | } else if (sourceTypes.has(CSS_TYPE)) { |
| | | return CSS_URL_TYPES; |
| | | } |
| | | return JS_TYPES; |
| | | return JAVASCRIPT_TYPES; |
| | | } |
| | | |
| | | return NO_TYPES; |
| | | } |
| | | |
| | | if (sourceTypes.size > 0) { |
| | | if (sourceTypes.has("javascript") && sourceTypes.has("css")) { |
| | | return ASSET_AND_JS_AND_CSS_URL_TYPES; |
| | | } else if (sourceTypes.has("css")) { |
| | | if (sourceTypes.has(JAVASCRIPT_TYPE) && sourceTypes.has(CSS_TYPE)) { |
| | | return ASSET_AND_JAVASCRIPT_AND_CSS_URL_TYPES; |
| | | } else if (sourceTypes.has(CSS_TYPE)) { |
| | | return ASSET_AND_CSS_URL_TYPES; |
| | | } |
| | | return ASSET_AND_JS_TYPES; |
| | | return ASSET_AND_JAVASCRIPT_TYPES; |
| | | } |
| | | |
| | | return ASSET_TYPES; |
| | | } |
| | | |
| | | /** |
| | | * Returns the estimated size for the requested source type. |
| | | * @param {NormalModule} module the module |
| | | * @param {string=} type source type |
| | | * @param {SourceType=} type source type |
| | | * @returns {number} estimate size of the module |
| | | */ |
| | | getSize(module, type) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Updates the hash with the data contributed by this instance. |
| | | * @param {Hash} hash hash that will be modified |
| | | * @param {UpdateHashContext} updateHashContext context for updating hash |
| | | */ |