123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Yuta Hiroto @hiroppy
- */
- "use strict";
- const {
- ASSET_MODULE_TYPE_RESOURCE,
- ASSET_MODULE_TYPE_INLINE,
- ASSET_MODULE_TYPE,
- ASSET_MODULE_TYPE_SOURCE
- } = require("../ModuleTypeConstants");
- const { cleverMerge } = require("../util/cleverMerge");
- const { compareModulesByIdOrIdentifier } = require("../util/comparators");
- const createSchemaValidation = require("../util/create-schema-validation");
- const memoize = require("../util/memoize");
- /** @typedef {import("webpack-sources").Source} Source */
- /** @typedef {import("../../declarations/WebpackOptions").AssetParserOptions} AssetParserOptions */
- /** @typedef {import("../Chunk")} Chunk */
- /** @typedef {import("../Compilation").AssetInfo} AssetInfo */
- /** @typedef {import("../Compiler")} Compiler */
- /** @typedef {import("../Module")} Module */
- /** @typedef {import("../Module").BuildInfo} BuildInfo */
- /** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
- /** @typedef {import("../NormalModule")} NormalModule */
- /**
- * @param {string} name name of definitions
- * @returns {TODO} definition
- */
- const getSchema = name => {
- const { definitions } = require("../../schemas/WebpackOptions.json");
- return {
- definitions,
- oneOf: [{ $ref: `#/definitions/${name}` }]
- };
- };
- const generatorValidationOptions = {
- name: "Asset Modules Plugin",
- baseDataPath: "generator"
- };
- const validateGeneratorOptions = {
- asset: createSchemaValidation(
- require("../../schemas/plugins/asset/AssetGeneratorOptions.check.js"),
- () => getSchema("AssetGeneratorOptions"),
- generatorValidationOptions
- ),
- "asset/resource": createSchemaValidation(
- require("../../schemas/plugins/asset/AssetResourceGeneratorOptions.check.js"),
- () => getSchema("AssetResourceGeneratorOptions"),
- generatorValidationOptions
- ),
- "asset/inline": createSchemaValidation(
- require("../../schemas/plugins/asset/AssetInlineGeneratorOptions.check.js"),
- () => getSchema("AssetInlineGeneratorOptions"),
- generatorValidationOptions
- )
- };
- const validateParserOptions = createSchemaValidation(
- require("../../schemas/plugins/asset/AssetParserOptions.check.js"),
- () => getSchema("AssetParserOptions"),
- {
- name: "Asset Modules Plugin",
- baseDataPath: "parser"
- }
- );
- const getAssetGenerator = memoize(() => require("./AssetGenerator"));
- const getAssetParser = memoize(() => require("./AssetParser"));
- const getAssetSourceParser = memoize(() => require("./AssetSourceParser"));
- const getAssetSourceGenerator = memoize(() =>
- require("./AssetSourceGenerator")
- );
- const type = ASSET_MODULE_TYPE;
- const plugin = "AssetModulesPlugin";
- class AssetModulesPlugin {
- /**
- * Apply the plugin
- * @param {Compiler} compiler the compiler instance
- * @returns {void}
- */
- apply(compiler) {
- compiler.hooks.compilation.tap(
- plugin,
- (compilation, { normalModuleFactory }) => {
- normalModuleFactory.hooks.createParser
- .for(ASSET_MODULE_TYPE)
- .tap(plugin, parserOptions => {
- validateParserOptions(parserOptions);
- parserOptions = cleverMerge(
- /** @type {AssetParserOptions} */
- (compiler.options.module.parser.asset),
- parserOptions
- );
- let dataUrlCondition = parserOptions.dataUrlCondition;
- if (!dataUrlCondition || typeof dataUrlCondition === "object") {
- dataUrlCondition = {
- maxSize: 8096,
- ...dataUrlCondition
- };
- }
- const AssetParser = getAssetParser();
- return new AssetParser(dataUrlCondition);
- });
- normalModuleFactory.hooks.createParser
- .for(ASSET_MODULE_TYPE_INLINE)
- .tap(plugin, _parserOptions => {
- const AssetParser = getAssetParser();
- return new AssetParser(true);
- });
- normalModuleFactory.hooks.createParser
- .for(ASSET_MODULE_TYPE_RESOURCE)
- .tap(plugin, _parserOptions => {
- const AssetParser = getAssetParser();
- return new AssetParser(false);
- });
- normalModuleFactory.hooks.createParser
- .for(ASSET_MODULE_TYPE_SOURCE)
- .tap(plugin, _parserOptions => {
- const AssetSourceParser = getAssetSourceParser();
- return new AssetSourceParser();
- });
- for (const type of [
- ASSET_MODULE_TYPE,
- ASSET_MODULE_TYPE_INLINE,
- ASSET_MODULE_TYPE_RESOURCE
- ]) {
- normalModuleFactory.hooks.createGenerator
- .for(type)
- .tap(plugin, generatorOptions => {
- validateGeneratorOptions[type](generatorOptions);
- let dataUrl;
- if (type !== ASSET_MODULE_TYPE_RESOURCE) {
- dataUrl = generatorOptions.dataUrl;
- if (!dataUrl || typeof dataUrl === "object") {
- dataUrl = {
- encoding: undefined,
- mimetype: undefined,
- ...dataUrl
- };
- }
- }
- let filename;
- let publicPath;
- let outputPath;
- if (type !== ASSET_MODULE_TYPE_INLINE) {
- filename = generatorOptions.filename;
- publicPath = generatorOptions.publicPath;
- outputPath = generatorOptions.outputPath;
- }
- const AssetGenerator = getAssetGenerator();
- return new AssetGenerator(
- compilation.moduleGraph,
- dataUrl,
- filename,
- publicPath,
- outputPath,
- generatorOptions.emit !== false
- );
- });
- }
- normalModuleFactory.hooks.createGenerator
- .for(ASSET_MODULE_TYPE_SOURCE)
- .tap(plugin, () => {
- const AssetSourceGenerator = getAssetSourceGenerator();
- return new AssetSourceGenerator(compilation.moduleGraph);
- });
- compilation.hooks.renderManifest.tap(plugin, (result, options) => {
- const { chunkGraph } = compilation;
- const { chunk, codeGenerationResults, runtimeTemplate } = options;
- const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
- chunk,
- ASSET_MODULE_TYPE,
- compareModulesByIdOrIdentifier(chunkGraph)
- );
- if (modules) {
- for (const module of modules) {
- try {
- const codeGenResult = codeGenerationResults.get(
- module,
- chunk.runtime
- );
- const buildInfo = /** @type {BuildInfo} */ (module.buildInfo);
- const data =
- /** @type {NonNullable<CodeGenerationResult["data"]>} */
- (codeGenResult.data);
- const errored = module.getNumberOfErrors() > 0;
- /** @type {string} */
- let entryFilename;
- /** @type {AssetInfo} */
- let entryInfo;
- /** @type {string} */
- let entryHash;
- if (errored) {
- const erroredModule = /** @type {NormalModule} */ (module);
- const AssetGenerator = getAssetGenerator();
- const [fullContentHash, contentHash] =
- AssetGenerator.getFullContentHash(
- erroredModule,
- runtimeTemplate
- );
- const { filename, assetInfo } =
- AssetGenerator.getFilenameWithInfo(
- erroredModule,
- {
- filename:
- erroredModule.generatorOptions &&
- erroredModule.generatorOptions.filename,
- outputPath:
- erroredModule.generatorOptions &&
- erroredModule.generatorOptions.outputPath
- },
- {
- runtime: chunk.runtime,
- runtimeTemplate,
- chunkGraph
- },
- contentHash
- );
- entryFilename = filename;
- entryInfo = assetInfo;
- entryHash = fullContentHash;
- } else {
- entryFilename = buildInfo.filename || data.get("filename");
- entryInfo = buildInfo.assetInfo || data.get("assetInfo");
- entryHash =
- buildInfo.fullContentHash || data.get("fullContentHash");
- }
- result.push({
- render: () =>
- /** @type {Source} */ (codeGenResult.sources.get(type)),
- filename: entryFilename,
- info: entryInfo,
- auxiliary: true,
- identifier: `assetModule${chunkGraph.getModuleId(module)}`,
- hash: entryHash
- });
- } catch (err) {
- /** @type {Error} */ (err).message +=
- `\nduring rendering of asset ${module.identifier()}`;
- throw err;
- }
- }
- }
- return result;
- });
- compilation.hooks.prepareModuleExecution.tap(
- "AssetModulesPlugin",
- (options, context) => {
- const { codeGenerationResult } = options;
- const source = codeGenerationResult.sources.get(ASSET_MODULE_TYPE);
- if (source === undefined) return;
- const data =
- /** @type {NonNullable<CodeGenerationResult["data"]>} */
- (codeGenerationResult.data);
- context.assets.set(data.get("filename"), {
- source,
- info: data.get("assetInfo")
- });
- }
- );
- }
- );
- }
- }
- module.exports = AssetModulesPlugin;
|