Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

minifyify

Package Overview
Dependencies
Maintainers
1
Versions
98
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

minifyify - npm Package Compare versions

Comparing version 3.0.0-beta11 to 3.0.0-beta12

lib/minifier.js

406

lib/index.js

@@ -1,372 +0,92 @@

var Minifier
, _ = {
each: require('lodash.foreach')
, defaults: require('lodash.defaults')
, bind: require('lodash.bind')
}
var plugin
, fs = require('fs')
, tmp = require('tmp')
, concat = require('concat-stream')
, through = require('through')
, uglify = require('uglify-js')
, SM = require('source-map')
, convertSM = require('convert-source-map')
, SMConsumer = SM.SourceMapConsumer
, SMGenerator = SM.SourceMapGenerator;
, ReadableStream = require('stream').Readable;
Minifier = function (opts) {
/*
* Handle options/defaults
*/
opts = opts || {};
plugin = function (bundle, minifyifyOpts) {
minifyifyOpts = minifyifyOpts || {};
var defaults = {
minify: true
, source: 'bundle.js'
, map: 'bundle.map'
, compressPath: function (filePath) {
// noop
return filePath;
}
};
var minifyify = require('./minifier')
, minifier = new minifyify(minifyifyOpts)
, oldBundle = bundle.bundle
, bundleStarted = false;
this.opts = _.defaults(opts, defaults);
// Hook up the transform so we know what sources were used
bundle.transform({global: true}, minifier.transformer);
if(this.opts.map === false)
this.opts.minify = false;
// Proxy the bundle's bundle function so we can capture its output
bundle.bundle = function (bundleOpts, bundleCb) {
/*
* Instance variables
*/
this.registry = {}; // Keep source maps and code by file
var bundleStream
, minifiedStream = new ReadableStream();
/**
* Browserify runs transforms with a different context
* but we always want to refer to ourselves
*/
this.transformer = _.bind(this.transformer, this);
return this;
};
/*
* Registers maps and code by file
*/
Minifier.prototype.registerMap = function (file, code, map) {
this.registry[file] = {code:code, map:map};
};
/*
* Gets map by file
*/
Minifier.prototype.mapForFile = function (file) {
if(!this.fileExists(file)) {
throw new Error('ENOFILE');
}
return this.registry[file].map;
};
/*
* Gets code by file
*/
Minifier.prototype.codeForFile = function (file) {
if(!this.fileExists(file)) {
throw new Error('ENOFILE');
}
return this.registry[file].code;
};
Minifier.prototype.fileExists = function (file) {
return (this.registry[file] != null);
}
/*
* Compresses code before Browserify touches it
* Does nothing if minify is false
*/
Minifier.prototype.transformer = function (file) {
var self = this
, buffs = []
, write
, end
, throughStream;
write = function (data) {
if(self.opts.minify) {
buffs.push(data);
// Normalize options
if(typeof bundleOpts == 'function') {
bundleCb = bundleOpts;
bundleOpts = {};
}
else {
this.queue(data);
bundleOpts = bundleOpts || {};
}
}
end = function () {
var thisStream = this
, unminCode = buffs.join()
, originalCode = false
, existingMap = convertSM.fromSource(unminCode)
, finish;
// Force debug mode
bundleOpts.debug = true;
existingMap = existingMap ? existingMap.toObject() : false;
if(existingMap && existingMap.sourcesContent && existingMap.sourcesContent.length) {
originalCode = convertSM.removeComments(existingMap.sourcesContent[0]);
existingMap = JSON.stringify(existingMap);
/*
* If no callback was given, require that the user
* specified a path to write the sourcemap out to
*/
if(!bundleStarted && !bundleCb && !minifyifyOpts.output) {
throw new Error('Minifyify: opts.output is required since no callback was given');
}
// Only accept existing maps with sourcesContent
else {
existingMap = false;
}
finish = function (tempExistingMapFile) {
if(self.opts.minify) {
var min = uglify.minify(unminCode, {
fromString: true
, outSourceMap: self.opts.map
, inSourceMap: tempExistingMapFile
});
// Call browserify's bundle function and capture the output stream
bundleStream = oldBundle.call(bundle, bundleOpts);
thisStream.queue(min.code);
self.registerMap(file, originalCode || unminCode, new SMConsumer(min.map));
}
// Otherwise we'll never finish
thisStream.queue(null);
/*
* Browserify has this mechanism that delays bundling until all deps
* are ready, and that means bundle gets called twice. The extra time,
* it should just pass thru the data instead of trying to consume it.
*/
if(bundleStarted) {
return bundleStream;
}
if(existingMap) {
tmp.file(function (err, path) {
if(err) { throw err; }
fs.writeFile(path, existingMap, function (err) {
if(err) { throw err; }
finish(path);
});
});
if(!bundleStarted) {
bundleStarted = true;
}
else {
finish();
}
}
throughStream = through(write, end);
throughStream.call = function () {
throw new Error('Transformer is a transform. Correct usage: `bundle.transform(minifier.transformer)`.')
}
return throughStream;
};
/*
* Consumes the output stream from Browserify
*/
Minifier.prototype.consumer = function (cb) {
var self = this;
return concat(function(data) {
if(!self.opts.minify) {
return cb(null, data, null);
}
else {
var bundle;
try {
bundle = self.decoupleBundle(data);
/*
* Pipe browserify's output into the minifier's consumer
* which has the ability to transform the sourcemap
*/
bundleStream.pipe(minifier.consumer(function (err, src, map) {
// If there was a callback given, we are done
if(typeof bundleCb == 'function') {
return bundleCb(err, src, map);
}
catch(e) {
if(e.toString() == 'ENOURL') {
return cb(new Error('Browserify must be in debug mode for minifyify to consume sourcemaps'));
}
else {
return cb(e);
}
}
// Re-maps the browserify sourcemap
// to the original source using the
// uglify sourcemap
bundle.map = self.transformMap(bundle.map);
// Otherwise, throw if anything bad happened
if(err) { throw err; }
bundle.code = bundle.code + '\n//# sourceMappingURL=' + self.opts.map
// Write the sourcemap to the specified output location
var writeStream = fs.createWriteStream(minifyifyOpts.output);
writeStream.write(map);
writeStream.end();
cb(null, bundle.code, bundle.map);
}
});
};
/*
* Given a SourceMapConsumer from a bundle's map,
* transform it so that it maps to the unminified
* source
*/
Minifier.prototype.transformMap = function (bundleMap) {
var self = this
, generator = new SMGenerator({
file: self.opts.source
})
// Map File -> The lowest numbered line in the bundle (offset)
, bundleToMinMap = {}
/*
* Helper function that maps minified source to a line in the browserify bundle
*/
, mapSourceToLine = function (source, line) {
var target = bundleToMinMap[source];
if(!target || target > line) {
bundleToMinMap[source] = line;
}
// Push the minified src to our proxied stream
minifiedStream._read = function () {
minifiedStream.push(src);
minifiedStream.push(null);
}
minifiedStream.resume();
minifiedStream.emit('readable');
}));
, hasNoMappings = function (file) {
return bundleToMinMap[file] == null;
}
minifiedStream.pause();
/*
* Helper function that gets the line
*/
, lineForSource = function (source) {
if(hasNoMappings(source)) {
throw new Error('ENOFILE: ' + source);
}
var target = bundleToMinMap[source];
return target;
}
, missingSources = {};
// Figure out where my minified files went in the bundle
bundleMap.eachMapping(function (mapping) {
if(self.fileExists(mapping.source)) {
mapSourceToLine(mapping.source, mapping.generatedLine);
}
// Not a known source, pass thru the mapping
else {
generator.addMapping({
generated: {
line: mapping.generatedLine
, column: mapping.generatedColumn
}
, original: {
line: mapping.originalLine
, column: mapping.originalColumn
}
, source: self.opts.compressPath(mapping.source)
, name: mapping.name
});
missingSources[mapping.source] = true;
}
});
if(process.env.debug) {
console.log(' [DEBUG] Here is where Browserify put your modules:');
_.each(bundleToMinMap, function (line, file) {
console.log(' [DEBUG] line ' + line + ' "' + self.opts.compressPath(file) + '"');
});
}
// Add sourceContent for missing sources
_.each(missingSources, function (v, source) {
generator.setSourceContent(self.opts.compressPath(source), bundleMap.sourceContentFor(source));
});
// Map from the hi-res sourcemaps to the browserify bundle
if(process.env.debug) {
console.log(' [DEBUG] Here is how I\'m mapping your code:');
}
self.eachSource(function (file, code) {
// Ignore files with no mappings
if(!self.fileExists(file) || hasNoMappings(file)) {
if(process.env.debug) {
throw new Error('File with no mappings: ' + file)
}
return;
}
var offset = lineForSource(file) - 1
, fileMap = self.mapForFile(file)
, transformedFileName = self.opts.compressPath(file);
if(process.env.debug) {
console.log(' [DEBUG] Now mapping "' + transformedFileName + '"');
}
fileMap.eachMapping(function (mapping) {
var transformedMapping = self.transformMapping(transformedFileName, mapping, offset);
if(process.env.debug) {
console.log(' [DEBUG] Generated [' + transformedMapping.generated.line +
':' + transformedMapping.generated.column + '] > [' +
mapping.originalLine + ':' + mapping.originalColumn + '] Original');
}
generator.addMapping( transformedMapping );
});
generator.setSourceContent(transformedFileName, code);
});
return generator.toString();
};
/*
* Given a mapping (from SMConsumer.eachMapping)
* return a new mapping (for SMGenerator.addMapping)
* resolved to the original source
*/
Minifier.prototype.transformMapping = function (file, mapping, offset) {
return {
generated: {
line: mapping.generatedLine + offset
, column: mapping.generatedColumn
}
, original: {
line: mapping.originalLine
, column: mapping.originalColumn
}
, source: file
, name: mapping.name
}
};
/*
* Iterates over each code file, executes a function
*/
Minifier.prototype.eachSource = function (cb) {
var self = this;
_.each(this.registry, function(v, file) {
cb(file, self.codeForFile(file), self.mapForFile(file));
});
};
/*
* Given source with embedded sourcemap, seperate the two
* Returns the code and SourcemapConsumer object seperately
*/
Minifier.prototype.decoupleBundle = function (src) {
if(typeof src != 'string')
src = src.toString();
var map = convertSM.fromSource(src);
// The source didn't have a sourcemap in it
if(!map) {
throw new Error('ENOURL');
}
return {
code: convertSM.removeComments(src)
, map: new SMConsumer( map.toObject() )
// The bundle function should return our proxied stream
return minifiedStream;
};
};
module.exports = Minifier;
module.exports = plugin;

@@ -21,3 +21,3 @@ {

],
"version": "3.0.0-beta11",
"version": "3.0.0-beta12",
"repository": {

@@ -24,0 +24,0 @@ "type": "git",

@@ -11,61 +11,23 @@ Minifyify

Minifyify takes your browserify bundle and minfies it. The magic: your code still maps back to the original, separate source files.
Minifyify is a browserify plugin that minifies your code. The magic? The sourcemap points back to the original, separate source files.
Now you can deploy a minified bundle in production, and still have a sourcemap handy for when things inevitably break!
## Simple Usage
## Usage
```js
var browserify = require('browserify')
, minifyify = require('minifyify')
, bundler = new browserify();
, minifier = new minifyify();
bundler.add('entry.js');
bundler.transform({global: true}, minifier.transformer);
bundler
.bundle({debug: true})
.pipe(minifier.consumer(function (err, src, map) {
// Your code here
}));
bundler.plugin('minifyify', options);
bundler.bundle(function (err, src, map) {
// Your code here
});
```
## Full Usage
```js
var path = require('path')
, browserify = require('browserify')
, minifyify = require('minifyify')
, bundler
, minifier
, options = {
compressPath: function (p) {
return path.relative('my-app-root', p);
}
, map: '/bundle.map.json'
};
bundler = new browserify();
minifier = new minifyify(options);
bundler.add('entry.js')
// Your other transforms
bundler.transform(require('coffeeify'));
bundler.transform(require('hbsfy'));
// Minifies code while tracking sourcemaps
// {global: true} lets us also minify browser shims
bundler.transform({global: true}, minifier.transformer);
bundler
// Debug must be true for minifyify to work
.bundle({debug: true})
// Consume pulls the source map out of src and transforms the mappings
.pipe(minifier.consumer(function (err, src, map) {
// src and map are strings
// src has a comment pointing to map
}));
```sh
browserify entry.js -p [minifyify --output bundle.map.json] > bundle.json
```

@@ -72,0 +34,0 @@

@@ -8,3 +8,3 @@ var fixtures = require('./fixtures')

, validate = require('sourcemap-validator')
, Minifyify = require('../lib')
, Minifyify = require('../lib/minifier')

@@ -11,0 +11,0 @@ // Helpers

@@ -10,3 +10,3 @@ /**

, browserify = require('browserify')
, minifyify = require('../lib')
, minifyify = require('../lib/minifier')
, fixtures = require('./fixtures')

@@ -13,0 +13,0 @@ , tests = {};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc