Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Error location mismatches after loader processing #18260

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 14 additions & 2 deletions lib/Compilation.js
Expand Up @@ -82,6 +82,7 @@ const {
const processAsyncTree = require("./util/processAsyncTree");
const { getRuntimeKey } = require("./util/runtime");
const { isSourceEqual } = require("./util/source");
const updateErrorLocation = require("./util/sourceMap");

/** @template T @typedef {import("tapable").AsArray<T>} AsArray<T> */
/** @typedef {import("webpack-sources").Source} Source */
Expand Down Expand Up @@ -1850,8 +1851,19 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
this.warnings.push(err);
return callback();
} else {
this.errors.push(err);
return callback(err);
// If module has a source map, update the error location using
// source map to avoid misaligned error location after loader processing
if (err.module && "useSourceMap" in err.module) {
if ("start" in err.loc) {
return updateErrorLocation(err, err => {
this.errors.push(err);
return callback(err);
});
}
} else {
this.errors.push(err);
return callback(err);
}
}
}

Expand Down
58 changes: 58 additions & 0 deletions lib/util/sourceMap.js
@@ -0,0 +1,58 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Furkan Erdem @log101
*/

"use strict";

const { SourceMapConsumer } = require("source-map");

/** @typedef {import("../Compilation").ModuleCallback} ModuleCallback */
/** @typedef {import("../Dependency").RealDependencyLocation} RealDependencyLocation */
/** @typedef {import("../WebpackError")} WebpackError */

/**
* Updates error location (line number and column) using sourcemap
*
* @param {WebpackError} err The error with the misaligned location.
* @param {ModuleCallback} callback callback
* @returns {Promise<void>}
*/
const updateErrorLocation = async (err, callback) => {
let consumer;
try {
consumer = await new SourceMapConsumer(err.module.originalSource().map());
log101 marked this conversation as resolved.
Show resolved Hide resolved
} catch (_err) {
return callback(err);
}

// Have to check to avoid type error
if ("start" in err.loc) {
// find the original positions
const startLoc = consumer.originalPositionFor({
line: err.loc.start.line,
column: err.loc.start.column
});

// update the error start location
err.loc.start.line = startLoc.line;
err.loc.start.column = startLoc.column;
}

// end field is optional, check if exists
if ("end" in err.loc) {
// find the original positions
const endLoc = consumer.originalPositionFor({
line: err.loc.end.line,
column: err.loc.end.column
});

// update the error end location
err.loc.end.line = endLoc.line;
err.loc.end.column = endLoc.column;
}

return callback(err);
};

module.exports = updateErrorLocation;
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -25,6 +25,7 @@
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^3.2.0",
"source-map": "^0.7.4",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.3.10",
"watchpack": "^2.4.1",
Expand Down
7 changes: 7 additions & 0 deletions test/__snapshots__/StatsTestCases.basictest.js.snap
Expand Up @@ -4815,3 +4815,10 @@ cacheable modules 250 bytes
./worker.js 135 bytes [built] [code generated]
webpack x.x.x compiled successfully in X ms"
`;

exports[`StatsTestCases should print correct stats for wrong-error-location-error 1`] = `
"ERROR in ./index.js 2:13-33
Module not found: Error: Can't resolve 'some_file' in 'Xdir/wrong-error-location-error'

webpack compiled with 1 error"
`;
3 changes: 3 additions & 0 deletions test/statsCases/wrong-error-location-error/index.js
@@ -0,0 +1,3 @@
// Test: Force Webpack error
const data = require('some_file');
log(data);
40 changes: 40 additions & 0 deletions test/statsCases/wrong-error-location-error/sampleLoader.js
@@ -0,0 +1,40 @@
const sourceMap = require("source-map");

/**
*
* @param {string|Buffer} source Content of the resource file
*/
function sampleLoader(source) {
var map = new sourceMap.SourceMapGenerator({
file: "index.js",
});

map.addMapping({
generated: {
line: 4,
column: 13
},
original: {
line: 2,
column: 13
},
source: "index.js",
})

map.addMapping({
generated: {
line: 4,
column: 33
},
original: {
line: 2,
column: 33
},
source: "index.js",
})

this.callback(null, `\n\n${source}`, map.toJSON())
return;
}

module.exports = sampleLoader;
15 changes: 15 additions & 0 deletions test/statsCases/wrong-error-location-error/webpack.config.js
@@ -0,0 +1,15 @@
/** @type {import("../../../types").Configuration} */

module.exports = {
entry: "./index",
module: {
rules: [
{
test: /\.js$/,
use: "./sampleLoader.js"
}
]
},
devtool: "source-map",
stats: "errors-only"
};