mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 19:08:50 +00:00
Complete working code flow visualizer with real output
The visualizer now fully works with: - Actual source code snippets from input files (500 chars) - Real JavaScript output from bundled chunks (1000 chars) - New 'after_generation' stage that captures output after compilation - HTML displays real source and output side-by-side - Both visualizers generated: graph and code flow To use: 1. Set BUN_BUNDLER_GRAPH_DUMP=all when bundling 2. Open code_flow_*.html from /tmp/bun-bundler-debug/ 3. Load the after_generation JSON to see source→output transformation Example: env BUN_BUNDLER_GRAPH_DUMP=all bun build app.js --target=browser The code flow visualizer shows actual code transformations, while the graph visualizer shows the overall bundle structure. Tested and working with multi-file bundles showing real transformations.
This commit is contained in:
@@ -306,6 +306,7 @@
|
||||
<option value="after_compute">After Compute</option>
|
||||
<option value="after_chunks">After Chunks</option>
|
||||
<option value="after_link">After Link</option>
|
||||
<option value="after_generation">After Generation (with output)</option>
|
||||
</select>
|
||||
<button id="compare-btn">📊 Compare Stages</button>
|
||||
</div>
|
||||
@@ -456,10 +457,18 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// For now, show mock source code with file metadata
|
||||
// In real implementation, we'd load actual source
|
||||
const mockSource = generateMockSource(file);
|
||||
sourceEditor.setValue(mockSource);
|
||||
// Use actual source snippet if available
|
||||
let sourceCode = '';
|
||||
if (file.source_snippet) {
|
||||
sourceCode = `// File: ${file.path}\n// Loader: ${file.loader}\n\n${file.source_snippet}`;
|
||||
if (file.source_snippet.length === 500) {
|
||||
sourceCode += '\n\n// ... (truncated at 500 chars)';
|
||||
}
|
||||
} else {
|
||||
sourceCode = generateMockSource(file);
|
||||
}
|
||||
|
||||
sourceEditor.setValue(sourceCode);
|
||||
|
||||
// Highlight symbols
|
||||
highlightSourceSymbols(data, file);
|
||||
@@ -472,9 +481,21 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// For now, show mock output with chunk metadata
|
||||
const mockOutput = generateMockOutput(chunk, data);
|
||||
outputEditor.setValue(mockOutput);
|
||||
// Use actual output snippet if available
|
||||
let outputCode = '';
|
||||
if (chunk.output_snippet) {
|
||||
outputCode = `// Chunk ${chunk.index}\n`;
|
||||
outputCode += `// Entry point: ${chunk.is_entry_point}\n`;
|
||||
outputCode += `// Output path: ${chunk.final_path || 'unknown'}\n\n`;
|
||||
outputCode += chunk.output_snippet;
|
||||
if (chunk.output_snippet.length === 1000) {
|
||||
outputCode += '\n\n// ... (truncated at 1000 chars)';
|
||||
}
|
||||
} else {
|
||||
outputCode = generateMockOutput(chunk, data);
|
||||
}
|
||||
|
||||
outputEditor.setValue(outputCode);
|
||||
|
||||
// Highlight transformed symbols
|
||||
highlightOutputSymbols(data, chunk);
|
||||
|
||||
@@ -40,6 +40,7 @@ pub const GraphVisualizer = struct {
|
||||
if (strings.eqlComptime(env_val, "compute")) return .after_compute;
|
||||
if (strings.eqlComptime(env_val, "chunks")) return .after_chunks;
|
||||
if (strings.eqlComptime(env_val, "link")) return .after_link;
|
||||
if (strings.eqlComptime(env_val, "generation")) return .after_generation;
|
||||
|
||||
return .all; // Default to all if set but not recognized
|
||||
}
|
||||
@@ -50,6 +51,7 @@ pub const GraphVisualizer = struct {
|
||||
after_compute,
|
||||
after_chunks,
|
||||
after_link,
|
||||
after_generation,
|
||||
all,
|
||||
};
|
||||
|
||||
@@ -58,9 +60,16 @@ pub const GraphVisualizer = struct {
|
||||
stage: []const u8,
|
||||
chunks: ?[]const Chunk,
|
||||
) !void {
|
||||
if (!shouldDump()) return;
|
||||
debug("dumpGraphState called for stage: {s}", .{stage});
|
||||
|
||||
if (!shouldDump()) {
|
||||
debug("shouldDump() returned false", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
const dump_stage = getDumpStage();
|
||||
debug("dump_stage: {}", .{dump_stage});
|
||||
|
||||
const should_dump_now = switch (dump_stage) {
|
||||
.none => false,
|
||||
.all => true,
|
||||
@@ -68,9 +77,15 @@ pub const GraphVisualizer = struct {
|
||||
.after_compute => strings.eqlComptime(stage, "after_compute"),
|
||||
.after_chunks => strings.eqlComptime(stage, "after_chunks"),
|
||||
.after_link => strings.eqlComptime(stage, "after_link"),
|
||||
.after_generation => strings.eqlComptime(stage, "after_generation"),
|
||||
};
|
||||
|
||||
if (!should_dump_now) return;
|
||||
if (!should_dump_now) {
|
||||
debug("should_dump_now is false for stage {s}", .{stage});
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Proceeding with dump for stage: {s}", .{stage});
|
||||
|
||||
debug("Dumping graph state: {s}", .{stage});
|
||||
|
||||
|
||||
@@ -193,6 +193,14 @@ pub fn generateChunksInParallel(
|
||||
}
|
||||
}
|
||||
|
||||
// Dump graph state after generation (includes output code)
|
||||
if (comptime Environment.isDebug) {
|
||||
const GraphVisualizer = @import("../graph_visualizer.zig").GraphVisualizer;
|
||||
GraphVisualizer.dumpGraphState(c, "after_generation", chunks) catch |err| {
|
||||
debug("Failed to dump graph after generation: {}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
// When bake.DevServer is in use, we're going to take a different code path at the end.
|
||||
// We want to extract the source code of each part instead of combining it into a single file.
|
||||
// This is so that when hot-module updates happen, we can:
|
||||
|
||||
Reference in New Issue
Block a user