1 | /*
|
---|
2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
3 | Author Tobias Koppers @sokra
|
---|
4 | */
|
---|
5 |
|
---|
6 | "use strict";
|
---|
7 |
|
---|
8 | const asyncLib = require("neo-async");
|
---|
9 | const { ConcatSource, RawSource } = require("webpack-sources");
|
---|
10 | const Compilation = require("./Compilation");
|
---|
11 | const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
|
---|
12 | const ProgressPlugin = require("./ProgressPlugin");
|
---|
13 | const SourceMapDevToolModuleOptionsPlugin = require("./SourceMapDevToolModuleOptionsPlugin");
|
---|
14 | const createSchemaValidation = require("./util/create-schema-validation");
|
---|
15 | const createHash = require("./util/createHash");
|
---|
16 | const { relative, dirname } = require("./util/fs");
|
---|
17 | const generateDebugId = require("./util/generateDebugId");
|
---|
18 | const { makePathsAbsolute } = require("./util/identifier");
|
---|
19 |
|
---|
20 | /** @typedef {import("webpack-sources").MapOptions} MapOptions */
|
---|
21 | /** @typedef {import("webpack-sources").Source} Source */
|
---|
22 | /** @typedef {import("../declarations/plugins/SourceMapDevToolPlugin").SourceMapDevToolPluginOptions} SourceMapDevToolPluginOptions */
|
---|
23 | /** @typedef {import("./Cache").Etag} Etag */
|
---|
24 | /** @typedef {import("./CacheFacade").ItemCacheFacade} ItemCacheFacade */
|
---|
25 | /** @typedef {import("./Chunk")} Chunk */
|
---|
26 | /** @typedef {import("./Compilation").Asset} Asset */
|
---|
27 | /** @typedef {import("./Compilation").AssetInfo} AssetInfo */
|
---|
28 | /** @typedef {import("./Compiler")} Compiler */
|
---|
29 | /** @typedef {import("./Module")} Module */
|
---|
30 | /** @typedef {import("./NormalModule").SourceMap} SourceMap */
|
---|
31 | /** @typedef {import("./TemplatedPathPlugin").TemplatePath} TemplatePath */
|
---|
32 | /** @typedef {import("./util/Hash")} Hash */
|
---|
33 | /** @typedef {import("./util/createHash").Algorithm} Algorithm */
|
---|
34 | /** @typedef {import("./util/fs").OutputFileSystem} OutputFileSystem */
|
---|
35 |
|
---|
36 | const validate = createSchemaValidation(
|
---|
37 | require("../schemas/plugins/SourceMapDevToolPlugin.check.js"),
|
---|
38 | () => require("../schemas/plugins/SourceMapDevToolPlugin.json"),
|
---|
39 | {
|
---|
40 | name: "SourceMap DevTool Plugin",
|
---|
41 | baseDataPath: "options"
|
---|
42 | }
|
---|
43 | );
|
---|
44 | /**
|
---|
45 | * @typedef {object} SourceMapTask
|
---|
46 | * @property {Source} asset
|
---|
47 | * @property {AssetInfo} assetInfo
|
---|
48 | * @property {(string | Module)[]} modules
|
---|
49 | * @property {string} source
|
---|
50 | * @property {string} file
|
---|
51 | * @property {SourceMap} sourceMap
|
---|
52 | * @property {ItemCacheFacade} cacheItem cache item
|
---|
53 | */
|
---|
54 |
|
---|
55 | const METACHARACTERS_REGEXP = /[-[\]\\/{}()*+?.^$|]/g;
|
---|
56 | const CONTENT_HASH_DETECT_REGEXP = /\[contenthash(:\w+)?\]/;
|
---|
57 | const CSS_AND_JS_MODULE_EXTENSIONS_REGEXP = /\.((c|m)?js|css)($|\?)/i;
|
---|
58 | const CSS_EXTENSION_DETECT_REGEXP = /\.css($|\?)/i;
|
---|
59 | const MAP_URL_COMMENT_REGEXP = /\[map\]/g;
|
---|
60 | const URL_COMMENT_REGEXP = /\[url\]/g;
|
---|
61 | const URL_FORMATTING_REGEXP = /^\n\/\/(.*)$/;
|
---|
62 |
|
---|
63 | /**
|
---|
64 | * Reset's .lastIndex of stateful Regular Expressions
|
---|
65 | * For when `test` or `exec` is called on them
|
---|
66 | * @param {RegExp} regexp Stateful Regular Expression to be reset
|
---|
67 | * @returns {void}
|
---|
68 | */
|
---|
69 | const resetRegexpState = regexp => {
|
---|
70 | regexp.lastIndex = -1;
|
---|
71 | };
|
---|
72 |
|
---|
73 | /**
|
---|
74 | * Escapes regular expression metacharacters
|
---|
75 | * @param {string} str String to quote
|
---|
76 | * @returns {string} Escaped string
|
---|
77 | */
|
---|
78 | const quoteMeta = str => str.replace(METACHARACTERS_REGEXP, "\\$&");
|
---|
79 |
|
---|
80 | /**
|
---|
81 | * Creating {@link SourceMapTask} for given file
|
---|
82 | * @param {string} file current compiled file
|
---|
83 | * @param {Source} asset the asset
|
---|
84 | * @param {AssetInfo} assetInfo the asset info
|
---|
85 | * @param {MapOptions} options source map options
|
---|
86 | * @param {Compilation} compilation compilation instance
|
---|
87 | * @param {ItemCacheFacade} cacheItem cache item
|
---|
88 | * @returns {SourceMapTask | undefined} created task instance or `undefined`
|
---|
89 | */
|
---|
90 | const getTaskForFile = (
|
---|
91 | file,
|
---|
92 | asset,
|
---|
93 | assetInfo,
|
---|
94 | options,
|
---|
95 | compilation,
|
---|
96 | cacheItem
|
---|
97 | ) => {
|
---|
98 | let source;
|
---|
99 | /** @type {SourceMap} */
|
---|
100 | let sourceMap;
|
---|
101 | /**
|
---|
102 | * Check if asset can build source map
|
---|
103 | */
|
---|
104 | if (asset.sourceAndMap) {
|
---|
105 | const sourceAndMap = asset.sourceAndMap(options);
|
---|
106 | sourceMap = /** @type {SourceMap} */ (sourceAndMap.map);
|
---|
107 | source = sourceAndMap.source;
|
---|
108 | } else {
|
---|
109 | sourceMap = /** @type {SourceMap} */ (asset.map(options));
|
---|
110 | source = asset.source();
|
---|
111 | }
|
---|
112 | if (!sourceMap || typeof source !== "string") return;
|
---|
113 | const context = /** @type {string} */ (compilation.options.context);
|
---|
114 | const root = compilation.compiler.root;
|
---|
115 | const cachedAbsolutify = makePathsAbsolute.bindContextCache(context, root);
|
---|
116 | const modules = sourceMap.sources.map(source => {
|
---|
117 | if (!source.startsWith("webpack://")) return source;
|
---|
118 | source = cachedAbsolutify(source.slice(10));
|
---|
119 | const module = compilation.findModule(source);
|
---|
120 | return module || source;
|
---|
121 | });
|
---|
122 |
|
---|
123 | return {
|
---|
124 | file,
|
---|
125 | asset,
|
---|
126 | source,
|
---|
127 | assetInfo,
|
---|
128 | sourceMap,
|
---|
129 | modules,
|
---|
130 | cacheItem
|
---|
131 | };
|
---|
132 | };
|
---|
133 |
|
---|
134 | class SourceMapDevToolPlugin {
|
---|
135 | /**
|
---|
136 | * @param {SourceMapDevToolPluginOptions} [options] options object
|
---|
137 | * @throws {Error} throws error, if got more than 1 arguments
|
---|
138 | */
|
---|
139 | constructor(options = {}) {
|
---|
140 | validate(options);
|
---|
141 |
|
---|
142 | this.sourceMapFilename = /** @type {string | false} */ (options.filename);
|
---|
143 | /** @type {false | TemplatePath}} */
|
---|
144 | this.sourceMappingURLComment =
|
---|
145 | options.append === false
|
---|
146 | ? false
|
---|
147 | : // eslint-disable-next-line no-useless-concat
|
---|
148 | options.append || "\n//# source" + "MappingURL=[url]";
|
---|
149 | /** @type {string | Function} */
|
---|
150 | this.moduleFilenameTemplate =
|
---|
151 | options.moduleFilenameTemplate || "webpack://[namespace]/[resourcePath]";
|
---|
152 | /** @type {string | Function} */
|
---|
153 | this.fallbackModuleFilenameTemplate =
|
---|
154 | options.fallbackModuleFilenameTemplate ||
|
---|
155 | "webpack://[namespace]/[resourcePath]?[hash]";
|
---|
156 | /** @type {string} */
|
---|
157 | this.namespace = options.namespace || "";
|
---|
158 | /** @type {SourceMapDevToolPluginOptions} */
|
---|
159 | this.options = options;
|
---|
160 | }
|
---|
161 |
|
---|
162 | /**
|
---|
163 | * Apply the plugin
|
---|
164 | * @param {Compiler} compiler compiler instance
|
---|
165 | * @returns {void}
|
---|
166 | */
|
---|
167 | apply(compiler) {
|
---|
168 | const outputFs = /** @type {OutputFileSystem} */ (
|
---|
169 | compiler.outputFileSystem
|
---|
170 | );
|
---|
171 | const sourceMapFilename = this.sourceMapFilename;
|
---|
172 | const sourceMappingURLComment = this.sourceMappingURLComment;
|
---|
173 | const moduleFilenameTemplate = this.moduleFilenameTemplate;
|
---|
174 | const namespace = this.namespace;
|
---|
175 | const fallbackModuleFilenameTemplate = this.fallbackModuleFilenameTemplate;
|
---|
176 | const requestShortener = compiler.requestShortener;
|
---|
177 | const options = this.options;
|
---|
178 | options.test = options.test || CSS_AND_JS_MODULE_EXTENSIONS_REGEXP;
|
---|
179 |
|
---|
180 | const matchObject = ModuleFilenameHelpers.matchObject.bind(
|
---|
181 | undefined,
|
---|
182 | options
|
---|
183 | );
|
---|
184 |
|
---|
185 | compiler.hooks.compilation.tap("SourceMapDevToolPlugin", compilation => {
|
---|
186 | new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation);
|
---|
187 |
|
---|
188 | compilation.hooks.processAssets.tapAsync(
|
---|
189 | {
|
---|
190 | name: "SourceMapDevToolPlugin",
|
---|
191 | stage: Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING,
|
---|
192 | additionalAssets: true
|
---|
193 | },
|
---|
194 | (assets, callback) => {
|
---|
195 | const chunkGraph = compilation.chunkGraph;
|
---|
196 | const cache = compilation.getCache("SourceMapDevToolPlugin");
|
---|
197 | /** @type {Map<string | Module, string>} */
|
---|
198 | const moduleToSourceNameMapping = new Map();
|
---|
199 | /**
|
---|
200 | * @type {Function}
|
---|
201 | * @returns {void}
|
---|
202 | */
|
---|
203 | const reportProgress =
|
---|
204 | ProgressPlugin.getReporter(compilation.compiler) || (() => {});
|
---|
205 |
|
---|
206 | /** @type {Map<string, Chunk>} */
|
---|
207 | const fileToChunk = new Map();
|
---|
208 | for (const chunk of compilation.chunks) {
|
---|
209 | for (const file of chunk.files) {
|
---|
210 | fileToChunk.set(file, chunk);
|
---|
211 | }
|
---|
212 | for (const file of chunk.auxiliaryFiles) {
|
---|
213 | fileToChunk.set(file, chunk);
|
---|
214 | }
|
---|
215 | }
|
---|
216 |
|
---|
217 | /** @type {string[]} */
|
---|
218 | const files = [];
|
---|
219 | for (const file of Object.keys(assets)) {
|
---|
220 | if (matchObject(file)) {
|
---|
221 | files.push(file);
|
---|
222 | }
|
---|
223 | }
|
---|
224 |
|
---|
225 | reportProgress(0);
|
---|
226 | /** @type {SourceMapTask[]} */
|
---|
227 | const tasks = [];
|
---|
228 | let fileIndex = 0;
|
---|
229 |
|
---|
230 | asyncLib.each(
|
---|
231 | files,
|
---|
232 | (file, callback) => {
|
---|
233 | const asset =
|
---|
234 | /** @type {Readonly<Asset>} */
|
---|
235 | (compilation.getAsset(file));
|
---|
236 | if (asset.info.related && asset.info.related.sourceMap) {
|
---|
237 | fileIndex++;
|
---|
238 | return callback();
|
---|
239 | }
|
---|
240 |
|
---|
241 | const chunk = fileToChunk.get(file);
|
---|
242 | const sourceMapNamespace = compilation.getPath(this.namespace, {
|
---|
243 | chunk
|
---|
244 | });
|
---|
245 |
|
---|
246 | const cacheItem = cache.getItemCache(
|
---|
247 | file,
|
---|
248 | cache.mergeEtags(
|
---|
249 | cache.getLazyHashedEtag(asset.source),
|
---|
250 | sourceMapNamespace
|
---|
251 | )
|
---|
252 | );
|
---|
253 |
|
---|
254 | cacheItem.get((err, cacheEntry) => {
|
---|
255 | if (err) {
|
---|
256 | return callback(err);
|
---|
257 | }
|
---|
258 | /**
|
---|
259 | * If presented in cache, reassigns assets. Cache assets already have source maps.
|
---|
260 | */
|
---|
261 | if (cacheEntry) {
|
---|
262 | const { assets, assetsInfo } = cacheEntry;
|
---|
263 | for (const cachedFile of Object.keys(assets)) {
|
---|
264 | if (cachedFile === file) {
|
---|
265 | compilation.updateAsset(
|
---|
266 | cachedFile,
|
---|
267 | assets[cachedFile],
|
---|
268 | assetsInfo[cachedFile]
|
---|
269 | );
|
---|
270 | } else {
|
---|
271 | compilation.emitAsset(
|
---|
272 | cachedFile,
|
---|
273 | assets[cachedFile],
|
---|
274 | assetsInfo[cachedFile]
|
---|
275 | );
|
---|
276 | }
|
---|
277 | /**
|
---|
278 | * Add file to chunk, if not presented there
|
---|
279 | */
|
---|
280 | if (cachedFile !== file && chunk !== undefined)
|
---|
281 | chunk.auxiliaryFiles.add(cachedFile);
|
---|
282 | }
|
---|
283 |
|
---|
284 | reportProgress(
|
---|
285 | (0.5 * ++fileIndex) / files.length,
|
---|
286 | file,
|
---|
287 | "restored cached SourceMap"
|
---|
288 | );
|
---|
289 |
|
---|
290 | return callback();
|
---|
291 | }
|
---|
292 |
|
---|
293 | reportProgress(
|
---|
294 | (0.5 * fileIndex) / files.length,
|
---|
295 | file,
|
---|
296 | "generate SourceMap"
|
---|
297 | );
|
---|
298 |
|
---|
299 | /** @type {SourceMapTask | undefined} */
|
---|
300 | const task = getTaskForFile(
|
---|
301 | file,
|
---|
302 | asset.source,
|
---|
303 | asset.info,
|
---|
304 | {
|
---|
305 | module: options.module,
|
---|
306 | columns: options.columns
|
---|
307 | },
|
---|
308 | compilation,
|
---|
309 | cacheItem
|
---|
310 | );
|
---|
311 |
|
---|
312 | if (task) {
|
---|
313 | const modules = task.modules;
|
---|
314 |
|
---|
315 | for (let idx = 0; idx < modules.length; idx++) {
|
---|
316 | const module = modules[idx];
|
---|
317 |
|
---|
318 | if (
|
---|
319 | typeof module === "string" &&
|
---|
320 | /^(data|https?):/.test(module)
|
---|
321 | ) {
|
---|
322 | moduleToSourceNameMapping.set(module, module);
|
---|
323 | continue;
|
---|
324 | }
|
---|
325 |
|
---|
326 | if (!moduleToSourceNameMapping.get(module)) {
|
---|
327 | moduleToSourceNameMapping.set(
|
---|
328 | module,
|
---|
329 | ModuleFilenameHelpers.createFilename(
|
---|
330 | module,
|
---|
331 | {
|
---|
332 | moduleFilenameTemplate,
|
---|
333 | namespace: sourceMapNamespace
|
---|
334 | },
|
---|
335 | {
|
---|
336 | requestShortener,
|
---|
337 | chunkGraph,
|
---|
338 | hashFunction: compilation.outputOptions.hashFunction
|
---|
339 | }
|
---|
340 | )
|
---|
341 | );
|
---|
342 | }
|
---|
343 | }
|
---|
344 |
|
---|
345 | tasks.push(task);
|
---|
346 | }
|
---|
347 |
|
---|
348 | reportProgress(
|
---|
349 | (0.5 * ++fileIndex) / files.length,
|
---|
350 | file,
|
---|
351 | "generated SourceMap"
|
---|
352 | );
|
---|
353 |
|
---|
354 | callback();
|
---|
355 | });
|
---|
356 | },
|
---|
357 | err => {
|
---|
358 | if (err) {
|
---|
359 | return callback(err);
|
---|
360 | }
|
---|
361 |
|
---|
362 | reportProgress(0.5, "resolve sources");
|
---|
363 | /** @type {Set<string>} */
|
---|
364 | const usedNamesSet = new Set(moduleToSourceNameMapping.values());
|
---|
365 | /** @type {Set<string>} */
|
---|
366 | const conflictDetectionSet = new Set();
|
---|
367 |
|
---|
368 | /**
|
---|
369 | * all modules in defined order (longest identifier first)
|
---|
370 | * @type {Array<string | Module>}
|
---|
371 | */
|
---|
372 | const allModules = Array.from(
|
---|
373 | moduleToSourceNameMapping.keys()
|
---|
374 | ).sort((a, b) => {
|
---|
375 | const ai = typeof a === "string" ? a : a.identifier();
|
---|
376 | const bi = typeof b === "string" ? b : b.identifier();
|
---|
377 | return ai.length - bi.length;
|
---|
378 | });
|
---|
379 |
|
---|
380 | // find modules with conflicting source names
|
---|
381 | for (let idx = 0; idx < allModules.length; idx++) {
|
---|
382 | const module = allModules[idx];
|
---|
383 | let sourceName =
|
---|
384 | /** @type {string} */
|
---|
385 | (moduleToSourceNameMapping.get(module));
|
---|
386 | let hasName = conflictDetectionSet.has(sourceName);
|
---|
387 | if (!hasName) {
|
---|
388 | conflictDetectionSet.add(sourceName);
|
---|
389 | continue;
|
---|
390 | }
|
---|
391 |
|
---|
392 | // try the fallback name first
|
---|
393 | sourceName = ModuleFilenameHelpers.createFilename(
|
---|
394 | module,
|
---|
395 | {
|
---|
396 | moduleFilenameTemplate: fallbackModuleFilenameTemplate,
|
---|
397 | namespace
|
---|
398 | },
|
---|
399 | {
|
---|
400 | requestShortener,
|
---|
401 | chunkGraph,
|
---|
402 | hashFunction: compilation.outputOptions.hashFunction
|
---|
403 | }
|
---|
404 | );
|
---|
405 | hasName = usedNamesSet.has(sourceName);
|
---|
406 | if (!hasName) {
|
---|
407 | moduleToSourceNameMapping.set(module, sourceName);
|
---|
408 | usedNamesSet.add(sourceName);
|
---|
409 | continue;
|
---|
410 | }
|
---|
411 |
|
---|
412 | // otherwise just append stars until we have a valid name
|
---|
413 | while (hasName) {
|
---|
414 | sourceName += "*";
|
---|
415 | hasName = usedNamesSet.has(sourceName);
|
---|
416 | }
|
---|
417 | moduleToSourceNameMapping.set(module, sourceName);
|
---|
418 | usedNamesSet.add(sourceName);
|
---|
419 | }
|
---|
420 |
|
---|
421 | let taskIndex = 0;
|
---|
422 |
|
---|
423 | asyncLib.each(
|
---|
424 | tasks,
|
---|
425 | (task, callback) => {
|
---|
426 | const assets = Object.create(null);
|
---|
427 | const assetsInfo = Object.create(null);
|
---|
428 | const file = task.file;
|
---|
429 | const chunk = fileToChunk.get(file);
|
---|
430 | const sourceMap = task.sourceMap;
|
---|
431 | const source = task.source;
|
---|
432 | const modules = task.modules;
|
---|
433 |
|
---|
434 | reportProgress(
|
---|
435 | 0.5 + (0.5 * taskIndex) / tasks.length,
|
---|
436 | file,
|
---|
437 | "attach SourceMap"
|
---|
438 | );
|
---|
439 |
|
---|
440 | const moduleFilenames = modules.map(m =>
|
---|
441 | moduleToSourceNameMapping.get(m)
|
---|
442 | );
|
---|
443 | sourceMap.sources = /** @type {string[]} */ (moduleFilenames);
|
---|
444 | if (options.noSources) {
|
---|
445 | sourceMap.sourcesContent = undefined;
|
---|
446 | }
|
---|
447 | sourceMap.sourceRoot = options.sourceRoot || "";
|
---|
448 | sourceMap.file = file;
|
---|
449 | const usesContentHash =
|
---|
450 | sourceMapFilename &&
|
---|
451 | CONTENT_HASH_DETECT_REGEXP.test(sourceMapFilename);
|
---|
452 |
|
---|
453 | resetRegexpState(CONTENT_HASH_DETECT_REGEXP);
|
---|
454 |
|
---|
455 | // If SourceMap and asset uses contenthash, avoid a circular dependency by hiding hash in `file`
|
---|
456 | if (usesContentHash && task.assetInfo.contenthash) {
|
---|
457 | const contenthash = task.assetInfo.contenthash;
|
---|
458 | const pattern = Array.isArray(contenthash)
|
---|
459 | ? contenthash.map(quoteMeta).join("|")
|
---|
460 | : quoteMeta(contenthash);
|
---|
461 | sourceMap.file = sourceMap.file.replace(
|
---|
462 | new RegExp(pattern, "g"),
|
---|
463 | m => "x".repeat(m.length)
|
---|
464 | );
|
---|
465 | }
|
---|
466 |
|
---|
467 | /** @type {false | TemplatePath} */
|
---|
468 | let currentSourceMappingURLComment = sourceMappingURLComment;
|
---|
469 | const cssExtensionDetected =
|
---|
470 | CSS_EXTENSION_DETECT_REGEXP.test(file);
|
---|
471 | resetRegexpState(CSS_EXTENSION_DETECT_REGEXP);
|
---|
472 | if (
|
---|
473 | currentSourceMappingURLComment !== false &&
|
---|
474 | typeof currentSourceMappingURLComment !== "function" &&
|
---|
475 | cssExtensionDetected
|
---|
476 | ) {
|
---|
477 | currentSourceMappingURLComment =
|
---|
478 | currentSourceMappingURLComment.replace(
|
---|
479 | URL_FORMATTING_REGEXP,
|
---|
480 | "\n/*$1*/"
|
---|
481 | );
|
---|
482 | }
|
---|
483 |
|
---|
484 | if (options.debugIds) {
|
---|
485 | const debugId = generateDebugId(source, sourceMap.file);
|
---|
486 | sourceMap.debugId = debugId;
|
---|
487 | currentSourceMappingURLComment = `\n//# debugId=${debugId}${currentSourceMappingURLComment}`;
|
---|
488 | }
|
---|
489 |
|
---|
490 | const sourceMapString = JSON.stringify(sourceMap);
|
---|
491 | if (sourceMapFilename) {
|
---|
492 | const filename = file;
|
---|
493 | const sourceMapContentHash =
|
---|
494 | /** @type {string} */
|
---|
495 | (
|
---|
496 | usesContentHash &&
|
---|
497 | createHash(
|
---|
498 | /** @type {Algorithm} */
|
---|
499 | (compilation.outputOptions.hashFunction)
|
---|
500 | )
|
---|
501 | .update(sourceMapString)
|
---|
502 | .digest("hex")
|
---|
503 | );
|
---|
504 | const pathParams = {
|
---|
505 | chunk,
|
---|
506 | filename: options.fileContext
|
---|
507 | ? relative(
|
---|
508 | outputFs,
|
---|
509 | `/${options.fileContext}`,
|
---|
510 | `/${filename}`
|
---|
511 | )
|
---|
512 | : filename,
|
---|
513 | contentHash: sourceMapContentHash
|
---|
514 | };
|
---|
515 | const { path: sourceMapFile, info: sourceMapInfo } =
|
---|
516 | compilation.getPathWithInfo(
|
---|
517 | sourceMapFilename,
|
---|
518 | pathParams
|
---|
519 | );
|
---|
520 | const sourceMapUrl = options.publicPath
|
---|
521 | ? options.publicPath + sourceMapFile
|
---|
522 | : relative(
|
---|
523 | outputFs,
|
---|
524 | dirname(outputFs, `/${file}`),
|
---|
525 | `/${sourceMapFile}`
|
---|
526 | );
|
---|
527 | /** @type {Source} */
|
---|
528 | let asset = new RawSource(source);
|
---|
529 | if (currentSourceMappingURLComment !== false) {
|
---|
530 | // Add source map url to compilation asset, if currentSourceMappingURLComment is set
|
---|
531 | asset = new ConcatSource(
|
---|
532 | asset,
|
---|
533 | compilation.getPath(currentSourceMappingURLComment, {
|
---|
534 | url: sourceMapUrl,
|
---|
535 | ...pathParams
|
---|
536 | })
|
---|
537 | );
|
---|
538 | }
|
---|
539 | const assetInfo = {
|
---|
540 | related: { sourceMap: sourceMapFile }
|
---|
541 | };
|
---|
542 | assets[file] = asset;
|
---|
543 | assetsInfo[file] = assetInfo;
|
---|
544 | compilation.updateAsset(file, asset, assetInfo);
|
---|
545 | // Add source map file to compilation assets and chunk files
|
---|
546 | const sourceMapAsset = new RawSource(sourceMapString);
|
---|
547 | const sourceMapAssetInfo = {
|
---|
548 | ...sourceMapInfo,
|
---|
549 | development: true
|
---|
550 | };
|
---|
551 | assets[sourceMapFile] = sourceMapAsset;
|
---|
552 | assetsInfo[sourceMapFile] = sourceMapAssetInfo;
|
---|
553 | compilation.emitAsset(
|
---|
554 | sourceMapFile,
|
---|
555 | sourceMapAsset,
|
---|
556 | sourceMapAssetInfo
|
---|
557 | );
|
---|
558 | if (chunk !== undefined)
|
---|
559 | chunk.auxiliaryFiles.add(sourceMapFile);
|
---|
560 | } else {
|
---|
561 | if (currentSourceMappingURLComment === false) {
|
---|
562 | throw new Error(
|
---|
563 | "SourceMapDevToolPlugin: append can't be false when no filename is provided"
|
---|
564 | );
|
---|
565 | }
|
---|
566 | if (typeof currentSourceMappingURLComment === "function") {
|
---|
567 | throw new Error(
|
---|
568 | "SourceMapDevToolPlugin: append can't be a function when no filename is provided"
|
---|
569 | );
|
---|
570 | }
|
---|
571 | /**
|
---|
572 | * Add source map as data url to asset
|
---|
573 | */
|
---|
574 | const asset = new ConcatSource(
|
---|
575 | new RawSource(source),
|
---|
576 | currentSourceMappingURLComment
|
---|
577 | .replace(MAP_URL_COMMENT_REGEXP, () => sourceMapString)
|
---|
578 | .replace(
|
---|
579 | URL_COMMENT_REGEXP,
|
---|
580 | () =>
|
---|
581 | `data:application/json;charset=utf-8;base64,${Buffer.from(
|
---|
582 | sourceMapString,
|
---|
583 | "utf-8"
|
---|
584 | ).toString("base64")}`
|
---|
585 | )
|
---|
586 | );
|
---|
587 | assets[file] = asset;
|
---|
588 | assetsInfo[file] = undefined;
|
---|
589 | compilation.updateAsset(file, asset);
|
---|
590 | }
|
---|
591 |
|
---|
592 | task.cacheItem.store({ assets, assetsInfo }, err => {
|
---|
593 | reportProgress(
|
---|
594 | 0.5 + (0.5 * ++taskIndex) / tasks.length,
|
---|
595 | task.file,
|
---|
596 | "attached SourceMap"
|
---|
597 | );
|
---|
598 |
|
---|
599 | if (err) {
|
---|
600 | return callback(err);
|
---|
601 | }
|
---|
602 | callback();
|
---|
603 | });
|
---|
604 | },
|
---|
605 | err => {
|
---|
606 | reportProgress(1);
|
---|
607 | callback(err);
|
---|
608 | }
|
---|
609 | );
|
---|
610 | }
|
---|
611 | );
|
---|
612 | }
|
---|
613 | );
|
---|
614 | });
|
---|
615 | }
|
---|
616 | }
|
---|
617 |
|
---|
618 | module.exports = SourceMapDevToolPlugin;
|
---|