Skip to content

Commit

Permalink
fix: resolve error when webpack output.futureEmitAssets is enabled (#314
Browse files Browse the repository at this point in the history
)

Webpack 4.29.0 introduced this option, which when enabled, breaks this
plugin. The fix is to read the file contents from disk after emit
instead of depending on the sources being available in the compilation.

closes #61
  • Loading branch information
brandondoran authored Dec 4, 2020
1 parent 1368ae3 commit 8bb1a52
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 3 deletions.
26 changes: 24 additions & 2 deletions src/RollbarSourceMapPlugin.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { promises as fs } from 'fs';
import { join } from 'path';
import fetch from 'node-fetch';
import FormData from 'form-data';
import isString from 'lodash.isstring';
Expand Down Expand Up @@ -49,6 +51,19 @@ class RollbarSourceMapPlugin {
compiler.hooks.afterEmit.tapPromise(PLUGIN_NAME, this.afterEmit.bind(this));
}

// eslint-disable-next-line class-methods-use-this
getAssetPath(compilation, name) {
return join(
compilation.getPath(compilation.compiler.outputPath),
name.split('?')[0]
);
}

getSource(compilation, name) {
const path = this.getAssetPath(compilation, name);
return fs.readFile(path, { encoding: 'utf-8' });
}

getAssets(compilation) {
const { includeChunks, encodeFilename } = this;
const { chunks } = compilation.getStats().toJson();
Expand Down Expand Up @@ -86,12 +101,19 @@ class RollbarSourceMapPlugin {

async uploadSourceMap(compilation, { sourceFile, sourceMap }) {
const errMessage = `failed to upload ${sourceMap} to Rollbar`;
const form = new FormData();
let sourceMapSource;

try {
sourceMapSource = await this.getSource(compilation, sourceMap);
} catch (err) {
throw new VError(err, errMessage);
}

const form = new FormData();
form.append('access_token', this.accessToken);
form.append('version', this.version);
form.append('minified_url', this.getPublicPath(sourceFile));
form.append('source_map', compilation.assets[sourceMap].source(), {
form.append('source_map', sourceMapSource, {
filename: sourceMap,
contentType: 'application/json'
});
Expand Down
21 changes: 20 additions & 1 deletion test/RollbarSourceMapPlugin.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { promises as fs } from 'fs';
import nock from 'nock';
import RollbarSourceMapPlugin from '../src/RollbarSourceMapPlugin';
import { PLUGIN_NAME, ROLLBAR_ENDPOINT } from '../src/constants';
Expand Down Expand Up @@ -409,23 +410,33 @@ describe('RollbarSourceMapPlugin', () => {
});

describe('uploadSourceMap', () => {
const outputPath = '/some/fake/path/';
let info;
let compilation;
let chunk;
let spyReadFile;

beforeEach(() => {
compilation = {
assets: {
'vendor.5190.js.map': { source: () => '{"version":3,"sources":[]' },
'app.81c1.js.map': { source: () => '{"version":3,"sources":[]' }
},
errors: []
compiler: {
outputPath
},
errors: [],
getPath: () => outputPath
};

chunk = {
sourceFile: 'vendor.5190.js',
sourceMap: 'vendor.5190.js.map'
};

spyReadFile = jest
.spyOn(fs, 'readFile')
.mockImplementation(() => Promise.resolve('data'));
});

it('logs to console if upload is success', async () => {
Expand Down Expand Up @@ -476,6 +487,14 @@ describe('RollbarSourceMapPlugin', () => {
);
});

it('returns error message if unable to read sourceMap file', async () => {
const err = new Error('ENOENT: no such file or directory');
spyReadFile.mockImplementationOnce(() => Promise.reject(err));
await expect(plugin.uploadSourceMap(compilation, chunk)).rejects.toThrow(
`failed to upload vendor.5190.js.map to Rollbar: ${err.message}`
);
});

it('returns response status text if response body does not have message', async () => {
const scope = nock('https://api.rollbar.com:443') // eslint-disable-line no-unused-vars
.post('/api/1/sourcemap')
Expand Down

0 comments on commit 8bb1a52

Please sign in to comment.