Skip to content
This repository was archived by the owner on Apr 3, 2024. It is now read-only.

Commit f79c83c

Browse files
fix: add webpack support to the Sourcemapper (#640)
Fixes: #616
1 parent fc5a387 commit f79c83c

File tree

7 files changed

+212
-25
lines changed

7 files changed

+212
-25
lines changed

src/agent/io/sourcemapper.ts

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {findScriptsFuzzy} from '../util/utils';
2424
import pLimit = require('p-limit');
2525

2626
const CONCURRENCY = 10;
27+
const WEBPACK_PREFIX = 'webpack://';
2728
const readFilep = promisify(fs.readFile);
2829

2930
/** @define {string} */ const MAP_EXT = '.map';
@@ -32,6 +33,9 @@ export interface MapInfoInput {
3233
outputFile: string;
3334
mapFile: string;
3435
mapConsumer: sourceMap.RawSourceMap;
36+
// the sources are in ascending order from
37+
// shortest to longest
38+
sources: string[];
3539
}
3640

3741
export interface MapInfoOutput {
@@ -91,27 +95,36 @@ async function processSourcemap(
9195
const parentDir = path.dirname(mapPath);
9296
const outputPath = path.normalize(path.join(parentDir, outputBase));
9397

94-
const sources = Array.prototype.slice.call(consumer.sources)
95-
.filter((value: string) => {
96-
// filter out any empty string, null, or undefined
97-
// sources
98-
return !!value;
99-
})
100-
.map((relPath: string) => {
101-
// resolve the paths relative to the map file so that
102-
// they are relative to the process's current working
103-
// directory
104-
return path.normalize(path.join(parentDir, relPath));
105-
});
106-
107-
if (sources.length === 0) {
98+
// the sources are in ascending order from shortest to longest
99+
const nonemptySources = consumer.sources.filter(val => !!val)
100+
.sort((src1, src2) => src1.length - src2.length);
101+
102+
const normalizedSources =
103+
nonemptySources
104+
.map((src: string) => {
105+
if (src.toLowerCase().startsWith(WEBPACK_PREFIX)) {
106+
return src.substring(WEBPACK_PREFIX.length);
107+
}
108+
return src;
109+
})
110+
.map((relPath: string) => {
111+
// resolve the paths relative to the map file so that
112+
// they are relative to the process's current working
113+
// directory
114+
return path.normalize(path.join(parentDir, relPath));
115+
});
116+
117+
if (normalizedSources.length === 0) {
108118
throw new Error('No sources listed in the sourcemap file ' + mapPath);
109119
}
110-
sources.forEach((src: string) => {
111-
infoMap.set(
112-
path.normalize(src),
113-
{outputFile: outputPath, mapFile: mapPath, mapConsumer: consumer});
114-
});
120+
for (const src of normalizedSources) {
121+
infoMap.set(path.normalize(src), {
122+
outputFile: outputPath,
123+
mapFile: mapPath,
124+
mapConsumer: consumer,
125+
sources: nonemptySources
126+
});
127+
}
115128
}
116129

117130
export class SourceMapper {
@@ -198,9 +211,25 @@ export class SourceMapper {
198211
return null;
199212
}
200213

214+
const relPath = path.relative(path.dirname(entry.mapFile), inputPath)
215+
.replace(/\\/g, '/');
216+
217+
/**
218+
* Note: Since `entry.sources` is in ascending order from shortest
219+
* to longest, the first source path that ends with the
220+
* relative path is necessarily the shortest source path
221+
* that ends with the relative path.
222+
*/
223+
let source: string|undefined;
224+
for (const src of entry.sources) {
225+
if (src.endsWith(relPath)) {
226+
source = src;
227+
break;
228+
}
229+
}
230+
201231
const sourcePos = {
202-
source: path.relative(path.dirname(entry.mapFile), inputPath)
203-
.replace(/\\/g, '/'),
232+
source: source || relPath,
204233
line: lineNumber + 1, // the SourceMapConsumer expects the line number
205234
// to be one-based but expects the column number
206235
column: colNumber // to be zero-based
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
function someFunction() {
3+
const x = 1;
4+
const y = 2;
5+
console.log(x + y);
6+
}
7+
8+
someFunction();

test/fixtures/sourcemapper/webpack-ts/out.js

Lines changed: 103 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/fixtures/sourcemapper/webpack-ts/out.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "webpack-ts",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "webpack.config.js",
6+
"scripts": {
7+
"compile": "webpack"
8+
},
9+
"keywords": [],
10+
"author": "",
11+
"license": "ISC",
12+
"devDependencies": {
13+
"webpack": "^4.29.4",
14+
"webpack-cli": "^3.2.3"
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
const path = require('path');
3+
4+
module.exports = {
5+
mode: 'none',
6+
entry: './in.ts_',
7+
output: {
8+
path: path.resolve(__dirname),
9+
filename: 'out.js'
10+
},
11+
devtool: 'source-map',
12+
optimization: {
13+
nodeEnv: false
14+
}
15+
};

test/test-sourcemapper.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ function testTool(
6060
it('for tool ' + tool +
6161
' it states that it has mapping info for files it knows about',
6262
(done) => {
63-
assert.strictEqual(sourcemapper.hasMappingInfo(inputFilePath), true);
63+
assert.strictEqual(
64+
sourcemapper.hasMappingInfo(inputFilePath), true,
65+
`The sourcemapper should have information about '${
66+
inputFilePath}'`);
6467
done();
6568
});
6669

@@ -72,16 +75,22 @@ function testTool(
7275
sourcemapper.hasMappingInfo(relativeInputFilePath), true);
7376
const movedPath =
7477
path.join('/some/other/base/dir/', relativeInputFilePath);
75-
assert.strictEqual(sourcemapper.hasMappingInfo(movedPath), true);
78+
assert.strictEqual(
79+
sourcemapper.hasMappingInfo(movedPath), true,
80+
`The sourcemapper should have information about paths similar to '${
81+
movedPath}'`);
7682
done();
7783
});
7884

7985
it('for tool ' + tool +
8086
' it states that it does not have mapping info for a file it ' +
8187
'doesn\'t recognize',
8288
(done) => {
89+
const invalidPath = inputFilePath + '_INVALID';
8390
assert.strictEqual(
84-
sourcemapper.hasMappingInfo(inputFilePath + '_INVALID'), false);
91+
sourcemapper.hasMappingInfo(invalidPath), false,
92+
`The source mapper should not have information the path '${
93+
invalidPath}' it doesn't recognize`);
8594
done();
8695
});
8796

@@ -93,7 +102,8 @@ function testTool(
93102
assert.strictEqual(info!.file, outputFilePath);
94103
assert.strictEqual(
95104
info!.line, expectedOutputLine,
96-
' invalid mapping for input line ' + inputLine);
105+
' invalid mapping for input line ' + inputLine +
106+
' Expected: ' + expectedOutputLine + ', Found: ' + info!.line);
97107
};
98108

99109
it('for tool ' + tool + ' it properly maps line numbers', (done) => {
@@ -134,3 +144,8 @@ testTool(
134144
[1, 1], [2, 7], [3, 8], [4, 9], [6, 12], [7, 13], [9, 20], [10, 23],
135145
[11, 24], [13, 31], [15, 33], [17, 36], [19, 38], [20, 40], [21, 44]
136146
]);
147+
148+
testTool(
149+
'Webpack with Typescript', path.join('webpack-ts', 'out.js.map'),
150+
path.join('webpack-ts', 'in.ts_'), path.join('webpack-ts', 'out.js'),
151+
[[3, 93], [4, 94], [8, 97]]);

0 commit comments

Comments
 (0)