| | |
| | | const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); |
| | | const ProgressPlugin = require("./ProgressPlugin"); |
| | | const SourceMapDevToolModuleOptionsPlugin = require("./SourceMapDevToolModuleOptionsPlugin"); |
| | | const createSchemaValidation = require("./util/create-schema-validation"); |
| | | const createHash = require("./util/createHash"); |
| | | const { dirname, relative } = require("./util/fs"); |
| | | const generateDebugId = require("./util/generateDebugId"); |
| | |
| | | |
| | | /** @typedef {import("webpack-sources").MapOptions} MapOptions */ |
| | | /** @typedef {import("webpack-sources").Source} Source */ |
| | | /** @typedef {import("../declarations/WebpackOptions").DevtoolNamespace} DevtoolNamespace */ |
| | | /** @typedef {import("../declarations/WebpackOptions").DevtoolModuleFilenameTemplate} DevtoolModuleFilenameTemplate */ |
| | | /** @typedef {import("../declarations/WebpackOptions").DevtoolFallbackModuleFilenameTemplate} DevtoolFallbackModuleFilenameTemplate */ |
| | | /** @typedef {import("../declarations/plugins/SourceMapDevToolPlugin").SourceMapDevToolPluginOptions} SourceMapDevToolPluginOptions */ |
| | | /** @typedef {import("../declarations/plugins/SourceMapDevToolPlugin").Rules} Rules */ |
| | | /** @typedef {import("./CacheFacade").ItemCacheFacade} ItemCacheFacade */ |
| | |
| | | /** @typedef {import("./TemplatedPathPlugin").TemplatePath} TemplatePath */ |
| | | /** @typedef {import("./util/fs").OutputFileSystem} OutputFileSystem */ |
| | | |
| | | const validate = createSchemaValidation( |
| | | require("../schemas/plugins/SourceMapDevToolPlugin.check"), |
| | | () => require("../schemas/plugins/SourceMapDevToolPlugin.json"), |
| | | { |
| | | name: "SourceMap DevTool Plugin", |
| | | baseDataPath: "options" |
| | | } |
| | | ); |
| | | /** |
| | | * Defines the source map task type used by this module. |
| | | * @typedef {object} SourceMapTask |
| | | * @property {Source} asset |
| | | * @property {AssetInfo} assetInfo |
| | |
| | | */ |
| | | |
| | | const METACHARACTERS_REGEXP = /[-[\]\\/{}()*+?.^$|]/g; |
| | | const CONTENT_HASH_DETECT_REGEXP = /\[contenthash(:\w+)?\]/; |
| | | const CONTENT_HASH_DETECT_REGEXP = /\[contenthash(?::\w+)?\]/; |
| | | const CSS_AND_JS_MODULE_EXTENSIONS_REGEXP = /\.((c|m)?js|css)($|\?)/i; |
| | | const CSS_EXTENSION_DETECT_REGEXP = /\.css($|\?)/i; |
| | | const CSS_EXTENSION_DETECT_REGEXP = /\.css(?:$|\?)/i; |
| | | const MAP_URL_COMMENT_REGEXP = /\[map\]/g; |
| | | const URL_COMMENT_REGEXP = /\[url\]/g; |
| | | const URL_FORMATTING_REGEXP = /^\n\/\/(.*)$/; |
| | |
| | | compilation, |
| | | cacheItem |
| | | ) => { |
| | | /** @type {string | Buffer} */ |
| | | let source; |
| | | /** @type {RawSourceMap} */ |
| | | /** @type {null | RawSourceMap} */ |
| | | let sourceMap; |
| | | /** |
| | | * Check if asset can build source map |
| | | */ |
| | | if (asset.sourceAndMap) { |
| | | const sourceAndMap = asset.sourceAndMap(options); |
| | | sourceMap = /** @type {RawSourceMap} */ (sourceAndMap.map); |
| | | sourceMap = sourceAndMap.map; |
| | | source = sourceAndMap.source; |
| | | } else { |
| | | sourceMap = /** @type {RawSourceMap} */ (asset.map(options)); |
| | | sourceMap = asset.map(options); |
| | | source = asset.source(); |
| | | } |
| | | if (!sourceMap || typeof source !== "string") return; |
| | |
| | | |
| | | class SourceMapDevToolPlugin { |
| | | /** |
| | | * Creates an instance of SourceMapDevToolPlugin. |
| | | * @param {SourceMapDevToolPluginOptions=} options options object |
| | | * @throws {Error} throws error, if got more than 1 arguments |
| | | */ |
| | | constructor(options = {}) { |
| | | validate(options); |
| | | |
| | | this.sourceMapFilename = /** @type {string | false} */ (options.filename); |
| | | /** @type {false | TemplatePath}} */ |
| | | /** @type {undefined | null | false | string} */ |
| | | this.sourceMapFilename = options.filename; |
| | | /** @type {false | TemplatePath} */ |
| | | this.sourceMappingURLComment = |
| | | options.append === false |
| | | ? false |
| | | : // eslint-disable-next-line no-useless-concat |
| | | options.append || "\n//# source" + "MappingURL=[url]"; |
| | | /** @type {DevtoolModuleFilenameTemplate} */ |
| | | this.moduleFilenameTemplate = |
| | | options.moduleFilenameTemplate || "webpack://[namespace]/[resourcePath]"; |
| | | /** @type {DevtoolFallbackModuleFilenameTemplate} */ |
| | | this.fallbackModuleFilenameTemplate = |
| | | options.fallbackModuleFilenameTemplate || |
| | | "webpack://[namespace]/[resourcePath]?[hash]"; |
| | | /** @type {DevtoolNamespace} */ |
| | | this.namespace = options.namespace || ""; |
| | | /** @type {SourceMapDevToolPluginOptions} */ |
| | | this.options = options; |
| | | } |
| | | |
| | | /** |
| | | * Apply the plugin |
| | | * Applies the plugin by registering its hooks on the compiler. |
| | | * @param {Compiler} compiler compiler instance |
| | | * @returns {void} |
| | | */ |
| | | apply(compiler) { |
| | | compiler.hooks.validate.tap(PLUGIN_NAME, () => { |
| | | compiler.validate( |
| | | () => require("../schemas/plugins/SourceMapDevToolPlugin.json"), |
| | | this.options, |
| | | { |
| | | name: "SourceMap DevTool Plugin", |
| | | baseDataPath: "options" |
| | | }, |
| | | (options) => |
| | | require("../schemas/plugins/SourceMapDevToolPlugin.check")(options) |
| | | ); |
| | | }); |
| | | |
| | | const outputFs = |
| | | /** @type {OutputFileSystem} */ |
| | | (compiler.outputFileSystem); |
| | |
| | | const options = this.options; |
| | | options.test = options.test || CSS_AND_JS_MODULE_EXTENSIONS_REGEXP; |
| | | |
| | | /** @type {(filename: string) => boolean} */ |
| | | const matchObject = ModuleFilenameHelpers.matchObject.bind( |
| | | undefined, |
| | | options |
| | |
| | | |
| | | if ( |
| | | typeof module === "string" && |
| | | /^(data|https?):/.test(module) |
| | | /^(?:data|https?):/.test(module) |
| | | ) { |
| | | moduleToSourceNameMapping.set(module, module); |
| | | continue; |
| | |
| | | asyncLib.each( |
| | | tasks, |
| | | (task, callback) => { |
| | | /** @type {Record<string, Source>} */ |
| | | const assets = Object.create(null); |
| | | /** @type {Record<string, AssetInfo | undefined>} */ |
| | | const assetsInfo = Object.create(null); |
| | | const file = task.file; |
| | | const chunk = fileToChunk.get(file); |
| | |
| | | moduleToSourceNameMapping.get(m) |
| | | ); |
| | | sourceMap.sources = /** @type {string[]} */ (moduleFilenames); |
| | | sourceMap.ignoreList = options.ignoreList |
| | | ? sourceMap.sources.reduce( |
| | | /** @type {(acc: number[], sourceName: string, idx: number) => number[]} */ ( |
| | | (acc, sourceName, idx) => { |
| | | const rule = /** @type {Rules} */ ( |
| | | options.ignoreList |
| | | ); |
| | | if ( |
| | | ModuleFilenameHelpers.matchPart(sourceName, rule) |
| | | ) { |
| | | acc.push(idx); |
| | | } |
| | | return acc; |
| | | if (options.ignoreList) { |
| | | const ignoreList = sourceMap.sources.reduce( |
| | | /** @type {(acc: number[], sourceName: string, idx: number) => number[]} */ ( |
| | | (acc, sourceName, idx) => { |
| | | const rule = /** @type {Rules} */ ( |
| | | options.ignoreList |
| | | ); |
| | | if ( |
| | | ModuleFilenameHelpers.matchPart(sourceName, rule) |
| | | ) { |
| | | acc.push(idx); |
| | | } |
| | | ), |
| | | [] |
| | | ) |
| | | : []; |
| | | return acc; |
| | | } |
| | | ), |
| | | [] |
| | | ); |
| | | if (ignoreList.length > 0) { |
| | | sourceMap.ignoreList = ignoreList; |
| | | } |
| | | } |
| | | |
| | | if (options.noSources) { |
| | | sourceMap.sourcesContent = undefined; |
| | |
| | | if (options.debugIds) { |
| | | const debugId = generateDebugId(source, sourceMap.file); |
| | | sourceMap.debugId = debugId; |
| | | currentSourceMappingURLComment = `\n//# debugId=${debugId}${currentSourceMappingURLComment}`; |
| | | |
| | | const debugIdComment = `\n//# debugId=${debugId}`; |
| | | currentSourceMappingURLComment = |
| | | currentSourceMappingURLComment |
| | | ? `${debugIdComment}${currentSourceMappingURLComment}` |
| | | : debugIdComment; |
| | | } |
| | | |
| | | const sourceMapString = JSON.stringify(sourceMap); |