mirror of https://github.com/webpack/webpack.git
feat: add `extractSourceMap` option to implement the capabilities of loading source maps by comment
This commit is contained in:
parent
bb98bb1470
commit
64ce283d76
|
@ -316,7 +316,8 @@
|
|||
"Nitin",
|
||||
"Kumar",
|
||||
"spacek",
|
||||
"thelarkinn"
|
||||
"thelarkinn",
|
||||
"behaviour"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"/Author.+/",
|
||||
|
|
|
@ -1467,6 +1467,10 @@ export interface RuleSetRule {
|
|||
* Shortcut for resource.exclude.
|
||||
*/
|
||||
exclude?: RuleSetConditionOrConditionsAbsolute;
|
||||
/**
|
||||
* Enable/Disable extracting source map.
|
||||
*/
|
||||
extractSourceMap?: boolean;
|
||||
/**
|
||||
* The options for the module generator.
|
||||
*/
|
||||
|
|
|
@ -101,6 +101,7 @@ const memoize = require("./util/memoize");
|
|||
/** @typedef {import("./util/identifier").AssociatedObjectForCache} AssociatedObjectForCache */
|
||||
/** @typedef {import("./dependencies/HarmonyImportSideEffectDependency")} HarmonyImportSideEffectDependency */
|
||||
/** @typedef {import("./dependencies/HarmonyImportSpecifierDependency")} HarmonyImportSpecifierDependency */
|
||||
/** @typedef {import("../declarations/WebpackOptions").RuleSetRule["extractSourceMap"]} ExtractSourceMapOptions */
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {import("./util/deprecation").FakeHook<T>} FakeHook
|
||||
|
@ -122,6 +123,9 @@ const memoize = require("./util/memoize");
|
|||
const getInvalidDependenciesModuleWarning = memoize(() =>
|
||||
require("./InvalidDependenciesModuleWarning")
|
||||
);
|
||||
|
||||
const getExtractSourceMap = memoize(() => require("./util/extractSourceMap"));
|
||||
|
||||
const getValidate = memoize(() => require("schema-utils").validate);
|
||||
|
||||
const ABSOLUTE_PATH_REGEX = /^([a-zA-Z]:\\|\\\\|\/)/;
|
||||
|
@ -254,6 +258,7 @@ makeSerializable(
|
|||
* @property {Generator} generator the generator used
|
||||
* @property {GeneratorOptions=} generatorOptions the options of the generator used
|
||||
* @property {ResolveOptions=} resolveOptions options used for resolving requests from this module
|
||||
* @property {boolean=} extractSourceMap enable/disable extracting source map
|
||||
*/
|
||||
|
||||
/** @type {WeakMap<Compilation, NormalModuleCompilationHooks>} */
|
||||
|
@ -341,7 +346,8 @@ class NormalModule extends Module {
|
|||
parserOptions,
|
||||
generator,
|
||||
generatorOptions,
|
||||
resolveOptions
|
||||
resolveOptions,
|
||||
extractSourceMap
|
||||
}) {
|
||||
super(type, context || getContext(resource), layer);
|
||||
|
||||
|
@ -373,6 +379,8 @@ class NormalModule extends Module {
|
|||
// already declared in super class
|
||||
this.resolveOptions = resolveOptions;
|
||||
}
|
||||
/** @type {ExtractSourceMapOptions} */
|
||||
this.extractSourceMap = extractSourceMap;
|
||||
|
||||
// Info from Build
|
||||
/** @type {WebpackError | null} */
|
||||
|
@ -1004,14 +1012,14 @@ class NormalModule extends Module {
|
|||
/**
|
||||
* @param {LoaderContext<EXPECTED_ANY>} loaderContext the loader context
|
||||
* @param {string} resourcePath the resource Path
|
||||
* @param {(err: Error | null, result?: string | Buffer) => void} callback callback
|
||||
* @param {(err: Error | null, result?: string | Buffer, sourceMap?: Result[1]) => void} callback callback
|
||||
*/
|
||||
processResource: (loaderContext, resourcePath, callback) => {
|
||||
const resource = loaderContext.resource;
|
||||
const scheme = getScheme(resource);
|
||||
hooks.readResource
|
||||
.for(scheme)
|
||||
.callAsync(loaderContext, (err, result) => {
|
||||
.callAsync(loaderContext, async (err, result) => {
|
||||
if (err) return callback(err);
|
||||
if (typeof result !== "string" && !result) {
|
||||
return callback(
|
||||
|
@ -1022,6 +1030,24 @@ class NormalModule extends Module {
|
|||
)
|
||||
);
|
||||
}
|
||||
if (
|
||||
this.extractSourceMap &&
|
||||
(this.useSourceMap || this.useSimpleSourceMap)
|
||||
) {
|
||||
try {
|
||||
const { source, sourceMap, fileDependencies } =
|
||||
await getExtractSourceMap()(result, resourcePath, fs);
|
||||
if (this.buildInfo && this.buildInfo.fileDependencies) {
|
||||
this.buildInfo.fileDependencies.addAll(fileDependencies);
|
||||
}
|
||||
return callback(null, source, sourceMap);
|
||||
} catch (err) {
|
||||
this.addWarning(
|
||||
new ModuleWarning(/** @type {Error} */ (err))
|
||||
);
|
||||
return callback(null, result);
|
||||
}
|
||||
}
|
||||
return callback(null, result);
|
||||
});
|
||||
}
|
||||
|
@ -1654,6 +1680,7 @@ class NormalModule extends Module {
|
|||
write(this._lastSuccessfulBuildMeta);
|
||||
write(this._forceBuild);
|
||||
write(this._codeGeneratorData);
|
||||
write(this.extractSourceMap);
|
||||
super.serialize(context);
|
||||
}
|
||||
|
||||
|
@ -1694,6 +1721,7 @@ class NormalModule extends Module {
|
|||
this._lastSuccessfulBuildMeta = read();
|
||||
this._forceBuild = read();
|
||||
this._codeGeneratorData = read();
|
||||
this.extractSourceMap = read();
|
||||
super.deserialize(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ const {
|
|||
* @typedef {import("./Compiler").Callback<T>} Callback
|
||||
*/
|
||||
|
||||
/** @typedef {Pick<RuleSetRule, 'type' | 'sideEffects' | 'parser' | 'generator' | 'resolve' | 'layer'>} ModuleSettings */
|
||||
/** @typedef {Pick<RuleSetRule, 'type' | 'sideEffects' | 'parser' | 'generator' | 'resolve' | 'layer' | 'extractSourceMap'>} ModuleSettings */
|
||||
/** @typedef {Partial<NormalModuleCreateData & { settings: ModuleSettings }>} CreateData */
|
||||
|
||||
/**
|
||||
|
@ -246,6 +246,7 @@ const ruleSetCompiler = new RuleSetCompiler([
|
|||
new BasicEffectRulePlugin("resolve"),
|
||||
new BasicEffectRulePlugin("generator"),
|
||||
new BasicEffectRulePlugin("layer"),
|
||||
new BasicEffectRulePlugin("extractSourceMap"),
|
||||
new UseEffectRulePlugin()
|
||||
]);
|
||||
|
||||
|
@ -714,7 +715,8 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
parserOptions: settings.parser,
|
||||
generator: this.getGenerator(type, settings.generator),
|
||||
generatorOptions: settings.generator,
|
||||
resolveOptions
|
||||
resolveOptions,
|
||||
extractSourceMap: settings.extractSourceMap || false
|
||||
});
|
||||
} catch (createDataErr) {
|
||||
return callback(/** @type {Error} */ (createDataErr));
|
||||
|
|
|
@ -6,37 +6,10 @@
|
|||
"use strict";
|
||||
|
||||
const NormalModule = require("../NormalModule");
|
||||
const { URIRegEx, decodeDataURI } = require("../util/dataURL");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
// data URL scheme: "data:text/javascript;charset=utf-8;base64,some-string"
|
||||
// http://www.ietf.org/rfc/rfc2397.txt
|
||||
const URIRegEx = /^data:([^;,]+)?((?:;[^;,]+)*?)(?:;(base64)?)?,(.*)$/i;
|
||||
|
||||
/**
|
||||
* @param {string} uri data URI
|
||||
* @returns {Buffer | null} decoded data
|
||||
*/
|
||||
const decodeDataURI = (uri) => {
|
||||
const match = URIRegEx.exec(uri);
|
||||
if (!match) return null;
|
||||
|
||||
const isBase64 = match[3];
|
||||
const body = match[4];
|
||||
|
||||
if (isBase64) {
|
||||
return Buffer.from(body, "base64");
|
||||
}
|
||||
|
||||
// CSS allows to use `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" style="stroke: rgb(223,224,225); stroke-width: 2px; fill: none; stroke-dasharray: 6px 3px" /></svg>`
|
||||
// so we return original body if we can't `decodeURIComponent`
|
||||
try {
|
||||
return Buffer.from(decodeURIComponent(body), "ascii");
|
||||
} catch (_) {
|
||||
return Buffer.from(body, "ascii");
|
||||
}
|
||||
};
|
||||
|
||||
const PLUGIN_NAME = "DataUriPlugin";
|
||||
|
||||
class DataUriPlugin {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Natsu @xiaoxiaojx
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// data URL scheme: "data:text/javascript;charset=utf-8;base64,some-string"
|
||||
// http://www.ietf.org/rfc/rfc2397.txt
|
||||
const URIRegEx = /^data:([^;,]+)?((?:;[^;,]+)*?)(?:;(base64)?)?,(.*)$/i;
|
||||
|
||||
/**
|
||||
* @param {string} uri data URI
|
||||
* @returns {Buffer | null} decoded data
|
||||
*/
|
||||
const decodeDataURI = (uri) => {
|
||||
const match = URIRegEx.exec(uri);
|
||||
if (!match) return null;
|
||||
|
||||
const isBase64 = match[3];
|
||||
const body = match[4];
|
||||
|
||||
if (isBase64) {
|
||||
return Buffer.from(body, "base64");
|
||||
}
|
||||
|
||||
// CSS allows to use `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" style="stroke: rgb(223,224,225); stroke-width: 2px; fill: none; stroke-dasharray: 6px 3px" /></svg>`
|
||||
// so we return original body if we can't `decodeURIComponent`
|
||||
try {
|
||||
return Buffer.from(decodeURIComponent(body), "ascii");
|
||||
} catch (_) {
|
||||
return Buffer.from(body, "ascii");
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
URIRegEx,
|
||||
decodeDataURI
|
||||
};
|
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Natsu @xiaoxiaojx
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const path = require("path");
|
||||
const urlUtils = require("url");
|
||||
const { decodeDataURI } = require("./dataURL");
|
||||
const { isAbsolute, join } = require("./fs");
|
||||
|
||||
/** @typedef {import("../../declarations/WebpackOptions").RuleSetRule["extractSourceMap"]} ExtractSourceMapOptions */
|
||||
/** @typedef {import("./fs").InputFileSystem} InputFileSystem */
|
||||
|
||||
/**
|
||||
* @typedef {(input: string | Buffer<ArrayBufferLike>, resourcePath: string, fs: InputFileSystem) => Promise<{source: string | Buffer<ArrayBufferLike>, sourceMap: string | RawSourceMap | undefined, fileDependencies: string[]}>} SourceMapExtractorFunction
|
||||
*/
|
||||
|
||||
/** @typedef {import("webpack-sources").RawSourceMap} RawSourceMap */
|
||||
|
||||
/**
|
||||
* @typedef {object} SourceMappingURL
|
||||
* @property {string} sourceMappingURL
|
||||
* @property {string} replacementString
|
||||
*/
|
||||
|
||||
// Matches only the last occurrence of sourceMappingURL
|
||||
const innerRegex = /\s*[#@]\s*sourceMappingURL\s*=\s*([^\s'"]*)\s*/;
|
||||
|
||||
const validProtocolPattern = /^[a-z][a-z0-9+.-]*:/i;
|
||||
|
||||
const sourceMappingURLRegex = new RegExp(
|
||||
"(?:" +
|
||||
"/\\*" +
|
||||
"(?:\\s*\r?\n(?://)?)?" +
|
||||
`(?:${innerRegex.source})` +
|
||||
"\\s*" +
|
||||
"\\*/" +
|
||||
"|" +
|
||||
`//(?:${innerRegex.source})` +
|
||||
")" +
|
||||
"\\s*"
|
||||
);
|
||||
|
||||
/**
|
||||
* Extract source mapping URL from code comments
|
||||
* @param {string} code source code content
|
||||
* @returns {SourceMappingURL} source mapping information
|
||||
*/
|
||||
function getSourceMappingURL(code) {
|
||||
const lines = code.split(/^/m);
|
||||
let match;
|
||||
|
||||
for (let i = lines.length - 1; i >= 0; i--) {
|
||||
match = lines[i].match(sourceMappingURLRegex);
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const sourceMappingURL = match ? match[1] || match[2] || "" : "";
|
||||
|
||||
return {
|
||||
sourceMappingURL: sourceMappingURL
|
||||
? decodeURI(sourceMappingURL)
|
||||
: sourceMappingURL,
|
||||
replacementString: match ? match[0] : ""
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get absolute path for source file
|
||||
* @param {InputFileSystem} fs file system
|
||||
* @param {string} context context directory
|
||||
* @param {string} request file request
|
||||
* @param {string} sourceRoot source root directory
|
||||
* @returns {string} absolute path
|
||||
*/
|
||||
function getAbsolutePath(fs, context, request, sourceRoot) {
|
||||
if (sourceRoot) {
|
||||
if (isAbsolute(sourceRoot)) {
|
||||
return join(fs, sourceRoot, request);
|
||||
}
|
||||
|
||||
return join(fs, join(fs, context, sourceRoot), request);
|
||||
}
|
||||
|
||||
return join(fs, context, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if value is a URL
|
||||
* @param {string} value string to check
|
||||
* @returns {boolean} true if value is a URL
|
||||
*/
|
||||
function isURL(value) {
|
||||
return validProtocolPattern.test(value) && !path.win32.isAbsolute(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch source content from data URL
|
||||
* @param {InputFileSystem} fs file system
|
||||
* @param {string} sourceURL data URL
|
||||
* @returns {string} source content promise
|
||||
*/
|
||||
function fetchFromDataURL(fs, sourceURL) {
|
||||
const content = decodeDataURI(sourceURL);
|
||||
|
||||
if (content) {
|
||||
return content.toString("utf8");
|
||||
}
|
||||
|
||||
throw new Error(`Failed to parse source map from "data" URL: ${sourceURL}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch source content from file system
|
||||
* @param {InputFileSystem} fs file system
|
||||
* @param {string} sourceURL file URL
|
||||
* @returns {Promise<{path: string, data?: string}>} source content promise
|
||||
*/
|
||||
async function fetchFromFilesystem(fs, sourceURL) {
|
||||
let buffer;
|
||||
|
||||
if (isURL(sourceURL)) {
|
||||
return { path: sourceURL };
|
||||
}
|
||||
|
||||
try {
|
||||
buffer = await new Promise((resolve, reject) => {
|
||||
fs.readFile(
|
||||
sourceURL,
|
||||
(
|
||||
/** @type {Error | null} */ error,
|
||||
/** @type {Buffer<ArrayBufferLike> | undefined} */ data
|
||||
) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
return resolve(data);
|
||||
}
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to parse source map from '${sourceURL}' file: ${error}`
|
||||
);
|
||||
}
|
||||
|
||||
return { path: sourceURL, data: buffer.toString() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch from multiple possible file paths
|
||||
* @param {InputFileSystem} fs file system
|
||||
* @param {string[]} possibleRequests array of possible file paths
|
||||
* @param {string} errorsAccumulator accumulated error messages
|
||||
* @returns {Promise<{path: string, data?: string}>} source content promise
|
||||
*/
|
||||
async function fetchPathsFromFilesystem(
|
||||
fs,
|
||||
possibleRequests,
|
||||
errorsAccumulator = ""
|
||||
) {
|
||||
let result;
|
||||
|
||||
try {
|
||||
result = await fetchFromFilesystem(fs, possibleRequests[0]);
|
||||
} catch (error) {
|
||||
errorsAccumulator += `${/** @type {Error} */ (error).message}\n\n`;
|
||||
|
||||
const [, ...tailPossibleRequests] = possibleRequests;
|
||||
|
||||
if (tailPossibleRequests.length === 0) {
|
||||
/** @type {Error} */ (error).message = errorsAccumulator;
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
return fetchPathsFromFilesystem(
|
||||
fs,
|
||||
tailPossibleRequests,
|
||||
errorsAccumulator
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch source content from URL
|
||||
* @param {InputFileSystem} fs file system
|
||||
* @param {string} context context directory
|
||||
* @param {string} url source URL
|
||||
* @param {string=} sourceRoot source root directory
|
||||
* @param {boolean=} skipReading whether to skip reading file content
|
||||
* @returns {Promise<{sourceURL: string, sourceContent?: string}>} source content promise
|
||||
*/
|
||||
async function fetchFromURL(fs, context, url, sourceRoot, skipReading = false) {
|
||||
// 1. It's an absolute url and it is not `windows` path like `C:\dir\file`
|
||||
if (isURL(url)) {
|
||||
// eslint-disable-next-line n/no-deprecated-api
|
||||
const { protocol } = urlUtils.parse(url);
|
||||
|
||||
if (protocol === "data:") {
|
||||
if (skipReading) {
|
||||
return { sourceURL: "" };
|
||||
}
|
||||
|
||||
const sourceContent = fetchFromDataURL(fs, url);
|
||||
|
||||
return { sourceURL: "", sourceContent };
|
||||
}
|
||||
|
||||
if (skipReading) {
|
||||
return { sourceURL: url };
|
||||
}
|
||||
|
||||
if (protocol === "file:") {
|
||||
const pathFromURL = urlUtils.fileURLToPath(url);
|
||||
const sourceURL = path.normalize(pathFromURL);
|
||||
const { data: sourceContent } = await fetchFromFilesystem(fs, sourceURL);
|
||||
|
||||
return { sourceURL, sourceContent };
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Failed to parse source map: '${url}' URL is not supported`
|
||||
);
|
||||
}
|
||||
|
||||
// 2. It's a scheme-relative
|
||||
if (/^\/\//.test(url)) {
|
||||
throw new Error(
|
||||
`Failed to parse source map: '${url}' URL is not supported`
|
||||
);
|
||||
}
|
||||
|
||||
// 3. Absolute path
|
||||
if (isAbsolute(url)) {
|
||||
let sourceURL = path.normalize(url);
|
||||
|
||||
let sourceContent;
|
||||
|
||||
if (!skipReading) {
|
||||
const possibleRequests = [sourceURL];
|
||||
|
||||
if (url.startsWith("/")) {
|
||||
possibleRequests.push(
|
||||
getAbsolutePath(fs, context, sourceURL.slice(1), sourceRoot || "")
|
||||
);
|
||||
}
|
||||
|
||||
const result = await fetchPathsFromFilesystem(fs, possibleRequests);
|
||||
|
||||
sourceURL = result.path;
|
||||
sourceContent = result.data;
|
||||
}
|
||||
|
||||
return { sourceURL, sourceContent };
|
||||
}
|
||||
|
||||
// 4. Relative path
|
||||
const sourceURL = getAbsolutePath(fs, context, url, sourceRoot || "");
|
||||
|
||||
let sourceContent;
|
||||
|
||||
if (!skipReading) {
|
||||
const { data } = await fetchFromFilesystem(fs, sourceURL);
|
||||
|
||||
sourceContent = data;
|
||||
}
|
||||
|
||||
return { sourceURL, sourceContent };
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract source map from code content
|
||||
* @param {string | Buffer<ArrayBufferLike>} stringOrBuffer The input code content as string or buffer
|
||||
* @param {string} resourcePath The path to the resource file
|
||||
* @param {InputFileSystem} fs The file system interface for reading files
|
||||
* @returns {Promise<{source: string | Buffer<ArrayBufferLike>, sourceMap: string | RawSourceMap | undefined, fileDependencies: string[]}>} Promise resolving to extracted source map information
|
||||
*/
|
||||
async function extractSourceMap(stringOrBuffer, resourcePath, fs) {
|
||||
const input =
|
||||
typeof stringOrBuffer === "string"
|
||||
? stringOrBuffer
|
||||
: stringOrBuffer.toString("utf8");
|
||||
const inputSourceMap = undefined;
|
||||
const output = {
|
||||
source: stringOrBuffer,
|
||||
sourceMap: inputSourceMap,
|
||||
fileDependencies: /** @type {string[]} */ ([])
|
||||
};
|
||||
const { sourceMappingURL, replacementString } = getSourceMappingURL(input);
|
||||
|
||||
if (!sourceMappingURL) {
|
||||
return output;
|
||||
}
|
||||
|
||||
const baseContext = path.dirname(resourcePath);
|
||||
|
||||
const { sourceURL, sourceContent } = await fetchFromURL(
|
||||
fs,
|
||||
baseContext,
|
||||
sourceMappingURL
|
||||
);
|
||||
|
||||
if (sourceURL) {
|
||||
output.fileDependencies.push(/** @type {string} */ (sourceURL));
|
||||
}
|
||||
|
||||
if (!sourceContent) {
|
||||
return output;
|
||||
}
|
||||
|
||||
/** @type {RawSourceMap} */
|
||||
const map = JSON.parse(sourceContent.replace(/^\)\]\}'/, ""));
|
||||
|
||||
const context = sourceURL ? path.dirname(sourceURL) : baseContext;
|
||||
|
||||
const resolvedSources = await Promise.all(
|
||||
map.sources.map(
|
||||
async (/** @type {string} */ source, /** @type {number} */ i) => {
|
||||
const originalSourceContent =
|
||||
map.sourcesContent &&
|
||||
typeof map.sourcesContent[i] !== "undefined" &&
|
||||
map.sourcesContent[i] !== null
|
||||
? map.sourcesContent[i]
|
||||
: undefined;
|
||||
const skipReading = typeof originalSourceContent !== "undefined";
|
||||
// We do not skipReading here, because we need absolute paths in sources.
|
||||
// This is necessary so that for sourceMaps with the same file structure in sources, name collisions do not occur.
|
||||
// https://github.com/webpack-contrib/source-map-loader/issues/51
|
||||
let { sourceURL, sourceContent } = await fetchFromURL(
|
||||
fs,
|
||||
context,
|
||||
source,
|
||||
map.sourceRoot,
|
||||
skipReading
|
||||
);
|
||||
|
||||
if (skipReading) {
|
||||
sourceContent = originalSourceContent;
|
||||
} else if (sourceURL && !isURL(sourceURL)) {
|
||||
output.fileDependencies.push(/** @type {string} */ (sourceURL));
|
||||
}
|
||||
|
||||
// Return original value of `source` when error happens
|
||||
return { sourceURL, sourceContent };
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
/** @type {RawSourceMap} */
|
||||
const newMap = { ...map };
|
||||
|
||||
newMap.sources = [];
|
||||
newMap.sourcesContent = [];
|
||||
|
||||
delete newMap.sourceRoot;
|
||||
|
||||
for (const source of resolvedSources) {
|
||||
const { sourceURL, sourceContent } = source;
|
||||
|
||||
newMap.sources.push(sourceURL || "");
|
||||
newMap.sourcesContent.push(sourceContent || "");
|
||||
}
|
||||
|
||||
const sourcesContentIsEmpty =
|
||||
newMap.sourcesContent.filter(Boolean).length === 0;
|
||||
|
||||
if (sourcesContentIsEmpty) {
|
||||
delete newMap.sourcesContent;
|
||||
}
|
||||
|
||||
return {
|
||||
source: input.replace(replacementString, ""),
|
||||
sourceMap: /** @type {RawSourceMap} */ (newMap),
|
||||
fileDependencies: output.fileDependencies
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = extractSourceMap;
|
||||
module.exports.getSourceMappingURL = getSourceMappingURL;
|
|
@ -649,7 +649,15 @@ const lstatReadlinkAbsolute = (fs, p, callback) => {
|
|||
doReadLink();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} pathname a path
|
||||
* @returns {boolean} is absolute
|
||||
*/
|
||||
const isAbsolute = (pathname) =>
|
||||
path.posix.isAbsolute(pathname) || path.win32.isAbsolute(pathname);
|
||||
|
||||
module.exports.dirname = dirname;
|
||||
module.exports.isAbsolute = isAbsolute;
|
||||
module.exports.join = join;
|
||||
module.exports.lstatReadlinkAbsolute = lstatReadlinkAbsolute;
|
||||
module.exports.mkdirp = mkdirp;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -4734,6 +4734,10 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"extractSourceMap": {
|
||||
"description": "Enable/Disable extracting source map.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"generator": {
|
||||
"description": "The options for the module generator.",
|
||||
"type": "object"
|
||||
|
|
|
@ -212,7 +212,7 @@ describe("Validation", () => {
|
|||
expect(msg).toMatchInlineSnapshot(`
|
||||
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
|
||||
- configuration.module.rules[0].oneOf[0] has an unknown property 'passer'. These properties are valid:
|
||||
object { assert?, compiler?, dependency?, descriptionData?, enforce?, exclude?, generator?, include?, issuer?, issuerLayer?, layer?, loader?, mimetype?, oneOf?, options?, parser?, realResource?, resolve?, resource?, resourceFragment?, resourceQuery?, rules?, scheme?, sideEffects?, test?, type?, use?, with? }
|
||||
object { assert?, compiler?, dependency?, descriptionData?, enforce?, exclude?, extractSourceMap?, generator?, include?, issuer?, issuerLayer?, layer?, loader?, mimetype?, oneOf?, options?, parser?, realResource?, resolve?, resource?, resourceFragment?, resourceQuery?, rules?, scheme?, sideEffects?, test?, type?, use?, with? }
|
||||
-> A rule description with conditions and effects for modules."
|
||||
`)
|
||||
);
|
||||
|
|
|
@ -4748,6 +4748,19 @@ Object {
|
|||
"multiple": true,
|
||||
"simpleType": "string",
|
||||
},
|
||||
"module-rules-extract-source-map": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Enable/Disable extracting source map.",
|
||||
"multiple": true,
|
||||
"path": "module.rules[].extractSourceMap",
|
||||
"type": "boolean",
|
||||
},
|
||||
],
|
||||
"description": "Enable/Disable extracting source map.",
|
||||
"multiple": true,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"module-rules-include": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
|
|
|
@ -11332,3 +11332,65 @@ const __webpack_exports__a = __webpack_exports__.a;
|
|||
export { __webpack_exports__HomeLayout as HomeLayout, __webpack_exports__a as a };
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ConfigCacheTestCases source-map extract-source-map exported tests should extract source map - 1 1`] = `
|
||||
Array [
|
||||
"webpack:///./external-source-map.txt",
|
||||
"webpack:///external node-commonjs \\"fs\\"",
|
||||
"webpack:///external node-commonjs \\"path\\"",
|
||||
"webpack:///webpack/bootstrap",
|
||||
"webpack:///./extract2.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ConfigCacheTestCases source-map extract-source-map exported tests should extract source map - 2 1`] = `
|
||||
Array [
|
||||
"webpack:///./external-source-map.txt",
|
||||
"webpack:///external node-commonjs \\"fs\\"",
|
||||
"webpack:///external node-commonjs \\"path\\"",
|
||||
"webpack:///webpack/bootstrap",
|
||||
"webpack:///./extract3.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ConfigCacheTestCases source-map extract-source-map exported tests should extract source map - 3 1`] = `
|
||||
Array [
|
||||
"webpack:///./external-source-map.txt",
|
||||
"webpack:///external node-commonjs \\"fs\\"",
|
||||
"webpack:///external node-commonjs \\"path\\"",
|
||||
"webpack:///webpack/bootstrap",
|
||||
"webpack:///./extract3.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ConfigCacheTestCases source-map extract-source-map-css exported tests should compile 1`] = `
|
||||
Array [
|
||||
"/*!*********************!*\\\\
|
||||
!*** css ./app.css ***!
|
||||
\\\\*********************/
|
||||
* {
|
||||
box-sizing: border-box; }
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
margin-right: -15px;
|
||||
margin-left: -15px; }
|
||||
|
||||
.col-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
height: 50px;
|
||||
background: coral; }
|
||||
|
||||
.col-s3 {
|
||||
flex: 0 1 25%;
|
||||
padding: 0 15px; }
|
||||
|
||||
|
||||
|
||||
|
||||
/*# sourceMappingURL=bundle0.css.map*/",
|
||||
]
|
||||
`;
|
||||
|
|
|
@ -10444,3 +10444,65 @@ const __webpack_exports__a = __webpack_exports__.a;
|
|||
export { __webpack_exports__HomeLayout as HomeLayout, __webpack_exports__a as a };
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ConfigTestCases source-map extract-source-map exported tests should extract source map - 1 1`] = `
|
||||
Array [
|
||||
"webpack:///./external-source-map.txt",
|
||||
"webpack:///external node-commonjs \\"fs\\"",
|
||||
"webpack:///external node-commonjs \\"path\\"",
|
||||
"webpack:///webpack/bootstrap",
|
||||
"webpack:///./extract2.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ConfigTestCases source-map extract-source-map exported tests should extract source map - 2 1`] = `
|
||||
Array [
|
||||
"webpack:///./external-source-map.txt",
|
||||
"webpack:///external node-commonjs \\"fs\\"",
|
||||
"webpack:///external node-commonjs \\"path\\"",
|
||||
"webpack:///webpack/bootstrap",
|
||||
"webpack:///./extract3.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ConfigTestCases source-map extract-source-map exported tests should extract source map - 3 1`] = `
|
||||
Array [
|
||||
"webpack:///./external-source-map.txt",
|
||||
"webpack:///external node-commonjs \\"fs\\"",
|
||||
"webpack:///external node-commonjs \\"path\\"",
|
||||
"webpack:///webpack/bootstrap",
|
||||
"webpack:///./extract3.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ConfigTestCases source-map extract-source-map-css exported tests should compile 1`] = `
|
||||
Array [
|
||||
"/*!*********************!*\\\\
|
||||
!*** css ./app.css ***!
|
||||
\\\\*********************/
|
||||
* {
|
||||
box-sizing: border-box; }
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
margin-right: -15px;
|
||||
margin-left: -15px; }
|
||||
|
||||
.col-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
height: 50px;
|
||||
background: coral; }
|
||||
|
||||
.col-s3 {
|
||||
flex: 0 1 25%;
|
||||
padding: 0 15px; }
|
||||
|
||||
|
||||
|
||||
|
||||
/*# sourceMappingURL=bundle0.css.map*/",
|
||||
]
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`getSourceMappingURL should work with " // # sourceMappingURL = absolute-sourceRoot-source-map.map " url: result 1`] = `"absolute-sourceRoot-source-map.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with " // #sourceMappingURL=absolute-sourceRoot-source-map.map" url: result 1`] = `"absolute-sourceRoot-source-map.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with ""\\n /*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))))+" */";" url: result 1`] = `""`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "/* #sourceMappingURL=absolute-sourceRoot-source-map.map */" url: result 1`] = `"absolute-sourceRoot-source-map.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "/*#sourceMappingURL=absolute-sourceRoot-source-map.map*/" url: result 1`] = `"absolute-sourceRoot-source-map.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "// # sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))))+"" url: result 1`] = `"data:application/json;base64,"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "// #sourceMappingURL = //hello.com/external-source-map2.map" url: result 1`] = `"//hello.com/external-source-map2.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "// #sourceMappingURL = http://hello.com/external-source-map2.map" url: result 1`] = `"http://hello.com/external-source-map2.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "// @sourceMappingURL=data:application/source-map;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5saW5lLXNvdXJjZS1tYXAuanMiLCJzb3VyY2VzIjpbImlubGluZS1zb3VyY2UtbWFwLnR4dCJdLCJzb3VyY2VzQ29udGVudCI6WyJ3aXRoIFNvdXJjZU1hcCJdLCJtYXBwaW5ncyI6IkFBQUEifQ==" url: result 1`] = `"data:application/source-map;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5saW5lLXNvdXJjZS1tYXAuanMiLCJzb3VyY2VzIjpbImlubGluZS1zb3VyY2UtbWFwLnR4dCJdLCJzb3VyY2VzQ29udGVudCI6WyJ3aXRoIFNvdXJjZU1hcCJdLCJtYXBwaW5ncyI6IkFBQUEifQ=="`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "//#sourceMappingURL=absolute-sourceRoot-source-map.map" url: result 1`] = `"absolute-sourceRoot-source-map.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "//@sourceMappingURL=absolute-sourceRoot-source-map.map" url: result 1`] = `"absolute-sourceRoot-source-map.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "\\n with SourceMap\\n // #sourceMappingURL = /sample-source-map-1.map\\n // #sourceMappingURL = /sample-source-map-2.map\\n // #sourceMappingURL = /sample-source-map-last.map\\n // comment\\n " url: result 1`] = `"/sample-source-map-last.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "\\n with SourceMap\\n \\n // #sourceMappingURL = /sample-source-map.map\\n // comment\\n " url: result 1`] = `"/sample-source-map.map"`;
|
||||
|
||||
exports[`getSourceMappingURL should work with "anInvalidDirective = "\\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))))+" */";" url: result 1`] = `""`;
|
|
@ -0,0 +1,22 @@
|
|||
* {
|
||||
box-sizing: border-box; }
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
margin-right: -15px;
|
||||
margin-left: -15px; }
|
||||
|
||||
.col-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
height: 50px;
|
||||
background: coral; }
|
||||
|
||||
.col-s3 {
|
||||
flex: 0 1 25%;
|
||||
padding: 0 15px; }
|
||||
|
||||
|
||||
/*# sourceMappingURL=app.css.map*/
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["webpack:///./src/app/app.scss"],"names":[],"mappings":"AAAA;EACE,sBAAsB;;AAGxB;EACE,aAAa;EACb,mBAAmB;EACnB,kBAAkB;;AAIlB;EACE,aAAa;EACb,mBAAmB;EACnB,uBAAuB;EACvB,WAAW;EACX,YAAY;EACZ,iBAAiB;;AAInB;EACE,aAAa;EACb,eAAe","file":"app.css","sourcesContent":["* {\n box-sizing: border-box;\n}\n\n.row {\n display: flex;\n margin-right: -15px;\n margin-left: -15px;\n}\n\n.col {\n &-inner {\n display: flex;\n align-items: center;\n justify-content: center;\n color: #fff;\n height: 50px;\n background: coral;\n //background: red;\n }\n\n &-s3 {\n flex: 0 1 25%;\n padding: 0 15px;\n }\n}\n"],"sourceRoot":""}
|
|
@ -0,0 +1,14 @@
|
|||
import "./app.css";
|
||||
|
||||
it("should compile", done => {
|
||||
const links = document.getElementsByTagName("link");
|
||||
const css = [];
|
||||
|
||||
// Skip first because import it by default
|
||||
for (const link of links.slice(1)) {
|
||||
css.push(link.sheet.css);
|
||||
}
|
||||
|
||||
expect(css).toMatchSnapshot();
|
||||
done();
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
moduleScope(scope) {
|
||||
const link = scope.window.document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = "bundle0.css";
|
||||
scope.window.document.head.appendChild(link);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
"use strict";
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
target: "web",
|
||||
mode: "development",
|
||||
devtool: "source-map",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/i,
|
||||
type: "css",
|
||||
extractSourceMap: true
|
||||
}
|
||||
]
|
||||
},
|
||||
experiments: {
|
||||
css: true
|
||||
}
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
require("./test1");
|
||||
require("./no-source-map")
|
||||
|
||||
it("should extract source map - 1", () => {
|
||||
const fileData = fs.readFileSync(path.resolve(__dirname, "bundle1.js.map")).toString("utf-8");
|
||||
const { sources } = JSON.parse(fileData);
|
||||
expect(sources).toMatchSnapshot();
|
||||
expect(1).toBe(1)
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
require("./test2");
|
||||
|
||||
it("should extract source map - 2", () => {
|
||||
const fileData = fs.readFileSync(path.resolve(__dirname, "bundle2.js.map")).toString("utf-8");
|
||||
const { sources } = JSON.parse(fileData);
|
||||
expect(sources).toMatchSnapshot();
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
require("./test3");
|
||||
|
||||
it("should extract source map - 3", () => {
|
||||
const fileData = fs.readFileSync(path.resolve(__dirname, "bundle2.js.map")).toString("utf-8");
|
||||
const { sources } = JSON.parse(fileData);
|
||||
expect(sources).toMatchSnapshot();
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = [
|
||||
/^Pack got invalid because of write to: Compilation\/modules.+no-source-map\.js$/
|
||||
];
|
|
@ -0,0 +1,2 @@
|
|||
const a = 1;
|
||||
//#sourceMappingURL=no-source-map.map
|
|
@ -0,0 +1,11 @@
|
|||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
|
||||
require("./test1");
|
||||
|
||||
it("should remove sourceMap comment", () => {
|
||||
expect(
|
||||
fs.readFileSync(__filename).toString("utf-8")
|
||||
).not.toMatch(/\/\/\s*@\s*sourceMappingURL/);
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
const a = 1;
|
||||
// @ sourceMappingURL = data:application/source-map;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnNldC1pbmxpbmUtc291cmNlLW1hcC5qcyIsInNvdXJjZXMiOlsiY2hhcnNldC1pbmxpbmUtc291cmNlLW1hcC50eHQiXSwic291cmNlc0NvbnRlbnQiOlsid2l0aCBTb3VyY2VNYXAiXSwibWFwcGluZ3MiOiJBQUFBIn0=
|
||||
// comment
|
|
@ -0,0 +1,3 @@
|
|||
const a = 1;
|
||||
// comment
|
||||
//#sourceMappingURL=test2.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"test2.js","sources":["external-source-map.txt"],"sourcesContent":["with SourceMap"],"mappings":"AAAA"}
|
|
@ -0,0 +1,3 @@
|
|||
const a = 1;
|
||||
// comment
|
||||
//#sourceMappingURL=/test2.map
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = [[/Failed to parse source map/]];
|
|
@ -0,0 +1,52 @@
|
|||
"use strict";
|
||||
|
||||
/** @type {import("../../../../").Configuration[]} */
|
||||
module.exports = [
|
||||
{
|
||||
target: "node",
|
||||
entry: "./extract1",
|
||||
devtool: "source-map",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
extractSourceMap: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
target: "node",
|
||||
entry: "./extract2",
|
||||
devtool: "source-map",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
extractSourceMap: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
target: "node",
|
||||
entry: "./extract3",
|
||||
devtool: "source-map",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
extractSourceMap: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
entry: "./remove-comment",
|
||||
devtool: "source-map",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
extractSourceMap: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
|
@ -0,0 +1,3 @@
|
|||
const a = 1;
|
||||
// comment
|
||||
//#sourceMappingURL=/a.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"test2.js","sources":["external-source-map.txt"],"sourcesContent":[],"mappings":"AAAA"}
|
|
@ -0,0 +1,27 @@
|
|||
/** @typedef {import("webpack").LoaderContext<void>} LoaderContext */
|
||||
|
||||
const assert = require("assert")
|
||||
|
||||
/**
|
||||
* @this {LoaderContext}
|
||||
* @param {string} source The source code to process
|
||||
* @param {import("webpack-sources").RawSourceMap} sourceMap The source map to process
|
||||
* @returns {void}
|
||||
*/
|
||||
module.exports = function(source, sourceMap) {
|
||||
const callback = this.async();
|
||||
const resourcePath = this.resourcePath;
|
||||
|
||||
if (resourcePath.endsWith("a.js")) {
|
||||
assert(sourceMap && sourceMap.version && sourceMap.mappings, "should have source map when extract source map");
|
||||
}
|
||||
|
||||
try {
|
||||
const withoutConst = source.replace(/const/g, "var");
|
||||
|
||||
callback(null, withoutConst, sourceMap);
|
||||
} catch (err) {
|
||||
callback(/** @type {Error} */ (err));
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
source
|
|
@ -0,0 +1,11 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
require("./a");
|
||||
|
||||
it("should extract source map", () => {
|
||||
const fileData = fs.readFileSync(path.resolve(__dirname, "bundle0.js.map")).toString("utf-8");
|
||||
const { sources, sourcesContent } = JSON.parse(fileData);
|
||||
expect(sources.includes("webpack:///./external-source-map.txt")).toBe(true);
|
||||
expect(sourcesContent.map(s => s.trim())).toContain("source");
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = function filter() {
|
||||
return process.platform !== "win32";
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
"use strict";
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
target: "node",
|
||||
entry: "./index",
|
||||
devtool: "source-map",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
extractSourceMap: true,
|
||||
loader: require.resolve("./babel-loader")
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
"use strict";
|
||||
|
||||
const { getSourceMappingURL } = require("../lib/util/extractSourceMap");
|
||||
|
||||
describe("getSourceMappingURL", () => {
|
||||
const cases = [
|
||||
"/*#sourceMappingURL=absolute-sourceRoot-source-map.map*/",
|
||||
"/* #sourceMappingURL=absolute-sourceRoot-source-map.map */",
|
||||
"//#sourceMappingURL=absolute-sourceRoot-source-map.map",
|
||||
"//@sourceMappingURL=absolute-sourceRoot-source-map.map",
|
||||
" // #sourceMappingURL=absolute-sourceRoot-source-map.map",
|
||||
" // # sourceMappingURL = absolute-sourceRoot-source-map.map ",
|
||||
"// #sourceMappingURL = http://hello.com/external-source-map2.map",
|
||||
"// #sourceMappingURL = //hello.com/external-source-map2.map",
|
||||
"// @sourceMappingURL=data:application/source-map;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5saW5lLXNvdXJjZS1tYXAuanMiLCJzb3VyY2VzIjpbImlubGluZS1zb3VyY2UtbWFwLnR4dCJdLCJzb3VyY2VzQ29udGVudCI6WyJ3aXRoIFNvdXJjZU1hcCJdLCJtYXBwaW5ncyI6IkFBQUEifQ==",
|
||||
`
|
||||
with SourceMap
|
||||
|
||||
// #sourceMappingURL = /sample-source-map.map
|
||||
// comment
|
||||
`,
|
||||
`
|
||||
with SourceMap
|
||||
// #sourceMappingURL = /sample-source-map-1.map
|
||||
// #sourceMappingURL = /sample-source-map-2.map
|
||||
// #sourceMappingURL = /sample-source-map-last.map
|
||||
// comment
|
||||
`,
|
||||
`"
|
||||
/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))))+" */";`,
|
||||
'anInvalidDirective = "\\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))))+" */";',
|
||||
'// # sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))))+"'
|
||||
];
|
||||
|
||||
for (const item of cases) {
|
||||
it(`should work with "${item}" url`, async () => {
|
||||
const { sourceMappingURL } = getSourceMappingURL(item);
|
||||
|
||||
expect(sourceMappingURL).toMatchSnapshot("result");
|
||||
});
|
||||
}
|
||||
});
|
|
@ -10713,6 +10713,11 @@ declare interface ModuleSettings {
|
|||
*/
|
||||
type?: string;
|
||||
|
||||
/**
|
||||
* Enable/Disable extracting source map.
|
||||
*/
|
||||
extractSourceMap?: boolean;
|
||||
|
||||
/**
|
||||
* Options for the resolver.
|
||||
*/
|
||||
|
@ -11020,6 +11025,7 @@ declare class NormalModule extends Module {
|
|||
resourceResolveData?: ResourceSchemeData & Partial<ResolveRequest>;
|
||||
matchResource?: string;
|
||||
loaders: LoaderItem[];
|
||||
extractSourceMap?: boolean;
|
||||
error: null | WebpackError;
|
||||
|
||||
/**
|
||||
|
@ -11169,6 +11175,11 @@ declare interface NormalModuleCreateData {
|
|||
* options used for resolving requests from this module
|
||||
*/
|
||||
resolveOptions?: ResolveOptions;
|
||||
|
||||
/**
|
||||
* enable/disable extracting source map
|
||||
*/
|
||||
extractSourceMap?: boolean;
|
||||
}
|
||||
declare abstract class NormalModuleFactory extends ModuleFactory {
|
||||
hooks: Readonly<{
|
||||
|
@ -15080,6 +15091,11 @@ declare interface RuleSetRule {
|
|||
| RuleSetLogicalConditionsAbsolute
|
||||
| RuleSetConditionAbsolute[];
|
||||
|
||||
/**
|
||||
* Enable/Disable extracting source map.
|
||||
*/
|
||||
extractSourceMap?: boolean;
|
||||
|
||||
/**
|
||||
* The options for the module generator.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue