| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 | 
							- /*
 
- 	MIT License http://www.opensource.org/licenses/mit-license.php
 
- 	Author Tobias Koppers @sokra
 
- */
 
- "use strict";
 
- const path = require("path");
 
- const { ConcatSource, RawSource } = require("webpack-sources");
 
- const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
 
- const SourceMapDevToolModuleOptionsPlugin = require("./SourceMapDevToolModuleOptionsPlugin");
 
- const createHash = require("./util/createHash");
 
- const { absolutify } = require("./util/identifier");
 
- const validateOptions = require("schema-utils");
 
- const schema = require("../schemas/plugins/SourceMapDevToolPlugin.json");
 
- /** @typedef {import("../declarations/plugins/SourceMapDevToolPlugin").SourceMapDevToolPluginOptions} SourceMapDevToolPluginOptions */
 
- /** @typedef {import("./Chunk")} Chunk */
 
- /** @typedef {import("webpack-sources").Source} Source */
 
- /** @typedef {import("source-map").RawSourceMap} SourceMap */
 
- /** @typedef {import("./Module")} Module */
 
- /** @typedef {import("./Compilation")} Compilation */
 
- /** @typedef {import("./Compiler")} Compiler */
 
- /** @typedef {import("./Compilation")} SourceMapDefinition */
 
- /**
 
-  * @typedef {object} SourceMapTask
 
-  * @property {Source} asset
 
-  * @property {Array<string | Module>} [modules]
 
-  * @property {string} source
 
-  * @property {string} file
 
-  * @property {SourceMap} sourceMap
 
-  * @property {Chunk} chunk
 
-  */
 
- /**
 
-  * @param {string} name file path
 
-  * @returns {string} file name
 
-  */
 
- const basename = name => {
 
- 	if (!name.includes("/")) return name;
 
- 	return name.substr(name.lastIndexOf("/") + 1);
 
- };
 
- /**
 
-  * @type {WeakMap<Source, {file: string, assets: {[k: string]: ConcatSource | RawSource}}>}
 
-  */
 
- const assetsCache = new WeakMap();
 
- /**
 
-  * Creating {@link SourceMapTask} for given file
 
-  * @param {string} file current compiled file
 
-  * @param {Source} asset the asset
 
-  * @param {Chunk} chunk related chunk
 
-  * @param {SourceMapDevToolPluginOptions} options source map options
 
-  * @param {Compilation} compilation compilation instance
 
-  * @returns {SourceMapTask | undefined} created task instance or `undefined`
 
-  */
 
- const getTaskForFile = (file, asset, chunk, options, compilation) => {
 
- 	let source, sourceMap;
 
- 	/**
 
- 	 * Check if asset can build source map
 
- 	 */
 
- 	if (asset.sourceAndMap) {
 
- 		const sourceAndMap = asset.sourceAndMap(options);
 
- 		sourceMap = sourceAndMap.map;
 
- 		source = sourceAndMap.source;
 
- 	} else {
 
- 		sourceMap = asset.map(options);
 
- 		source = asset.source();
 
- 	}
 
- 	if (!sourceMap || typeof source !== "string") return;
 
- 	const context = compilation.options.context;
 
- 	const modules = sourceMap.sources.map(source => {
 
- 		if (source.startsWith("webpack://")) {
 
- 			source = absolutify(context, source.slice(10));
 
- 		}
 
- 		const module = compilation.findModule(source);
 
- 		return module || source;
 
- 	});
 
- 	return {
 
- 		chunk,
 
- 		file,
 
- 		asset,
 
- 		source,
 
- 		sourceMap,
 
- 		modules
 
- 	};
 
- };
 
- class SourceMapDevToolPlugin {
 
- 	/**
 
- 	 * @param {SourceMapDevToolPluginOptions} [options] options object
 
- 	 * @throws {Error} throws error, if got more than 1 arguments
 
- 	 */
 
- 	constructor(options) {
 
- 		if (arguments.length > 1) {
 
- 			throw new Error(
 
- 				"SourceMapDevToolPlugin only takes one argument (pass an options object)"
 
- 			);
 
- 		}
 
- 		if (!options) options = {};
 
- 		validateOptions(schema, options, "SourceMap DevTool Plugin");
 
- 		/** @type {string | false} */
 
- 		this.sourceMapFilename = options.filename;
 
- 		/** @type {string | false} */
 
- 		this.sourceMappingURLComment =
 
- 			options.append === false
 
- 				? false
 
- 				: options.append || "\n//# sourceMappingURL=[url]";
 
- 		/** @type {string | Function} */
 
- 		this.moduleFilenameTemplate =
 
- 			options.moduleFilenameTemplate || "webpack://[namespace]/[resourcePath]";
 
- 		/** @type {string | Function} */
 
- 		this.fallbackModuleFilenameTemplate =
 
- 			options.fallbackModuleFilenameTemplate ||
 
- 			"webpack://[namespace]/[resourcePath]?[hash]";
 
- 		/** @type {string} */
 
- 		this.namespace = options.namespace || "";
 
- 		/** @type {SourceMapDevToolPluginOptions} */
 
- 		this.options = options;
 
- 	}
 
- 	/**
 
- 	 * Apply compiler
 
- 	 * @param {Compiler} compiler compiler instance
 
- 	 * @returns {void}
 
- 	 */
 
- 	apply(compiler) {
 
- 		const sourceMapFilename = this.sourceMapFilename;
 
- 		const sourceMappingURLComment = this.sourceMappingURLComment;
 
- 		const moduleFilenameTemplate = this.moduleFilenameTemplate;
 
- 		const namespace = this.namespace;
 
- 		const fallbackModuleFilenameTemplate = this.fallbackModuleFilenameTemplate;
 
- 		const requestShortener = compiler.requestShortener;
 
- 		const options = this.options;
 
- 		options.test = options.test || /\.(m?js|css)($|\?)/i;
 
- 		const matchObject = ModuleFilenameHelpers.matchObject.bind(
 
- 			undefined,
 
- 			options
 
- 		);
 
- 		compiler.hooks.compilation.tap("SourceMapDevToolPlugin", compilation => {
 
- 			new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation);
 
- 			compilation.hooks.afterOptimizeChunkAssets.tap(
 
- 				/** @type {TODO} */
 
- 				({ name: "SourceMapDevToolPlugin", context: true }),
 
- 				/**
 
- 				 * @param {object} context hook context
 
- 				 * @param {Array<Chunk>} chunks resulted chunks
 
- 				 * @throws {Error} throws error, if `sourceMapFilename === false && sourceMappingURLComment === false`
 
- 				 * @returns {void}
 
- 				 */
 
- 				(context, chunks) => {
 
- 					/** @type {Map<string | Module, string>} */
 
- 					const moduleToSourceNameMapping = new Map();
 
- 					/**
 
- 					 * @type {Function}
 
- 					 * @returns {void}
 
- 					 */
 
- 					const reportProgress =
 
- 						context && context.reportProgress
 
- 							? context.reportProgress
 
- 							: () => {};
 
- 					const files = [];
 
- 					for (const chunk of chunks) {
 
- 						for (const file of chunk.files) {
 
- 							if (matchObject(file)) {
 
- 								files.push({
 
- 									file,
 
- 									chunk
 
- 								});
 
- 							}
 
- 						}
 
- 					}
 
- 					reportProgress(0.0);
 
- 					const tasks = [];
 
- 					files.forEach(({ file, chunk }, idx) => {
 
- 						const asset = compilation.getAsset(file).source;
 
- 						const cache = assetsCache.get(asset);
 
- 						/**
 
- 						 * If presented in cache, reassigns assets. Cache assets already have source maps.
 
- 						 */
 
- 						if (cache && cache.file === file) {
 
- 							for (const cachedFile in cache.assets) {
 
- 								if (cachedFile === file) {
 
- 									compilation.updateAsset(cachedFile, cache.assets[cachedFile]);
 
- 								} else {
 
- 									compilation.emitAsset(cachedFile, cache.assets[cachedFile], {
 
- 										development: true
 
- 									});
 
- 								}
 
- 								/**
 
- 								 * Add file to chunk, if not presented there
 
- 								 */
 
- 								if (cachedFile !== file) chunk.files.push(cachedFile);
 
- 							}
 
- 							return;
 
- 						}
 
- 						reportProgress(
 
- 							(0.5 * idx) / files.length,
 
- 							file,
 
- 							"generate SourceMap"
 
- 						);
 
- 						/** @type {SourceMapTask | undefined} */
 
- 						const task = getTaskForFile(
 
- 							file,
 
- 							asset,
 
- 							chunk,
 
- 							options,
 
- 							compilation
 
- 						);
 
- 						if (task) {
 
- 							const modules = task.modules;
 
- 							for (let idx = 0; idx < modules.length; idx++) {
 
- 								const module = modules[idx];
 
- 								if (!moduleToSourceNameMapping.get(module)) {
 
- 									moduleToSourceNameMapping.set(
 
- 										module,
 
- 										ModuleFilenameHelpers.createFilename(
 
- 											module,
 
- 											{
 
- 												moduleFilenameTemplate: moduleFilenameTemplate,
 
- 												namespace: namespace
 
- 											},
 
- 											requestShortener
 
- 										)
 
- 									);
 
- 								}
 
- 							}
 
- 							tasks.push(task);
 
- 						}
 
- 					});
 
- 					reportProgress(0.5, "resolve sources");
 
- 					/** @type {Set<string>} */
 
- 					const usedNamesSet = new Set(moduleToSourceNameMapping.values());
 
- 					/** @type {Set<string>} */
 
- 					const conflictDetectionSet = new Set();
 
- 					/**
 
- 					 * all modules in defined order (longest identifier first)
 
- 					 * @type {Array<string | Module>}
 
- 					 */
 
- 					const allModules = Array.from(moduleToSourceNameMapping.keys()).sort(
 
- 						(a, b) => {
 
- 							const ai = typeof a === "string" ? a : a.identifier();
 
- 							const bi = typeof b === "string" ? b : b.identifier();
 
- 							return ai.length - bi.length;
 
- 						}
 
- 					);
 
- 					// find modules with conflicting source names
 
- 					for (let idx = 0; idx < allModules.length; idx++) {
 
- 						const module = allModules[idx];
 
- 						let sourceName = moduleToSourceNameMapping.get(module);
 
- 						let hasName = conflictDetectionSet.has(sourceName);
 
- 						if (!hasName) {
 
- 							conflictDetectionSet.add(sourceName);
 
- 							continue;
 
- 						}
 
- 						// try the fallback name first
 
- 						sourceName = ModuleFilenameHelpers.createFilename(
 
- 							module,
 
- 							{
 
- 								moduleFilenameTemplate: fallbackModuleFilenameTemplate,
 
- 								namespace: namespace
 
- 							},
 
- 							requestShortener
 
- 						);
 
- 						hasName = usedNamesSet.has(sourceName);
 
- 						if (!hasName) {
 
- 							moduleToSourceNameMapping.set(module, sourceName);
 
- 							usedNamesSet.add(sourceName);
 
- 							continue;
 
- 						}
 
- 						// elsewise just append stars until we have a valid name
 
- 						while (hasName) {
 
- 							sourceName += "*";
 
- 							hasName = usedNamesSet.has(sourceName);
 
- 						}
 
- 						moduleToSourceNameMapping.set(module, sourceName);
 
- 						usedNamesSet.add(sourceName);
 
- 					}
 
- 					tasks.forEach((task, index) => {
 
- 						reportProgress(
 
- 							0.5 + (0.5 * index) / tasks.length,
 
- 							task.file,
 
- 							"attach SourceMap"
 
- 						);
 
- 						const assets = Object.create(null);
 
- 						const chunk = task.chunk;
 
- 						const file = task.file;
 
- 						const asset = task.asset;
 
- 						const sourceMap = task.sourceMap;
 
- 						const source = task.source;
 
- 						const modules = task.modules;
 
- 						const moduleFilenames = modules.map(m =>
 
- 							moduleToSourceNameMapping.get(m)
 
- 						);
 
- 						sourceMap.sources = moduleFilenames;
 
- 						if (options.noSources) {
 
- 							sourceMap.sourcesContent = undefined;
 
- 						}
 
- 						sourceMap.sourceRoot = options.sourceRoot || "";
 
- 						sourceMap.file = file;
 
- 						assetsCache.set(asset, { file, assets });
 
- 						/** @type {string | false} */
 
- 						let currentSourceMappingURLComment = sourceMappingURLComment;
 
- 						if (
 
- 							currentSourceMappingURLComment !== false &&
 
- 							/\.css($|\?)/i.test(file)
 
- 						) {
 
- 							currentSourceMappingURLComment = currentSourceMappingURLComment.replace(
 
- 								/^\n\/\/(.*)$/,
 
- 								"\n/*$1*/"
 
- 							);
 
- 						}
 
- 						const sourceMapString = JSON.stringify(sourceMap);
 
- 						if (sourceMapFilename) {
 
- 							let filename = file;
 
- 							let query = "";
 
- 							const idx = filename.indexOf("?");
 
- 							if (idx >= 0) {
 
- 								query = filename.substr(idx);
 
- 								filename = filename.substr(0, idx);
 
- 							}
 
- 							const pathParams = {
 
- 								chunk,
 
- 								filename: options.fileContext
 
- 									? path.relative(options.fileContext, filename)
 
- 									: filename,
 
- 								query,
 
- 								basename: basename(filename),
 
- 								contentHash: createHash("md4")
 
- 									.update(sourceMapString)
 
- 									.digest("hex")
 
- 							};
 
- 							let sourceMapFile = compilation.getPath(
 
- 								sourceMapFilename,
 
- 								pathParams
 
- 							);
 
- 							const sourceMapUrl = options.publicPath
 
- 								? options.publicPath + sourceMapFile.replace(/\\/g, "/")
 
- 								: path
 
- 										.relative(path.dirname(file), sourceMapFile)
 
- 										.replace(/\\/g, "/");
 
- 							/**
 
- 							 * Add source map url to compilation asset, if {@link currentSourceMappingURLComment} presented
 
- 							 */
 
- 							if (currentSourceMappingURLComment !== false) {
 
- 								const asset = new ConcatSource(
 
- 									new RawSource(source),
 
- 									compilation.getPath(
 
- 										currentSourceMappingURLComment,
 
- 										Object.assign({ url: sourceMapUrl }, pathParams)
 
- 									)
 
- 								);
 
- 								assets[file] = asset;
 
- 								compilation.updateAsset(file, asset);
 
- 							}
 
- 							/**
 
- 							 * Add source map file to compilation assets and chunk files
 
- 							 */
 
- 							const asset = new RawSource(sourceMapString);
 
- 							assets[sourceMapFile] = asset;
 
- 							compilation.emitAsset(sourceMapFile, asset, {
 
- 								development: true
 
- 							});
 
- 							chunk.files.push(sourceMapFile);
 
- 						} else {
 
- 							if (currentSourceMappingURLComment === false) {
 
- 								throw new Error(
 
- 									"SourceMapDevToolPlugin: append can't be false when no filename is provided"
 
- 								);
 
- 							}
 
- 							/**
 
- 							 * Add source map as data url to asset
 
- 							 */
 
- 							const asset = new ConcatSource(
 
- 								new RawSource(source),
 
- 								currentSourceMappingURLComment
 
- 									.replace(/\[map\]/g, () => sourceMapString)
 
- 									.replace(
 
- 										/\[url\]/g,
 
- 										() =>
 
- 											`data:application/json;charset=utf-8;base64,${Buffer.from(
 
- 												sourceMapString,
 
- 												"utf-8"
 
- 											).toString("base64")}`
 
- 									)
 
- 							);
 
- 							assets[file] = asset;
 
- 							compilation.updateAsset(file, asset);
 
- 						}
 
- 					});
 
- 					reportProgress(1.0);
 
- 				}
 
- 			);
 
- 		});
 
- 	}
 
- }
 
- module.exports = SourceMapDevToolPlugin;
 
 
  |