node package manager
Share your code. npm Orgs help your team discover, share, and reuse code. Create a free org »

@elsassph/fast-source-map

Fast Source Map Build Status

Keeping the JIT gods happy since circa 2015

When working with sourcemaps, VLQ encoding and decoding typically dominiates cost. To address this, this library provides a Fast VLQ encoder & decoder for JavaScript. By reducing allocations, minimizing transformations, and writing JIT friendly code we are able to drammatically improve performance.

How much faster? At the time this README was written, decoding scala.js.map took:

v8: 4.6.85.28
node: 5.0.0
os: 10.10.3
hw: 2.5 GHz Intel Core i7, 16gb
  • source-map: ~5,000ms
  • fast-source-map ~ 500ms

Usage

First we will need to have our sourceMap.mappings stored as a buffer. We have future plans to work directly on a sourceMap buffer, as that will allow for more ideal performance. Even without, the performance improvements are still well worth it.

var buffer = /* try to leave the map inert, and in buffer form. Otherwise convert to buffer */

Typically, the following steps are required:

Setup the reader

The reader can read mappings from any array of ascii values. We will use Uint8Array in this example.

let map = JSON.parse(fs.readFileSync('path/to/source/to/decode.js.map', 'utf8'));
 
let byteArray = new Uint8Array(map.mappings.length);
let buffer = Buffer.from(byteArray.buffer);
buffer.write(map.mappings, 0, 'ascii');
 
const SM = require("fast-source-map");
let reader = new SM.IntBufferReader(byteArray, 0, byteArray.length);

Setup the decoder

let decoder = new SM.Decoder();
let mappingsDecoder = new SM.MappingsDecoder(decoder);

Now for some actual decoding

mappingsDecoder.decode(reader);
decoder.mappings // => is the quickly decoded

To concatenate multiple source maps

const decodeFile = SM.decodeFile;
 
let concatenator = new SM.SourceMapConcatenator();
concatenator.push(decodeFile('path/to/file-1.js.map'));
concatenator.push(decodeFile('path/to/file-2.js.map'));
concatenator.push(decodeFile('path/to/file-3.js.map'));
 
concatenator.toJSON(); // => the concatenated source maps

Now to reconcatenate the source maps after a source file is removed.

// file-2.js.map is removed
concatenator.splice(1, 1);
concatenator.toJSON(); // => the concatenated source maps

And reconcatenate again after adding back other files.

// an updated file 2 and a new file 4 are added
concatenator.splice(1, 0, decodeFile('path/to/file-2-updated.js.map'));
concatenator.push(decodeFile('path/to/file-4.js.map'));
concatenator.toJSON(); // => the concatenated source maps