All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.lib.ModuleInfoHeaderPlugin.js Maven / Gradle / Ivy

Go to download

Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.

The newest version!
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { ConcatSource, RawSource, CachedSource } = require("webpack-sources");
const { UsageState } = require("./ExportsInfo");
const Template = require("./Template");
const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");

/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./ExportsInfo")} ExportsInfo */
/** @typedef {import("./ExportsInfo").ExportInfo} ExportInfo */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./Module").BuildMeta} BuildMeta */
/** @typedef {import("./ModuleGraph")} ModuleGraph */
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
/** @typedef {import("./RequestShortener")} RequestShortener */

/**
 * @template T
 * @param {Iterable} iterable iterable
 * @returns {string} joined with comma
 */
const joinIterableWithComma = iterable => {
	// This is more performant than Array.from().join(", ")
	// as it doesn't create an array
	let str = "";
	let first = true;
	for (const item of iterable) {
		if (first) {
			first = false;
		} else {
			str += ", ";
		}
		str += item;
	}
	return str;
};

/**
 * @param {ConcatSource} source output
 * @param {string} indent spacing
 * @param {ExportsInfo} exportsInfo data
 * @param {ModuleGraph} moduleGraph moduleGraph
 * @param {RequestShortener} requestShortener requestShortener
 * @param {Set} alreadyPrinted deduplication set
 * @returns {void}
 */
const printExportsInfoToSource = (
	source,
	indent,
	exportsInfo,
	moduleGraph,
	requestShortener,
	alreadyPrinted = new Set()
) => {
	const otherExportsInfo = exportsInfo.otherExportsInfo;

	let alreadyPrintedExports = 0;

	// determine exports to print
	const printedExports = [];
	for (const exportInfo of exportsInfo.orderedExports) {
		if (!alreadyPrinted.has(exportInfo)) {
			alreadyPrinted.add(exportInfo);
			printedExports.push(exportInfo);
		} else {
			alreadyPrintedExports++;
		}
	}
	let showOtherExports = false;
	if (!alreadyPrinted.has(otherExportsInfo)) {
		alreadyPrinted.add(otherExportsInfo);
		showOtherExports = true;
	} else {
		alreadyPrintedExports++;
	}

	// print the exports
	for (const exportInfo of printedExports) {
		const target = exportInfo.getTarget(moduleGraph);
		source.add(
			Template.toComment(
				`${indent}export ${JSON.stringify(exportInfo.name).slice(
					1,
					-1
				)} [${exportInfo.getProvidedInfo()}] [${exportInfo.getUsedInfo()}] [${exportInfo.getRenameInfo()}]${
					target
						? ` -> ${target.module.readableIdentifier(requestShortener)}${
								target.export
									? ` .${target.export
											.map(e => JSON.stringify(e).slice(1, -1))
											.join(".")}`
									: ""
							}`
						: ""
				}`
			) + "\n"
		);
		if (exportInfo.exportsInfo) {
			printExportsInfoToSource(
				source,
				indent + "  ",
				exportInfo.exportsInfo,
				moduleGraph,
				requestShortener,
				alreadyPrinted
			);
		}
	}

	if (alreadyPrintedExports) {
		source.add(
			Template.toComment(
				`${indent}... (${alreadyPrintedExports} already listed exports)`
			) + "\n"
		);
	}

	if (showOtherExports) {
		const target = otherExportsInfo.getTarget(moduleGraph);
		if (
			target ||
			otherExportsInfo.provided !== false ||
			otherExportsInfo.getUsed(undefined) !== UsageState.Unused
		) {
			const title =
				printedExports.length > 0 || alreadyPrintedExports > 0
					? "other exports"
					: "exports";
			source.add(
				Template.toComment(
					`${indent}${title} [${otherExportsInfo.getProvidedInfo()}] [${otherExportsInfo.getUsedInfo()}]${
						target
							? ` -> ${target.module.readableIdentifier(requestShortener)}`
							: ""
					}`
				) + "\n"
			);
		}
	}
};

/** @type {WeakMap }>>} */
const caches = new WeakMap();

class ModuleInfoHeaderPlugin {
	/**
	 * @param {boolean=} verbose add more information like exports, runtime requirements and bailouts
	 */
	constructor(verbose = true) {
		this._verbose = verbose;
	}
	/**
	 * @param {Compiler} compiler the compiler
	 * @returns {void}
	 */
	apply(compiler) {
		const { _verbose: verbose } = this;
		compiler.hooks.compilation.tap("ModuleInfoHeaderPlugin", compilation => {
			const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
			hooks.renderModulePackage.tap(
				"ModuleInfoHeaderPlugin",
				(
					moduleSource,
					module,
					{ chunk, chunkGraph, moduleGraph, runtimeTemplate }
				) => {
					const { requestShortener } = runtimeTemplate;
					let cacheEntry;
					let cache = caches.get(requestShortener);
					if (cache === undefined) {
						caches.set(requestShortener, (cache = new WeakMap()));
						cache.set(
							module,
							(cacheEntry = { header: undefined, full: new WeakMap() })
						);
					} else {
						cacheEntry = cache.get(module);
						if (cacheEntry === undefined) {
							cache.set(
								module,
								(cacheEntry = { header: undefined, full: new WeakMap() })
							);
						} else if (!verbose) {
							const cachedSource = cacheEntry.full.get(moduleSource);
							if (cachedSource !== undefined) return cachedSource;
						}
					}
					const source = new ConcatSource();
					let header = cacheEntry.header;
					if (header === undefined) {
						const req = module.readableIdentifier(requestShortener);
						const reqStr = req.replace(/\*\//g, "*_/");
						const reqStrStar = "*".repeat(reqStr.length);
						const headerStr = `/*!****${reqStrStar}****!*\\\n  !*** ${reqStr} ***!\n  \\****${reqStrStar}****/\n`;
						header = new RawSource(headerStr);
						cacheEntry.header = header;
					}
					source.add(header);
					if (verbose) {
						const exportsType = /** @type {BuildMeta} */ (module.buildMeta)
							.exportsType;
						source.add(
							Template.toComment(
								exportsType
									? `${exportsType} exports`
									: "unknown exports (runtime-defined)"
							) + "\n"
						);
						if (exportsType) {
							const exportsInfo = moduleGraph.getExportsInfo(module);
							printExportsInfoToSource(
								source,
								"",
								exportsInfo,
								moduleGraph,
								requestShortener
							);
						}
						source.add(
							Template.toComment(
								`runtime requirements: ${joinIterableWithComma(
									chunkGraph.getModuleRuntimeRequirements(module, chunk.runtime)
								)}`
							) + "\n"
						);
						const optimizationBailout =
							moduleGraph.getOptimizationBailout(module);
						if (optimizationBailout) {
							for (const text of optimizationBailout) {
								let code;
								if (typeof text === "function") {
									code = text(requestShortener);
								} else {
									code = text;
								}
								source.add(Template.toComment(`${code}`) + "\n");
							}
						}
						source.add(moduleSource);
						return source;
					} else {
						source.add(moduleSource);
						const cachedSource = new CachedSource(source);
						cacheEntry.full.set(moduleSource, cachedSource);
						return cachedSource;
					}
				}
			);
			hooks.chunkHash.tap("ModuleInfoHeaderPlugin", (chunk, hash) => {
				hash.update("ModuleInfoHeaderPlugin");
				hash.update("1");
			});
		});
	}
}
module.exports = ModuleInfoHeaderPlugin;




© 2015 - 2024 Weber Informatics LLC | Privacy Policy