Exorcist is a Node.js package that externalizes source maps from JavaScript and CSS streams to separate .map files. It provides a simple transform stream that extracts inline source maps from bundled code and writes them to external files while updating the sourceMappingURL reference. Commonly used with build tools like Browserify to separate source maps from production bundles.
npm install exorcistconst exorcist = require('exorcist');const browserify = require('browserify');
const path = require('path');
const fs = require('fs');
const exorcist = require('exorcist');
const mapfile = path.join(__dirname, 'bundle.js.map');
// From a file, to a file, and send source map to its own file
browserify({debug: true})
.require(require.resolve('./main'), { entry: true })
.bundle()
.pipe(exorcist(mapfile))
.pipe(fs.createWriteStream(path.join(__dirname, 'bundle.js'), 'utf8'));
// Command line usage
// browserify main.js --debug | exorcist bundle.js.map > bundle.jsExorcist is built around several key components:
mold-source-map library to parse, modify, and generate source map JSONmkdirpCreates a transform stream that extracts source maps from the input stream and writes them to an external file or stream.
/**
* Externalizes the source map of the file streamed in.
*
* The source map is written as JSON to the specified file or stream, and the original
* file is streamed out with its sourceMappingURL set to the path of the file
* (or to the value of url).
*
* @param {string|Object} input - File path or writable stream where the source map will be written
* @param {string} [url] - Full URL to the map file, set as sourceMappingURL in the streaming output (default: file path)
* @param {string} [root] - Root URL for loading relative source paths, set as sourceRoot in the source map (default: '')
* @param {string} [base] - Base path for calculating relative source paths (default: use absolute paths)
* @param {boolean} [errorOnMissing] - When truthy, causes 'error' to be emitted instead of 'missing-map' if no map was found in the stream (default: false)
* @returns {TransformStream} Transform stream into which to pipe the code containing the source map
*/
function exorcist(input, url, root, base, errorOnMissing);Usage Examples:
const exorcist = require('exorcist');
const fs = require('fs');
// Basic usage with file output
someStream
.pipe(exorcist('/path/to/bundle.js.map'))
.pipe(fs.createWriteStream('bundle.js'));
// Usage with stream output and custom URL
const mapStream = fs.createWriteStream('maps/bundle.js.map');
someStream
.pipe(exorcist(mapStream, '/assets/maps/bundle.js.map'))
.pipe(fs.createWriteStream('bundle.js'));
// Usage with all options
someStream
.pipe(exorcist(
'dist/bundle.js.map', // output file
'/assets/bundle.js.map', // URL for sourceMappingURL
'/src', // sourceRoot
'./src', // base path for relative sources
true // error on missing map
))
.pipe(fs.createWriteStream('dist/bundle.js'));The transform stream emits additional events beyond standard stream events:
/**
* Events emitted by the exorcist transform stream
*/
interface ExorcistEvents {
/** Emitted if no map was found in the stream and errorOnMissing is false */
'missing-map': (message: string) => void;
/** Standard stream error event; also emitted when errorOnMissing is true and no map is found */
'error': (error: Error) => void;
}Event Usage:
const stream = exorcist('bundle.js.map');
stream.on('missing-map', (message) => {
console.warn('Source map not found:', message);
});
stream.on('error', (error) => {
console.error('Exorcist error:', error.message);
});Exorcist includes a command-line interface for processing streams from stdin.
# Command syntax
exorcist map_file [options]
# Options:
# --base, -b Base path for calculating relative source paths (default: use absolute paths)
# --root, -r Root URL for loading relative source paths, set as sourceRoot in the source map (default: '')
# --url, -u Full URL to source map, set as sourceMappingURL in the output stream (default: map_file)
# --error-on-missing, -e Abort with error if no map is found in the stream (default: warn but pipe through)
# --help, -h Show usage informationCLI Usage Examples:
# Basic usage
browserify main.js --debug | exorcist bundle.js.map > bundle.js
# With custom source root
browserify main.js --debug | exorcist bundle.js.map --root /assets > bundle.js
# With base path for relative sources
browserify main.js --debug | exorcist bundle.js.map --base ./src > bundle.js
# With custom URL and error handling
browserify main.js --debug | exorcist bundle.js.map --url /maps/bundle.js.map --error-on-missing > bundle.js/**
* Node.js transform stream interface
*/
interface TransformStream {
pipe(destination: WritableStream): WritableStream;
on(event: string, listener: Function): TransformStream;
emit(event: string, ...args: any[]): boolean;
}
/**
* Node.js writable stream interface
*/
interface WritableStream {
write(chunk: any, encoding?: string, callback?: Function): boolean;
end(chunk?: any, encoding?: string, callback?: Function): void;
}