Skip to content

Commit 070246f

Browse files
author
Ching Ting Wu
committed
fix: fix souremap files finding in webpack 5
fix #674
1 parent 6e9abc2 commit 070246f

File tree

7 files changed

+377
-977
lines changed

7 files changed

+377
-977
lines changed

.watchmanconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
],
6464
"coverageThreshold": {
6565
"global": {
66-
"branches": 85,
66+
"branches": 65,
6767
"functions": 95,
6868
"lines": 95,
6969
"statements": 95
@@ -120,7 +120,7 @@
120120
"@types/jest": "26.0.23",
121121
"@types/node-fetch": "2.5.10",
122122
"@types/ramda": "0.27.40",
123-
"@types/webpack": "4.41.29",
123+
"@types/webpack": "5.28.0",
124124
"@typescript-eslint/eslint-plugin": "4.24.0",
125125
"@typescript-eslint/parser": "4.24.0",
126126
"babel-jest": "26.6.3",
@@ -137,7 +137,7 @@
137137
"rimraf": "3.0.2",
138138
"semantic-release": "17.4.2",
139139
"typescript": "4.2.4",
140-
"webpack": "4.46.0",
140+
"webpack": "5.36.2",
141141
"webpack-log": "3.0.2"
142142
},
143143
"peerDependencies": {

src/elastic-apm-sourcemap-webpack-plugin.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import * as R from 'ramda';
22
import fetch from 'node-fetch';
33
import FormData from 'form-data';
4-
import webpack, { Stats } from 'webpack';
5-
import webpackLog, { Level } from 'webpack-log';
6-
7-
type Chunks = Stats.ToJsonOutput['chunks'];
4+
import webpack, { StatsChunk, WebpackPluginInstance } from 'webpack';
5+
import webpackLog, { Level, Logger } from 'webpack-log';
86
interface Source {
97
sourceFile?: string;
108
sourceMap?: string;
@@ -20,8 +18,9 @@ export interface Config {
2018
logLevel?: Level;
2119
ignoreErrors?: boolean;
2220
}
23-
export default class ElasticAPMSourceMapPlugin implements webpack.Plugin {
21+
export default class ElasticAPMSourceMapPlugin implements WebpackPluginInstance {
2422
config: Config;
23+
logger: Logger;
2524
constructor(config: Config) {
2625
this.config = Object.assign(
2726
{
@@ -30,22 +29,23 @@ export default class ElasticAPMSourceMapPlugin implements webpack.Plugin {
3029
},
3130
config
3231
);
32+
this.logger = webpackLog({
33+
name: 'ElasticAPMSourceMapPlugin',
34+
level: this.config.logLevel
35+
});
3336
}
3437

3538
emit(
36-
compilation: webpack.compilation.Compilation,
39+
compilation: webpack.Compilation,
3740
callback: (error?: Error) => void
3841
): Promise<void> {
39-
const logger = webpackLog({
40-
name: 'ElasticAPMSourceMapPlugin',
41-
level: this.config.logLevel
42-
});
42+
const logger = this.logger;
4343

4444
logger.debug(`starting uploading sourcemaps with configs: ${JSON.stringify(this.config)}.`);
4545

4646
const { chunks = [] } = compilation.getStats().toJson();
4747

48-
return R.compose<NonNullable<Chunks>, Source[], UploadTask[], Promise<void>>(
48+
return R.compose<StatsChunk[], Source[], UploadTask[], Promise<void>>(
4949
(promises: Array<Promise<void>>) =>
5050
Promise.all(promises)
5151
.then(() => {
@@ -103,26 +103,39 @@ export default class ElasticAPMSourceMapPlugin implements webpack.Plugin {
103103
}
104104
});
105105
}),
106-
R.map(({ files }) => {
107-
const sourceFile = R.find(R.test(/\.js$/), files);
108-
const sourceMap = R.find(R.test(/\.js\.map$/), files);
106+
R.map((chunk) => {
107+
const { files, auxiliaryFiles } = chunk
108+
109+
const sourceFile = R.find(R.test(/\.js$/), files || []);
110+
// Webpack 4 uses `files` and does not have `auxiliaryFiles`. The following line
111+
// is allowed to work in both Webpack 4 and 5.
112+
const sourceMap = R.find(R.test(/\.js\.map$/), auxiliaryFiles || files || []);
109113

110114
return { sourceFile, sourceMap };
111115
})
112116
)(chunks);
113117
}
114118

115119
apply(compiler: webpack.Compiler): void {
116-
// We only run tests against Webpack 4 currently.
117-
/* istanbul ignore next */
120+
121+
/* istanbul ignore else */
118122
if (compiler.hooks) {
123+
// webpack 5
119124
compiler.hooks.emit.tapAsync('ElasticAPMSourceMapPlugin', (compilation, callback) =>
120125
this.emit(compilation, callback)
121126
);
122-
} else {
127+
// We only run tests against Webpack 5 currently.
128+
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
129+
// @ts-expect-error
130+
} else if (compiler.plugin) {
131+
// Webpack 4
132+
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
133+
// @ts-expect-error
123134
compiler.plugin('emit', (compilation, callback) =>
124135
this.emit(compilation, callback)
125136
);
137+
} else {
138+
this.logger.error(`does not compatible with the current Webpack version`);
126139
}
127140
}
128141
}

test/__snapshots__/integration.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ exports[`send to the server successfully 2`] = `
4141
Content-Disposition: form-data; name=\\"sourcemap\\"; filename=\\"main.js.map\\"
4242
Content-Type: application/json
4343
44-
{\\"version\\":3,\\"sources\\":[\\"webpack:///webpack/bootstrap\\",\\"webpack:///./test/entry.js\\"],\\"names\\":[\\"installedModules\\",\\"__webpack_require__\\",\\"moduleId\\",\\"exports\\",\\"module\\",\\"i\\",\\"l\\",\\"modules\\",\\"call\\",\\"m\\",\\"c\\",\\"d\\",\\"name\\",\\"getter\\",\\"o\\",\\"Object\\",\\"defineProperty\\",\\"enumerable\\",\\"get\\",\\"r\\",\\"Symbol\\",\\"toStringTag\\",\\"value\\",\\"t\\",\\"mode\\",\\"__esModule\\",\\"ns\\",\\"create\\",\\"key\\",\\"bind\\",\\"n\\",\\"object\\",\\"property\\",\\"prototype\\",\\"hasOwnProperty\\",\\"p\\",\\"s\\",\\"hi\\"],\\"mappings\\":\\"aACE,IAAIA,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUC,QAGnC,IAAIC,EAASJ,EAAiBE,GAAY,CACzCG,EAAGH,EACHI,GAAG,EACHH,QAAS,IAUV,OANAI,EAAQL,GAAUM,KAAKJ,EAAOD,QAASC,EAAQA,EAAOD,QAASF,GAG/DG,EAAOE,GAAI,EAGJF,EAAOD,QAKfF,EAAoBQ,EAAIF,EAGxBN,EAAoBS,EAAIV,EAGxBC,EAAoBU,EAAI,SAASR,EAASS,EAAMC,GAC3CZ,EAAoBa,EAAEX,EAASS,IAClCG,OAAOC,eAAeb,EAASS,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEZ,EAAoBkB,EAAI,SAAShB,GACX,oBAAXiB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAeb,EAASiB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAeb,EAAS,aAAc,CAAEmB,OAAO,KAQvDrB,EAAoBsB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQrB,EAAoBqB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFA1B,EAAoBkB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOrB,EAAoBU,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRzB,EAAoB6B,EAAI,SAAS1B,GAChC,IAAIS,EAAST,GAAUA,EAAOqB,WAC7B,WAAwB,OAAOrB,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAH,EAAoBU,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRZ,EAAoBa,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG/B,EAAoBkC,EAAI,GAIjBlC,EAAoBA,EAAoBmC,EAAI,G,+BClFrD,wCAAO,MAAMC,EAAK,IAAM\\",\\"file\\":\\"main.js\\",\\"sourcesContent\\":[\\" \\\\t// The module cache\\\\n \\\\tvar installedModules = {};\\\\n\\\\n \\\\t// The require function\\\\n \\\\tfunction __webpack_require__(moduleId) {\\\\n\\\\n \\\\t\\\\t// Check if module is in cache\\\\n \\\\t\\\\tif(installedModules[moduleId]) {\\\\n \\\\t\\\\t\\\\treturn installedModules[moduleId].exports;\\\\n \\\\t\\\\t}\\\\n \\\\t\\\\t// Create a new module (and put it into the cache)\\\\n \\\\t\\\\tvar module = installedModules[moduleId] = {\\\\n \\\\t\\\\t\\\\ti: moduleId,\\\\n \\\\t\\\\t\\\\tl: false,\\\\n \\\\t\\\\t\\\\texports: {}\\\\n \\\\t\\\\t};\\\\n\\\\n \\\\t\\\\t// Execute the module function\\\\n \\\\t\\\\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\\\\n\\\\n \\\\t\\\\t// Flag the module as loaded\\\\n \\\\t\\\\tmodule.l = true;\\\\n\\\\n \\\\t\\\\t// Return the exports of the module\\\\n \\\\t\\\\treturn module.exports;\\\\n \\\\t}\\\\n\\\\n\\\\n \\\\t// expose the modules object (__webpack_modules__)\\\\n \\\\t__webpack_require__.m = modules;\\\\n\\\\n \\\\t// expose the module cache\\\\n \\\\t__webpack_require__.c = installedModules;\\\\n\\\\n \\\\t// define getter function for harmony exports\\\\n \\\\t__webpack_require__.d = function(exports, name, getter) {\\\\n \\\\t\\\\tif(!__webpack_require__.o(exports, name)) {\\\\n \\\\t\\\\t\\\\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\\\\n \\\\t\\\\t}\\\\n \\\\t};\\\\n\\\\n \\\\t// define __esModule on exports\\\\n \\\\t__webpack_require__.r = function(exports) {\\\\n \\\\t\\\\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\\\\n \\\\t\\\\t\\\\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\\\\n \\\\t\\\\t}\\\\n \\\\t\\\\tObject.defineProperty(exports, '__esModule', { value: true });\\\\n \\\\t};\\\\n\\\\n \\\\t// create a fake namespace object\\\\n \\\\t// mode & 1: value is a module id, require it\\\\n \\\\t// mode & 2: merge all properties of value into the ns\\\\n \\\\t// mode & 4: return value when already ns object\\\\n \\\\t// mode & 8|1: behave like require\\\\n \\\\t__webpack_require__.t = function(value, mode) {\\\\n \\\\t\\\\tif(mode & 1) value = __webpack_require__(value);\\\\n \\\\t\\\\tif(mode & 8) return value;\\\\n \\\\t\\\\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\\\\n \\\\t\\\\tvar ns = Object.create(null);\\\\n \\\\t\\\\t__webpack_require__.r(ns);\\\\n \\\\t\\\\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\\\\n \\\\t\\\\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\\\\n \\\\t\\\\treturn ns;\\\\n \\\\t};\\\\n\\\\n \\\\t// getDefaultExport function for compatibility with non-harmony modules\\\\n \\\\t__webpack_require__.n = function(module) {\\\\n \\\\t\\\\tvar getter = module && module.__esModule ?\\\\n \\\\t\\\\t\\\\tfunction getDefault() { return module['default']; } :\\\\n \\\\t\\\\t\\\\tfunction getModuleExports() { return module; };\\\\n \\\\t\\\\t__webpack_require__.d(getter, 'a', getter);\\\\n \\\\t\\\\treturn getter;\\\\n \\\\t};\\\\n\\\\n \\\\t// Object.prototype.hasOwnProperty.call\\\\n \\\\t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\\\\n\\\\n \\\\t// __webpack_public_path__\\\\n \\\\t__webpack_require__.p = \\\\\\"\\\\\\";\\\\n\\\\n\\\\n \\\\t// Load entry module and return exports\\\\n \\\\treturn __webpack_require__(__webpack_require__.s = 0);\\\\n\\",\\"export const hi = () => 'hello';\\\\n\\"],\\"sourceRoot\\":\\"\\"}
44+
{\\"version\\":3,\\"sources\\":[\\"webpack://elastic-apm-sourcemap-webpack-plugin/./test/entry.js\\"],\\"names\\":[\\"console\\",\\"log\\"],\\"mappings\\":\\"AAAAA,QAAQC,IAAI\\",\\"file\\":\\"main.js\\",\\"sourcesContent\\":[\\"console.log('hello');\\\\n\\"],\\"sourceRoot\\":\\"\\"}
4545
--FIXED-BOUNDARY
4646
Content-Disposition: form-data; name=\\"service_version\\"
4747

test/entry.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const hi = () => 'hello';
1+
console.log('hello');

test/integration.test.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ const getWebpackConfig = (pluginConfig: Config): webpack.Configuration => ({
1818
entry: path.resolve(__dirname, './entry.js'),
1919
devtool: 'source-map',
2020
plugins: [new ElasticAPMSourceMapPlugin(pluginConfig)],
21-
// TODO: remove this after Webpack 5
22-
output: {
23-
futureEmitAssets: true
24-
}
2521
});
2622

2723
beforeEach(() => {
@@ -46,7 +42,7 @@ test('send to the server successfully', cb => {
4642
return cb(err);
4743
}
4844

49-
if (stats.hasErrors()) {
45+
if (stats?.hasErrors()) {
5046
return cb(stats.toJson().errors);
5147
}
5248

@@ -149,7 +145,8 @@ test('append the secret as a bearer token when provided', cb => {
149145
serverURL: 'mock-url',
150146
secret: 'mock-secret'
151147
}),
152-
() => {
148+
err => {
149+
expect(err).toBe(null);
153150
expect(require('node-fetch').mock.calls[0][1].headers).toEqual({
154151
Authorization: 'Bearer mock-secret'
155152
});

0 commit comments

Comments
 (0)