Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 10 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tools/webpack-plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
webpackBuild/
5 changes: 4 additions & 1 deletion tools/webpack-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
},
"scripts": {
"build": "tsc -b ./tsconfig.build.json",
"build:webpack": "webpack",
"clean": "tsc -b ./tsconfig.build.json --clean && rimraf \"lib\"",
"format": "prettier --write '**/*.ts'",
"lint": "eslint . --ext .ts",
Expand Down Expand Up @@ -45,9 +46,11 @@
"jest": "^29.5.0",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.3 || ^8.4.0",
"ts-loader-webpack-4": "npm:ts-loader@^8.4.0",
"typescript": "^5.0.4",
"webpack-4": "npm:webpack@^4.46.0",
"ts-loader-webpack-4": "npm:ts-loader@^8.4.0",
"webpack-cli": "^5.1.4",
"webpack-node-externals": "^3.0.0",
"webpack-sources-webpack-4": "npm:webpack-sources@^1.4.1"
},
"dependencies": {
Expand Down
119 changes: 86 additions & 33 deletions tools/webpack-plugin/src/BacktracePluginV4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import crypto from 'crypto';
import path from 'path';
import { Compiler, WebpackPluginInstance } from 'webpack';
import { BacktraceWebpackSourceGenerator } from './BacktraceWebpackSourceGenerator';
import { statsPrinter } from './helpers/statsPrinter';
import { AssetStats } from './models/AssetStats';
import { BacktracePluginOptions } from './models/BacktracePluginOptions';

export class BacktracePluginV4 implements WebpackPluginInstance {
Expand All @@ -20,62 +22,113 @@ export class BacktracePluginV4 implements WebpackPluginInstance {
}

public apply(compiler: Compiler) {
const assetDebugIds = new Map<string, string>();
const assetStats = new Map<string, AssetStats>();

compiler.hooks.emit.tap(BacktracePluginV4.name, (compilation) => {
const logger = compilation.getLogger(BacktracePluginV4.name);
for (const key in compilation.assets) {
let source = compilation.assets[key];

let debugId;
if (key.match(/.(c|m)?jsx?$/)) {
debugId = crypto.randomUUID();
assetDebugIds.set(key, debugId);
if (key.match(/\.(c|m)?jsx?$/)) {
const debugId = crypto.randomUUID();
const stats: AssetStats = { debugId };
assetStats.set(key, stats);
logger.log(`[${key}] generated debug ID ${debugId}`);

source = this._sourceGenerator.addDebugIdToSource(source as never, debugId) as typeof source;
source = this._sourceGenerator.addDebugIdCommentToSource(source as never, debugId) as typeof source;
logger.time(`[${key}] inject source snippet`);
try {
source = this._sourceGenerator.addDebugIdToSource(source as never, debugId) as typeof source;
logger.timeEnd(`[${key}] inject source snippet`);
stats.sourceSnippet = true;
} catch (err) {
stats.sourceSnippet = err instanceof Error ? err : new Error('Unknown error.');
}

logger.time(`[${key}] inject sourcemap key`);
try {
source = this._sourceGenerator.addDebugIdCommentToSource(
source as never,
debugId,
) as typeof source;
logger.timeEnd(`[${key}] inject sourcemap key`);
stats.sourceComment = true;
} catch (err) {
stats.sourceComment = err instanceof Error ? err : new Error('Unknown error.');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the time command from line 47 will never end. Should we add an error log about that? RIght now the user needs to check the source map comment however no one will do that in practice

}
} else if (key.match(/\.(c|m)?jsx?\.map$/)) {
// The .map replacement should account for most of the use cases
const sourceKey = key.replace(/.map$/, '');
debugId = assetDebugIds.get(sourceKey);
if (!debugId) {
const stats = assetStats.get(sourceKey);
if (!stats) {
continue;
}

source = this._sourceGenerator.addDebugIdToRawSourceMap(source as never, debugId) as never;
logger.time(`[${key}] append sourcemap key`);
try {
source = this._sourceGenerator.addDebugIdToRawSourceMap(
source as never,
stats.debugId,
) as never;
logger.timeEnd(`[${key}] append sourcemap key`);
stats.sourceMapAppend = true;
} catch (err) {
stats.sourceMapAppend = err instanceof Error ? err : new Error('Unknown error.');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the time command from line 66 will not end. Should we add a log error about that?

}
}

compilation.assets[key] = source;
}
});

const uploader = this._sourceMapUploader;
if (uploader) {
compiler.hooks.afterEmit.tapPromise(BacktracePluginV4.name, async (compilation) => {
const outputPath = compilation.outputOptions.path;
if (!outputPath) {
throw new Error('Output path is required to upload sourcemaps.');
compiler.hooks.afterEmit.tapPromise(BacktracePluginV4.name, async (compilation) => {
const logger = compilation.getLogger(BacktracePluginV4.name);

const outputPath = compilation.outputOptions.path;
if (!outputPath) {
throw new Error('Output path is required to upload sourcemaps.');
}

for (const key in compilation.assets) {
if (!key.match(/\.(c|m)?jsx?\.map$/)) {
continue;
}

for (const key in compilation.assets) {
if (!key.match(/\.(c|m)?jsx?\.map$/)) {
continue;
}
const sourceKey = key.replace(/.map$/, '');
const stats = assetStats.get(sourceKey);
if (!stats) {
continue;
}

const sourceKey = key.replace(/.map$/, '');
const debugId = assetDebugIds.get(sourceKey);
if (!debugId) {
continue;
}
const sourceMapAsset = compilation.getAsset(key);
if (!sourceMapAsset) {
stats.sourceMapUpload = false;
continue;
}

const sourceMapAsset = compilation.getAsset(key);
if (!sourceMapAsset) {
continue;
}
if (!this._sourceMapUploader) {
stats.sourceMapUpload = false;
continue;
}

const sourceMapPath = path.join(outputPath, sourceMapAsset.name);
await uploader.upload(sourceMapPath, debugId);
const sourceMapPath = path.join(outputPath, sourceMapAsset.name);

logger.time(`[${key}] upload sourcemap`);
try {
const result = await this._sourceMapUploader.upload(sourceMapPath, stats.debugId);
logger.timeEnd(`[${key}] upload sourcemap`);
stats.sourceMapUpload = result;
} catch (err) {
stats.sourceMapAppend = err instanceof Error ? err : new Error('Unknown error.');
}
});
}
logger.timeEnd(`[${key}] upload sourcemap`);
}
});

compiler.hooks.afterEmit.tap(BacktracePluginV4.name, (compilation) => {
const printer = statsPrinter(compilation.getLogger(BacktracePluginV4.name));
for (const [key, stats] of assetStats) {
printer(key, stats);
}
});
}
}
Loading