Skip to content
Merged
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"repository": "https://github.com/AriPerkkio/vite-plugin-source-map-visualizer",
"scripts": {
"build": "rm -rf ./dist && tsc --project tsconfig.build.json && cp src/*.css dist",
"test": "vitest --coverage",
"test": "vitest --coverage --coverage.include=src",
"typecheck": "tsc --noEmit",
"example": "node scripts/generate-example.mjs",
"deploy": "touch example/.nojekyll && gh-pages --dist example --dotfiles true"
Expand Down
23 changes: 18 additions & 5 deletions src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from "node:fs/promises";
import { join } from "node:path";
import type { Logger, Plugin } from "vite";
import type { TransformResult } from "vite";

import { toVisualizer } from "./generate-link.js";
import { script, style } from "./report.js";
Expand All @@ -25,6 +26,8 @@ interface Result {
filename: string;
hash: string;
ssr: boolean;
code: TransformResult["code"];
map: TransformResult["map"];
}

/**
Expand Down Expand Up @@ -76,8 +79,9 @@ export function sourcemapVisualizer(options?: Options): Plugin {
const map = this.getCombinedSourcemap();
const hash = toVisualizer({ code, map });
const filename = formatName(id);
const ssr = options?.ssr || false;

results.push({ filename, hash, ssr: options?.ssr || false });
results.push({ filename, hash, code, map, ssr });
},

async buildEnd() {
Expand Down Expand Up @@ -116,13 +120,21 @@ function generateHTML(results: Result[]) {
<a href="#">Vite Source Map Visualizer</a>
</h1>

<button id="json-view-toggle" title="View transform results" style="display: none;">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><g><rect width="24" height="24" opacity="0"/><path d="M15 16H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2z"/><path d="M9 14h3a1 1 0 0 0 0-2H9a1 1 0 0 0 0 2z"/><path d="M19.74 8.33l-5.44-6a1 1 0 0 0-.74-.33h-7A2.53 2.53 0 0 0 4 4.5v15A2.53 2.53 0 0 0 6.56 22h10.88A2.53 2.53 0 0 0 20 19.5V9a1 1 0 0 0-.26-.67zM14 5l2.74 3h-2a.79.79 0 0 1-.74-.85zm3.44 15H6.56a.53.53 0 0 1-.56-.5v-15a.53.53 0 0 1 .56-.5H12v3.15A2.79 2.79 0 0 0 14.71 10H18v9.5a.53.53 0 0 1-.56.5z"/></g></g></svg>
</button>

<button id="visualizer-view-toggle" title="View visualizer" style="display: none;">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><g><rect width="24" height="24" opacity="0"/><path d="M20.71 19.29l-3.4-3.39A7.92 7.92 0 0 0 19 11a8 8 0 1 0-8 8 7.92 7.92 0 0 0 4.9-1.69l3.39 3.4a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42zM5 11a6 6 0 1 1 6 6 6 6 0 0 1-6-6z"/></g></g></svg>
</button>

<button id="menu" title="Toggle file list">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g data-name="Layer 2"><g data-name="menu"><rect width="24" height="24" transform="rotate(180 12 12)" opacity="0"/><rect x="3" y="11" width="18" height="2" rx=".95" ry=".95"/><rect x="3" y="16" width="18" height="2" rx=".95" ry=".95"/><rect x="3" y="6" width="18" height="2" rx=".95" ry=".95"/></g></g></svg>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><g><rect width="24" height="24" transform="rotate(180 12 12)" opacity="0"/><rect x="3" y="11" width="18" height="2" rx=".95" ry=".95"/><rect x="3" y="16" width="18" height="2" rx=".95" ry=".95"/><rect x="3" y="6" width="18" height="2" rx=".95" ry=".95"/></g></g></svg>
</button>

<button id="theme-toggle" title="Toggle theme">
<svg id="theme-icon-light" class="theme-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g data-name="Layer 2"><g data-name="sun"><rect width="24" height="24" transform="rotate(180 12 12)" opacity="0"/><path d="M12 6a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v2a1 1 0 0 0 1 1z"/><path d="M21 11h-2a1 1 0 0 0 0 2h2a1 1 0 0 0 0-2z"/><path d="M6 12a1 1 0 0 0-1-1H3a1 1 0 0 0 0 2h2a1 1 0 0 0 1-1z"/><path d="M6.22 5a1 1 0 0 0-1.39 1.47l1.44 1.39a1 1 0 0 0 .73.28 1 1 0 0 0 .72-.31 1 1 0 0 0 0-1.41z"/><path d="M17 8.14a1 1 0 0 0 .69-.28l1.44-1.39A1 1 0 0 0 17.78 5l-1.44 1.42a1 1 0 0 0 0 1.41 1 1 0 0 0 .66.31z"/><path d="M12 18a1 1 0 0 0-1 1v2a1 1 0 0 0 2 0v-2a1 1 0 0 0-1-1z"/><path d="M17.73 16.14a1 1 0 0 0-1.39 1.44L17.78 19a1 1 0 0 0 .69.28 1 1 0 0 0 .72-.3 1 1 0 0 0 0-1.42z"/><path d="M6.27 16.14l-1.44 1.39a1 1 0 0 0 0 1.42 1 1 0 0 0 .72.3 1 1 0 0 0 .67-.25l1.44-1.39a1 1 0 0 0-1.39-1.44z"/><path d="M12 8a4 4 0 1 0 4 4 4 4 0 0 0-4-4zm0 6a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></g></g></svg>
<svg id="theme-icon-dark" class="theme-dark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g data-name="Layer 2"><g data-name="moon"><rect width="24" height="24" opacity="0"/><path d="M12.3 22h-.1a10.31 10.31 0 0 1-7.34-3.15 10.46 10.46 0 0 1-.26-14 10.13 10.13 0 0 1 4-2.74 1 1 0 0 1 1.06.22 1 1 0 0 1 .24 1 8.4 8.4 0 0 0 1.94 8.81 8.47 8.47 0 0 0 8.83 1.94 1 1 0 0 1 1.27 1.29A10.16 10.16 0 0 1 19.6 19a10.28 10.28 0 0 1-7.3 3zM7.46 4.92a7.93 7.93 0 0 0-1.37 1.22 8.44 8.44 0 0 0 .2 11.32A8.29 8.29 0 0 0 12.22 20h.08a8.34 8.34 0 0 0 6.78-3.49A10.37 10.37 0 0 1 7.46 4.92z"/></g></g></svg>
<svg id="theme-icon-light" aria-hidden="true" class="theme-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><g><rect width="24" height="24" transform="rotate(180 12 12)" opacity="0"/><path d="M12 6a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v2a1 1 0 0 0 1 1z"/><path d="M21 11h-2a1 1 0 0 0 0 2h2a1 1 0 0 0 0-2z"/><path d="M6 12a1 1 0 0 0-1-1H3a1 1 0 0 0 0 2h2a1 1 0 0 0 1-1z"/><path d="M6.22 5a1 1 0 0 0-1.39 1.47l1.44 1.39a1 1 0 0 0 .73.28 1 1 0 0 0 .72-.31 1 1 0 0 0 0-1.41z"/><path d="M17 8.14a1 1 0 0 0 .69-.28l1.44-1.39A1 1 0 0 0 17.78 5l-1.44 1.42a1 1 0 0 0 0 1.41 1 1 0 0 0 .66.31z"/><path d="M12 18a1 1 0 0 0-1 1v2a1 1 0 0 0 2 0v-2a1 1 0 0 0-1-1z"/><path d="M17.73 16.14a1 1 0 0 0-1.39 1.44L17.78 19a1 1 0 0 0 .69.28 1 1 0 0 0 .72-.3 1 1 0 0 0 0-1.42z"/><path d="M6.27 16.14l-1.44 1.39a1 1 0 0 0 0 1.42 1 1 0 0 0 .72.3 1 1 0 0 0 .67-.25l1.44-1.39a1 1 0 0 0-1.39-1.44z"/><path d="M12 8a4 4 0 1 0 4 4 4 4 0 0 0-4-4zm0 6a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></g></g></svg>
<svg id="theme-icon-dark" aria-hidden="true" class="theme-dark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><g><rect width="24" height="24" opacity="0"/><path d="M12.3 22h-.1a10.31 10.31 0 0 1-7.34-3.15 10.46 10.46 0 0 1-.26-14 10.13 10.13 0 0 1 4-2.74 1 1 0 0 1 1.06.22 1 1 0 0 1 .24 1 8.4 8.4 0 0 0 1.94 8.81 8.47 8.47 0 0 0 8.83 1.94 1 1 0 0 1 1.27 1.29A10.16 10.16 0 0 1 19.6 19a10.28 10.28 0 0 1-7.3 3zM7.46 4.92a7.93 7.93 0 0 0-1.37 1.22 8.44 8.44 0 0 0 .2 11.32A8.29 8.29 0 0 0 12.22 20h.08a8.34 8.34 0 0 0 6.78-3.49A10.37 10.37 0 0 1 7.46 4.92z"/></g></g></svg>
</button>

<details id="files" open>
Expand Down Expand Up @@ -150,7 +162,7 @@ function generateHTML(results: Result[]) {
</td>
<td class="center">
<a title="Open in source-map-visualization" target="_blank" href="https://evanw.github.io/source-map-visualization#${result.hash}">
<svg class="icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g data-name="Layer 2"><g data-name="external-link"><rect width="24" height="24" opacity="0"/><path d="M20 11a1 1 0 0 0-1 1v6a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h6a1 1 0 0 0 0-2H6a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3h12a3 3 0 0 0 3-3v-6a1 1 0 0 0-1-1z"/><path d="M16 5h1.58l-6.29 6.28a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0L19 6.42V8a1 1 0 0 0 1 1 1 1 0 0 0 1-1V4a1 1 0 0 0-1-1h-4a1 1 0 0 0 0 2z"/></g></g></svg>
<svg class="icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><g><rect width="24" height="24" opacity="0"/><path d="M20 11a1 1 0 0 0-1 1v6a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h6a1 1 0 0 0 0-2H6a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3h12a3 3 0 0 0 3-3v-6a1 1 0 0 0-1-1z"/><path d="M16 5h1.58l-6.29 6.28a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0L19 6.42V8a1 1 0 0 0 1 1 1 1 0 0 0 1-1V4a1 1 0 0 0-1-1h-4a1 1 0 0 0 0 2z"/></g></g></svg>
</a>
</td>
</tr>
Expand All @@ -160,6 +172,7 @@ function generateHTML(results: Result[]) {

</details>

<div id="json-visualizer" style="display: none;"></div>
<iframe id="source-map-visualizer" style="display: none;"></iframe>
</main>
<script>
Expand Down
63 changes: 63 additions & 0 deletions src/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,34 @@ export function script() {
fileList.open = !fileList.open;
});

const jsonView = document.getElementById("json-visualizer")!;
const visualizerView = document.getElementById("source-map-visualizer")!;
const jsonViewToggle = document.querySelector(
"button#json-view-toggle" as "button"
)!;
const visualizerViewToggle = document.querySelector(
"button#visualizer-view-toggle" as "button"
)!;

function setView(view: "json-view" | "visualizer-view") {
if (view === "json-view") {
visualizerView.style.display = "none";
jsonViewToggle.style.display = "none";
visualizerViewToggle.style.display = "block";
jsonView.style.display = "block";
} else {
jsonView.style.display = "none";
visualizerViewToggle.style.display = "none";
visualizerView.style.display = "block";
jsonViewToggle.style.display = "block";
}
}

jsonViewToggle.addEventListener("click", () => setView("json-view"));
visualizerViewToggle.addEventListener("click", () =>
setView("visualizer-view")
);

initializePage();
addEventListener("hashchange", initializePage);

Expand All @@ -32,14 +60,49 @@ export function script() {
"iframe#source-map-visualizer" as "iframe"
)!;

Array.from(jsonView.children).map((child) => jsonView.removeChild(child));

if (window.location.hash) {
iframe.src = `https://evanw.github.io/source-map-visualization${window.location.hash}`;
iframe.style.display = "block";
fileList.open = false;
setView("visualizer-view");

const result = convertHash(window.location.hash.slice(1));
const code = document.createElement("pre");
code.textContent = result.code;
jsonView.appendChild(code);

const map = document.createElement("pre");
map.textContent = JSON.stringify(result.map, null, 2);
jsonView.appendChild(map);
} else {
iframe.src = "";
iframe.style.display = "none";
fileList.open = true;

visualizerView.style.display = "none";
visualizerViewToggle.style.display = "none";
jsonView.style.display = "none";
jsonViewToggle.style.display = "none";
}
}

function convertHash(hash: string) {
let bin = atob(hash);
const code = readBuffer();
const map = readBuffer();

return { code, map: JSON.parse(map) };

function readBuffer() {
const zero = bin.indexOf("\0");
const start = zero + 1;
const end = start + (0 | parseInt(bin.slice(0, zero)));
const buffer = decodeURIComponent(bin.slice(start, end));

bin = bin.slice(end);
return buffer;
}
}
}
Expand Down
28 changes: 23 additions & 5 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ h1 {
}

button#theme-toggle,
button#menu {
button#menu,
button#json-view-toggle,
button#visualizer-view-toggle {
width: 3rem;
height: 3rem;
border: 0;
Expand All @@ -63,18 +65,23 @@ button#menu {
}

button#theme-toggle {
right: 1rem;
right: 2rem;
}

button#menu {
right: 5rem;
right: 6rem;
}

button#json-view-toggle,
button#visualizer-view-toggle {
right: 10rem;
}

a {
color: var(--text-accent);
}

details#files {
details#files[open] {
margin: 2rem;
}

Expand Down Expand Up @@ -105,5 +112,16 @@ svg.icon {

iframe {
height: 100%;
margin: 1rem;
margin: 2rem;
}

#json-visualizer {
margin: 2rem;
}

#json-visualizer pre {
overflow: auto;
border: 0.1rem solid var(--border);
margin-bottom: 2rem;
padding: 2rem;
}