Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Browserify-specific fix for #29 #36

Merged
merged 9 commits into from
Nov 2, 2016
57 changes: 44 additions & 13 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ function optimizeJs (jsString, opts) {
return false
}

function isNumeric (str) {
return /^[0-9]+$/.test(str)
}

function isCallExpression (node) {
return node && node.type === 'CallExpression'
}
Expand All @@ -49,37 +53,62 @@ function optimizeJs (jsString, opts) {
return node && node.type === 'ArrayExpression'
}

function isElementOfArray (node) {
return isArrayExpression(node.parent()) &&
node.parent().elements.indexOf(node) !== -1
}

// returns true iff node is an argument to a function call expression.
function isArgumentToFunctionCall (node) {
return isCallExpression(node.parent()) &&
node.parent().arguments.length &&
node.parent().arguments.indexOf(node) !== -1
}

// returns true iff node is an element of an array literal which is in turn
// an argument to a function call expression.
function isElementOfArrayArgumentToFunctionCall (node) {
return isArrayExpression(node.parent()) &&
node.parent().elements.indexOf(node) !== -1 &&
isArgumentToFunctionCall(node.parent())
function isValueOfObjectLiteralWithNumericName (node) {
return node &&
node.parent() &&
node.parent().type === 'Property' &&
node.parent().key &&
node.parent().key.type === 'Literal' &&
node.parent().key.raw &&
isNumeric(node.parent().key.raw) &&
node.parent().value === node &&
node.parent().parent() &&
node.parent().parent().type === 'ObjectExpression'
}

// returns true iff node is an IIFE.
function isIIFE (node) {
return isCallExpression(node.parent()) &&
return node &&
node.type === 'FunctionExpression' &&
isCallExpression(node.parent()) &&
node.parent().callee === node
}

// returns true iff this is an IIFE call expression
function isIIFECall (node) {
return node &&
isCallExpression(node) &&
node.callee &&
node.callee.type === 'FunctionExpression'
}

// tries to divine if this function is a webpack module wrapper.
// returns true iff node is an element of an array literal which is in turn
// an argument to a function call expression, and that function call
// expression is an IIFE.
function isProbablyWebpackModule (node) {
return isElementOfArrayArgumentToFunctionCall(node) &&
node.parent() && // array literal
node.parent().parent() && // CallExpression
node.parent().parent().callee && // function that is being called
node.parent().parent().callee.type === 'FunctionExpression'
return isElementOfArray(node) &&
isArgumentToFunctionCall(node.parent()) &&
isIIFECall(node.parent().parent())
}

function isProbablyBrowserifyModule (node) {
return isElementOfArray(node) &&
isValueOfObjectLiteralWithNumericName(node.parent()) &&
isArgumentToFunctionCall(node.parent().parent().parent()) &&
isIIFECall(node.parent().parent().parent().parent())
}

if (node.type === 'FunctionExpression') {
Expand All @@ -88,7 +117,9 @@ function optimizeJs (jsString, opts) {
var postChar = jsString.charAt(node.end)
var postPostChar = jsString.charAt(node.end + 1)

if (isArgumentToFunctionCall(node) || isProbablyWebpackModule(node)) {
if (isArgumentToFunctionCall(node) ||
isProbablyWebpackModule(node) ||
isProbablyBrowserifyModule(node)) {
// function passed in to another function, either as an argument, or as an element
// of an array argument. these are almost _always_ executed, e.g. webpack bundles,
// UMD bundles, Browserify bundles, Node-style errbacks, Promise then()s and catch()s, etc.
Expand Down
9 changes: 9 additions & 0 deletions test/cases/browserify-object-literal-in-global-scope/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// a browserify-style object literal that isn't a parameter shouldn't be optimized.
var a = {
1:[
function(o,r,t){
console.log("browserify style!");
},
{}
]
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// a browserify-style object literal that isn't a parameter shouldn't be optimized.
var a = {
1:[
function(o,r,t){
console.log("browserify style!");
},
{}
]
};
24 changes: 24 additions & 0 deletions test/cases/browserify-style-multi-element/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
!function(o){
return o[0]();
}(
{
1:[
function(o,r,t){
console.log("browserify style!");
},
{}
],
2:[
function(o,r,t){
console.log("browserify style!");
},
{}
],
3:[
function(o,r,t){
console.log("browserify style!");
},
{}
]
}
);
24 changes: 24 additions & 0 deletions test/cases/browserify-style-multi-element/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
!(function(o){
return o[0]();
})(
{
1:[
(function(o,r,t){
console.log("browserify style!");
}),
{}
],
2:[
(function(o,r,t){
console.log("browserify style!");
}),
{}
],
3:[
(function(o,r,t){
console.log("browserify style!");
}),
{}
]
}
);
10 changes: 10 additions & 0 deletions test/cases/browserify-style-non-iife/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
foo(
{
1:[
function(o,r,t){
console.log("browserify style!");
},
{}
]
}
);
10 changes: 10 additions & 0 deletions test/cases/browserify-style-non-iife/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
foo(
{
1:[
function(o,r,t){
console.log("browserify style!");
},
{}
]
}
);
12 changes: 12 additions & 0 deletions test/cases/browserify-style-one-element/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
!function(o){
return o[0]();
}(
{
1:[
function(o,r,t){
console.log("browserify style!");
},
{}
]
}
);
12 changes: 12 additions & 0 deletions test/cases/browserify-style-one-element/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
!(function(o){
return o[0]();
})(
{
1:[
(function(o,r,t){
console.log("browserify style!");
}),
{}
]
}
);
14 changes: 14 additions & 0 deletions test/cases/browserify-style-with-non-numeric-propname/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// a browserify-style function call that has non-numeric object indices shouldn't
// be optimized.
!function(o){
return o[0]();
}(
{
a:[
function(o,r,t){
console.log("browserify style!");
},
{}
]
}
);
14 changes: 14 additions & 0 deletions test/cases/browserify-style-with-non-numeric-propname/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// a browserify-style function call that has non-numeric object indices shouldn't
// be optimized.
!(function(o){
return o[0]();
})(
{
a:[
function(o,r,t){
console.log("browserify style!");
},
{}
]
}
);