CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-source-map-explorer

Analyze and debug space usage through source maps

Pending
Overview
Eval results
Files

analysis-results.mddocs/

Analysis Results

Structured data format for bundle analysis results, including file size breakdowns, error handling, and formatted output.

Capabilities

Main Result Interface

The primary result structure returned by the explore function.

interface ExploreResult {
  /** Array of successfully analyzed bundles */
  bundles: ExploreBundleResult[];
  /** Result as a string - either JSON, TSV or HTML */
  output?: string;
  /** Array of errors and warnings from analysis */
  errors: ExploreErrorResult[];
}

Usage Examples:

import { explore } from "source-map-explorer";

const result = await explore("dist/bundle.js");

// Access bundle data
console.log(result.bundles[0].totalBytes);
console.log(result.bundles[0].files);

// Handle errors
if (result.errors.length > 0) {
  result.errors.forEach(error => {
    console.error(`${error.bundleName}: ${error.message}`);
  });
}

// Use formatted output if requested
if (result.output) {
  console.log(result.output); // JSON, TSV, or HTML string
}

Bundle Analysis Results

Detailed results for each successfully analyzed bundle.

interface ExploreBundleResult {
  /** Display name for the bundle */
  bundleName: string;
  /** Map of source files to their size data */
  files: FileDataMap;
  /** Total bytes that were successfully mapped to source files */
  mappedBytes: number;
  /** Bytes that could not be mapped to source files */
  unmappedBytes?: number;
  /** Bytes consumed by end-of-line characters */
  eolBytes: number;
  /** Bytes consumed by sourceMappingURL comment */
  sourceMapCommentBytes: number;
  /** Total size of the bundle file */
  totalBytes: number;
}

type FileDataMap = Record<string, FileData>;

interface FileData {
  /** Size in bytes contributed by this file */
  size: number;
  /** Size in bytes covered by code coverage (if coverage data provided) */
  coveredSize?: number;
}

Usage Examples:

const result = await explore("dist/bundle.js");
const bundle = result.bundles[0];

// Access size information  
console.log(`Total bundle size: ${bundle.totalBytes} bytes`);
console.log(`Mapped to sources: ${bundle.mappedBytes} bytes`);
console.log(`Unmapped: ${bundle.unmappedBytes || 0} bytes`);

// Iterate through source files
Object.entries(bundle.files).forEach(([filename, data]) => {
  console.log(`${filename}: ${data.size} bytes`);
  if (data.coveredSize !== undefined) {
    console.log(`  Coverage: ${data.coveredSize}/${data.size} bytes`);
  }
});

// Find largest contributors
const sortedFiles = Object.entries(bundle.files)
  .sort(([,a], [,b]) => b.size - a.size)
  .slice(0, 10);

console.log("Top 10 largest files:");
sortedFiles.forEach(([filename, data]) => {
  console.log(`  ${filename}: ${data.size} bytes`);
});

Error Results

Error information for bundles that could not be analyzed successfully.

interface ExploreErrorResult {
  /** Name of the bundle that failed */
  bundleName: string;
  /** Error code identifier */
  code: string;
  /** Human-readable error message */
  message: string;
  /** Original error object if available */
  error?: NodeJS.ErrnoException;
  /** True if this is a warning rather than a fatal error */
  isWarning?: boolean;
}

Usage Examples:

const result = await explore(["good-bundle.js", "bad-bundle.js"]);

// Separate errors from warnings
const errors = result.errors.filter(e => !e.isWarning);
const warnings = result.errors.filter(e => e.isWarning);

// Handle fatal errors
errors.forEach(error => {
  console.error(`ERROR [${error.code}] ${error.bundleName}: ${error.message}`);
  if (error.error) {
    console.error("  Caused by:", error.error.message);
  }
});

// Handle warnings  
warnings.forEach(warning => {
  console.warn(`WARNING [${warning.code}] ${warning.bundleName}: ${warning.message}`);
});

// Check if any bundles succeeded
if (result.bundles.length === 0) {
  console.error("No bundles were successfully analyzed");
  process.exit(1);
}

Special File Keys

Analysis results include special keys for different types of content:

// Special filename constants used in results
const UNMAPPED_KEY = "[unmapped]";           // Bytes not mapped to source files
const SOURCE_MAP_COMMENT_KEY = "[sourceMappingURL]"; // Source map comment bytes  
const NO_SOURCE_KEY = "[no source]";         // Mapped bytes without source info
const EOL_KEY = "[EOLs]";                   // End-of-line character bytes

Usage Examples:

import { explore, UNMAPPED_KEY, SOURCE_MAP_COMMENT_KEY } from "source-map-explorer";

const result = await explore("bundle.js");
const files = result.bundles[0].files;

// Check for unmapped bytes
if (files[UNMAPPED_KEY]) {
  console.log(`Unmapped bytes: ${files[UNMAPPED_KEY].size}`);
}

// Check source map comment size
if (files[SOURCE_MAP_COMMENT_KEY]) {
  console.log(`Source map comment: ${files[SOURCE_MAP_COMMENT_KEY].size} bytes`);
}

// Filter out special keys to get only source files
const sourceFiles = Object.entries(files).filter(([filename]) => 
  !filename.startsWith("[") || !filename.endsWith("]")
);

console.log(`Found ${sourceFiles.length} source files`);

Output Formats

JSON Output

Structured data format for programmatic processing.

const result = await explore("bundle.js", { 
  output: { format: "json" } 
});

// result.output contains JSON string
const data = JSON.parse(result.output);
console.log(data.results[0].files);

JSON Structure:

{
  "results": [
    {
      "bundleName": "bundle.js",
      "totalBytes": 12345,
      "mappedBytes": 11000,
      "unmappedBytes": 1000,
      "eolBytes": 200,
      "sourceMapCommentBytes": 145,
      "files": {
        "src/main.js": { "size": 2500 },
        "src/utils.js": { "size": 1200 },
        "node_modules/lodash/index.js": { "size": 7300 },
        "[unmapped]": { "size": 1000 }
      }
    }
  ]
}

TSV Output

Tab-separated values format for spreadsheet import and analysis.

const result = await explore("bundle.js", { 
  output: { format: "tsv" } 
});

// result.output contains TSV string
console.log(result.output);

TSV Format:

Source	Size
src/main.js	2500
node_modules/lodash/index.js	7300
src/utils.js	1200
[unmapped]	1000
[sourceMappingURL]	145

HTML Output

Interactive treemap visualization for visual analysis.

const result = await explore("bundle.js", { 
  output: { format: "html" } 
});

// result.output contains complete HTML document
fs.writeFileSync("analysis.html", result.output);

The HTML output includes:

  • Interactive treemap visualization using d3.js
  • Hover tooltips showing file sizes and percentages
  • Clickable navigation for drilling into directories
  • Color coding for coverage data (if provided)
  • Responsive design for different screen sizes

Coverage Data Integration

When Chrome DevTools coverage data is provided, results include coverage information:

const result = await explore("bundle.js", {
  coverage: "coverage.json"
});

// FileData includes coveredSize when coverage is available
const files = result.bundles[0].files;
Object.entries(files).forEach(([filename, data]) => {
  if (data.coveredSize !== undefined) {
    const coverage = (data.coveredSize / data.size * 100).toFixed(1);
    console.log(`${filename}: ${coverage}% covered`);
  }
});

Coverage data affects:

  • HTML visualization colors (red = low coverage, green = high coverage)
  • FileData objects include coveredSize property
  • Analysis warnings for files with zero coverage

Install with Tessl CLI

npx tessl i tessl/npm-source-map-explorer

docs

analysis-results.md

bundle-analysis.md

configuration.md

error-handling.md

index.md

tile.json