Skip to content

Commit e27ee95

Browse files
authored
webpack plugin: update plugin to use common code (#56)
* sourcemap tools: fix doesSourceMapHaveSources with undefined sources array * sourcemap tools: add functions in AsyncResult * sourcemap tools: add common helpers from CLI to sourcemap-tools and use them * sourcemap tools: add some common functions and match functions * sourcemap tools: add common code for managing sourcemaps * webpack: update plugin to use common code --------- Co-authored-by: Sebastian Alex <sebastian.alex@saucelabs.com>
1 parent 394cc50 commit e27ee95

File tree

1 file changed

+19
-110
lines changed

1 file changed

+19
-110
lines changed
Lines changed: 19 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,132 +1,41 @@
1-
import { DebugIdGenerator, SourceProcessor, SymbolUploader, ZipArchive } from '@backtrace/sourcemap-tools';
2-
import fs from 'fs';
1+
import { Asset, matchSourceExtension, processAndUploadAssetsCommand } from '@backtrace/sourcemap-tools';
32
import path from 'path';
43
import webpack, { WebpackPluginInstance } from 'webpack';
54
import { BacktracePluginOptions } from './models/BacktracePluginOptions';
65

76
export class BacktracePlugin implements WebpackPluginInstance {
8-
private readonly _sourceProcessor: SourceProcessor;
9-
private readonly _sourceMapUploader?: SymbolUploader;
10-
11-
constructor(public readonly options?: BacktracePluginOptions) {
12-
this._sourceProcessor = new SourceProcessor(new DebugIdGenerator());
13-
this._sourceMapUploader = options?.uploadUrl
14-
? new SymbolUploader(options.uploadUrl, options.uploadOptions)
15-
: undefined;
16-
}
7+
constructor(public readonly options?: BacktracePluginOptions) {}
178

189
public apply(compiler: webpack.Compiler) {
19-
const processResults = new Map<string, string | Error>();
20-
let uploadResult: string | Error | undefined;
21-
2210
compiler.hooks.afterEmit.tapPromise(BacktracePlugin.name, async (compilation) => {
2311
const logger = compilation.getLogger(BacktracePlugin.name);
24-
if (!compilation.outputOptions.path) {
12+
const outputDir = compilation.outputOptions.path;
13+
if (!outputDir) {
2514
logger.error(
2615
'Skipping everything because outputOptions.path is not set. If you see this error, please report this to Backtrace.',
2716
);
2817
return;
2918
}
3019

31-
const entries: [string, string, string][] = [];
32-
33-
for (const asset in compilation.assets) {
34-
if (!asset.match(/\.(c|m)?jsx?$/)) {
35-
logger.debug(`[${asset}] skipping processing, extension does not match`);
36-
continue;
37-
}
38-
39-
const map = asset + '.map';
40-
if (!compilation.assets[map]) {
41-
logger.debug(`[${asset}] skipping processing, map file not found`);
42-
continue;
43-
}
44-
45-
const assetPath = path.join(compilation.outputOptions.path, asset);
46-
const sourceMapPath = path.join(compilation.outputOptions.path, map);
47-
48-
logger.debug(`adding asset ${assetPath} with sourcemap ${sourceMapPath}`);
49-
entries.push([asset, assetPath, sourceMapPath]);
50-
}
51-
52-
logger.log(`received ${entries.length} files for processing`);
53-
54-
for (const [asset, sourcePath, sourceMapPath] of entries) {
55-
let debugId: string;
20+
const processAndUpload = processAndUploadAssetsCommand(this.options ?? {}, {
21+
beforeAll: (assets) => logger.log(`processing ${assets.length} files`),
5622

57-
logger.time(`[${asset}] process source and sourcemap`);
58-
try {
59-
const result = await this._sourceProcessor.processSourceAndSourceMapFiles(
60-
sourcePath,
61-
sourceMapPath,
62-
);
23+
afterProcess: (asset) => logger.log(`[${asset.asset.name}] processed source and sourcemap`),
24+
afterWrite: (asset) => logger.log(`[${asset.asset.name}] wrote source and sourcemap to file`),
25+
assetFinished: (asset) => logger.info(`[${asset.asset.name}] asset processed successfully`),
26+
assetError: (asset) => logger.error(`[${asset.asset.name}] ${asset.error}`),
6327

64-
if (result.isErr()) {
65-
logger.error(`[${asset}] process source and sourcemap failed:`, result.data);
66-
processResults.set(asset, new Error(result.data));
67-
continue;
68-
}
28+
beforeArchive: (paths) => logger.log(`creating archive to upload from ${paths.length} files`),
29+
beforeUpload: () => logger.log(`uploading sourcemaps...`),
30+
afterUpload: (result) => logger.info(`sourcemaps uploaded to Backtrace: ${result.rxid}`),
31+
uploadError: (error) => logger.error(`failed to upload sourcemaps: ${error}`),
32+
});
6933

70-
debugId = result.data.debugId;
71-
await fs.promises.writeFile(sourcePath, result.data.source, 'utf8');
72-
await fs.promises.writeFile(sourceMapPath, JSON.stringify(result.data.sourceMap), 'utf8');
34+
const assets = Object.keys(compilation.assets)
35+
.filter(matchSourceExtension)
36+
.map<Asset>((asset) => ({ name: asset, path: path.join(outputDir, asset) }));
7337

74-
processResults.set(asset, debugId);
75-
} catch (err) {
76-
logger.error(`[${asset}] process source and sourcemap failed:`, err);
77-
processResults.set(asset, err instanceof Error ? err : new Error('Unknown error.'));
78-
continue;
79-
} finally {
80-
logger.timeEnd(`[${asset}] process source and sourcemap`);
81-
}
82-
}
83-
84-
if (this._sourceMapUploader) {
85-
logger.time(`upload sourcemaps`);
86-
try {
87-
const archive = new ZipArchive();
88-
const request = this._sourceMapUploader.uploadSymbol(archive);
89-
90-
for (const [asset, _, sourceMapPath] of entries) {
91-
const stream = fs.createReadStream(sourceMapPath);
92-
archive.append(`${asset}.map`, stream);
93-
}
94-
95-
await archive.finalize();
96-
const result = await request;
97-
if (result.isErr()) {
98-
logger.error(`upload sourcemaps failed:`, result.data);
99-
uploadResult = new Error(result.data);
100-
} else {
101-
uploadResult = result.data.rxid;
102-
}
103-
} catch (err) {
104-
logger.error(`upload sourcemaps failed:`, err);
105-
uploadResult = err instanceof Error ? err : new Error('Unknown error.');
106-
} finally {
107-
logger.timeEnd(`upload sourcemaps`);
108-
}
109-
}
110-
111-
for (const [key, result] of processResults) {
112-
if (typeof result === 'string') {
113-
logger.info(`[${key}] processed file successfully`);
114-
logger.debug(`\tdebugId: ${result}`);
115-
} else {
116-
logger.error(`[${key}] failed to process file: ${result.message}`);
117-
logger.debug(`Error stack trace: ${result.stack}`);
118-
}
119-
}
120-
121-
if (uploadResult) {
122-
if (typeof uploadResult === 'string') {
123-
logger.info(`uploaded sourcemaps successfully`);
124-
logger.debug(`\trxid: ${uploadResult}`);
125-
} else {
126-
logger.error(`failed to upload sourcemaps: ${uploadResult.message}`);
127-
logger.debug(`Error stack trace: ${uploadResult.stack}`);
128-
}
129-
}
38+
await processAndUpload(assets);
13039
});
13140
}
13241
}

0 commit comments

Comments
 (0)