CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-webpack-sources

Source code handling classes for webpack and other build tools with optional source map support

Pending
Overview
Eval results
Files

utility-classes.mddocs/

Utility Classes

Additional utilities for source compatibility and specialized use cases, including source-like object conversion and size-only sources.

Capabilities

CompatSource

Converts source-like objects into real Source instances, enabling compatibility with objects that implement the source interface but aren't actual Source instances.

/**
 * Converts source-like objects to real Sources
 * @param sourceLike - Object implementing source-like interface
 */
class CompatSource extends Source {
  constructor(sourceLike: SourceLike);
  
  /**
   * Static factory method that returns Source unmodified if already a Source,
   * otherwise wraps in CompatSource
   * @param sourceLike - Source or source-like object
   * @returns Real Source instance
   */
  static from(sourceLike: SourceLike): Source;
}

Usage Examples:

const { CompatSource } = require("webpack-sources");

// Source-like object (not a real Source)
const sourceLike = {
  source() {
    return "console.log('from source-like');";
  },
  size() {
    return 29;
  },
  map() {
    return null;
  }
};

// Convert to real Source
const compatSource = new CompatSource(sourceLike);
console.log(compatSource.source()); // "console.log('from source-like');"
console.log(compatSource instanceof Source); // true

// Static factory method - preferred approach
const source1 = CompatSource.from(sourceLike); // Wraps in CompatSource
const source2 = CompatSource.from(compatSource); // Returns as-is (already Source)

console.log(source1 !== sourceLike); // true - wrapped
console.log(source2 === compatSource); // true - not re-wrapped

// Use with objects that have partial source interface
const minimalSourceLike = {
  source: () => "minimal content"
  // size, map, etc. will use defaults
};

const minimal = CompatSource.from(minimalSourceLike);
console.log(minimal.size()); // Calculated from source content
console.log(minimal.map()); // null (default)

SizeOnlySource

Source that only provides size information without actual content. Useful for tracking sizes without storing large content in memory.

/**
 * Source that only provides size information
 * @param size - Size in bytes
 */
class SizeOnlySource extends Source {
  constructor(size: number);
}

Usage Examples:

const { SizeOnlySource } = require("webpack-sources");

// Create size-only source
const sizeOnly = new SizeOnlySource(1024);

console.log(sizeOnly.size()); // 1024

// Other methods throw errors - no actual content available
try {
  sizeOnly.source(); // Throws: "Content and Map of this Source is not available (only size() is supported)"
} catch (e) {
  console.log("Cannot get source:", e.message);
}

try {
  sizeOnly.buffer(); // Throws same error
} catch (e) {
  console.log("Cannot get buffer:", e.message);
}

try {
  sizeOnly.map(); // Throws same error  
} catch (e) {
  console.log("Cannot get map:", e.message);
}

// Useful for size calculations without content
const totalSize = sources.reduce((sum, source) => {
  return sum + source.size();
}, 0);

// Memory-efficient size tracking
const fileSizes = files.map(file => 
  new SizeOnlySource(file.stats.size)
);

Source-Like Interface

Interface definition for objects that can be converted to Sources via CompatSource.

/**
 * Interface for objects that can be converted to Sources
 */
interface SourceLike {
  /** Required: Returns source content */
  source(): string | Buffer;
  
  /** Optional: Returns content as Buffer (auto-generated if missing) */
  buffer?(): Buffer;
  
  /** Optional: Returns size in bytes (calculated if missing) */
  size?(): number;
  
  /** Optional: Returns source map (defaults to null) */
  map?(options?: MapOptions): RawSourceMap | null;
  
  /** Optional: Returns both source and map (auto-generated if missing) */
  sourceAndMap?(options?: MapOptions): SourceAndMap;
  
  /** Optional: Updates hash (defaults to abstract error if missing) */
  updateHash?(hash: HashLike): void;
}

Complete Implementation Example:

const { CompatSource } = require("webpack-sources");

// Full source-like implementation
class CustomSourceLike {
  constructor(content, filename) {
    this.content = content;
    this.filename = filename;
  }
  
  source() {
    return this.content;
  }
  
  buffer() {
    return Buffer.from(this.content, 'utf8');
  }
  
  size() {
    return this.content.length;
  }
  
  map(options) {
    // Custom source map generation
    return {
      version: 3,
      sources: [this.filename],
      names: [],
      mappings: "AAAA",
      file: this.filename
    };
  }
  
  sourceAndMap(options) {
    return {
      source: this.source(),
      map: this.map(options)
    };
  }
  
  updateHash(hash) {
    hash.update("CustomSourceLike");
    hash.update(this.content);
  }
}

const custom = new CustomSourceLike("console.log('test');", "test.js");
const source = CompatSource.from(custom);

console.log(source.source()); // "console.log('test');"
console.log(source.map().sources); // ["test.js"]

Utility Usage Patterns

Working with Unknown Sources:

const { CompatSource, Source } = require("webpack-sources");

function processAnySource(input) {
  // Ensure we have a real Source instance
  const source = CompatSource.from(input);
  
  // Now we can safely use all Source methods
  console.log("Size:", source.size());
  console.log("Content:", source.source());
  
  return source;
}

// Works with real Sources
processAnySource(new RawSource("test"));

// Works with source-like objects
processAnySource({
  source: () => "custom content",
  size: () => 14
});

Size Tracking Without Content:

const { SizeOnlySource, ConcatSource } = require("webpack-sources");

class BuildTracker {
  constructor() {
    this.chunks = [];
  }
  
  addChunk(name, size) {
    // Track size without storing content
    this.chunks.push({
      name,
      source: new SizeOnlySource(size)
    });
  }
  
  getTotalSize() {
    return this.chunks.reduce((sum, chunk) => {
      return sum + chunk.source.size();
    }, 0);
  }
  
  getSummary() {
    return this.chunks.map(chunk => ({
      name: chunk.name,
      size: chunk.source.size()
    }));
  }
}

const tracker = new BuildTracker();
tracker.addChunk("main.js", 45000);
tracker.addChunk("vendor.js", 120000);

console.log("Total size:", tracker.getTotalSize()); // 165000
console.log("Summary:", tracker.getSummary());

Compatibility Layer:

const { CompatSource } = require("webpack-sources");

// Legacy system that returns source-like objects
function legacySourceProvider(filename) {
  return {
    source: () => fs.readFileSync(filename, 'utf8'),
    // Missing other methods - CompatSource will provide defaults
  };
}

// Modern system that needs real Sources
function modernProcessor(source) {
  // Ensure compatibility
  const realSource = CompatSource.from(source);
  
  // Use full Source API
  const content = realSource.source();
  const buffer = realSource.buffer();
  const size = realSource.size();
  
  // Process...
}

// Bridge legacy and modern systems
const legacySource = legacySourceProvider("input.js");
modernProcessor(legacySource); // Works seamlessly

Install with Tessl CLI

npx tessl i tessl/npm-webpack-sources

docs

base-source.md

caching-performance.md

index.md

source-implementations.md

source-manipulation.md

utility-classes.md

tile.json