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

When packaging, copy the code and inline __DEV__ #1572

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
},
"preferGlobal": true,
"commonerConfig": {
"version": 4
"version": 5
},
"scripts": {
"test": "./node_modules/.bin/grunt test"
Expand Down
146 changes: 127 additions & 19 deletions vendor/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,96 @@ var DEV_EXPRESSION = builders.binaryExpression(
function transform(ast, constants) {
constants = constants || {};

var devProgram = copyAst(ast.program);
var prodProgram = copyAst(ast.program);

devProgram = transformDev(hoistFunctions(devProgram), constants);
prodProgram = transformProd(hoistFunctions(prodProgram), constants);

return builders.program([
builders.ifStatement(
DEV_EXPRESSION,
builders.blockStatement(devProgram.body),
builders.blockStatement(prodProgram.body)
)
]);
}

function copyAst(node) {
if (node instanceof RegExp) {
return node;
} else if (node instanceof Array) {
return node.map(copyAst);
} else if (typeof node === "object" && node != null) {
var newNode = Object.create(Object.getPrototypeOf(node));
for (var key in node) {
if (!Object.prototype.hasOwnProperty.call(node, key)) {
continue;
}
if (namedTypes.Node.check(node)) {
newNode[key] = copyAst(node[key]);
} else {
newNode[key] = node[key];
}
}

Object.defineProperty(newNode, "original", {
value: node.original,
configurable: false,
enumerable: false,
writable: true
});

return newNode;
} else {
return node;
}
}

function isUseStrict(node) {
return node &&
namedTypes.ExpressionStatement.check(node) &&
namedTypes.Literal.check(node.expression) &&
node.expression.value === "use strict";
}

function hoistFunctions(program) {
var functionVariableDeclarations = [];

var body = program.body.slice();
for (var i = 0; i < body.length; i++) {
var node = body[i];
if (namedTypes.FunctionDeclaration.check(node)) {
functionVariableDeclarations.push(
builders.variableDeclaration("var", [
builders.variableDeclarator(
node.id,
builders.functionExpression(
null,
node.params,
node.body,
node.generator,
node.expression,
// Switch to node.async after upgrading esprima-fb
false
)
)
])
);
body.splice(i, 1);
i--;
}
}

// Insert functions after "use strict", if present
body.splice.apply(
body,
[isUseStrict(body[0]) ? 1 : 0, 0].concat(functionVariableDeclarations)
);
return builders.program(body);
}

function transformDev(ast, constants) {
return types.traverse(ast, function(node, traverse) {
if (namedTypes.Identifier.check(node)) {
// If the identifier is the property of a member expression
Expand All @@ -53,12 +143,40 @@ function transform(ast, constants) {
return false;
}

if (node.name === '__DEV__') {
// Replace __DEV__ with 'true'
this.replace(builders.literal(true));
return false;

// There could in principle be a constant called "hasOwnProperty",
// so be careful always to use Object.prototype.hasOwnProperty.
} else if (hasOwn.call(constants, node.name)) {
this.replace(builders.literal(constants[node.name]));
return false;
}
}
});
}

function transformProd(ast, constants) {
return types.traverse(ast, function(node, traverse) {
if (namedTypes.Identifier.check(node)) {
// If the identifier is the property of a member expression
// (e.g. object.property), then it definitely is not a constant
// expression that we want to replace.
if (namedTypes.MemberExpression.check(this.parent.node) &&
this.name === 'property' &&
!this.parent.node.computed) {
return false;
}

if (node.name === '__DEV__') {
// replace __DEV__ with process.env.NODE_ENV !== 'production'
this.replace(DEV_EXPRESSION);
// Replace __DEV__ with 'false'
this.replace(builders.literal(false));
return false;

// There could in principle be a constant called "hasOwnProperty",
// so be careful always to use Object.prototype.hasOwnProperty.
} else if (hasOwn.call(constants, node.name)) {
this.replace(builders.literal(constants[node.name]));
return false;
Expand All @@ -67,30 +185,20 @@ function transform(ast, constants) {
} else if (namedTypes.CallExpression.check(node)) {
if (namedTypes.Identifier.check(node.callee) &&
node.callee.name === 'invariant') {
// Truncate the arguments of invariant(condition, ...)
// statements to just the condition based on NODE_ENV
// (dead code removal will remove the extra bytes).
// Truncate the arguments of invariant(condition, ...) statements to
// just the condition
this.replace(
builders.conditionalExpression(
DEV_EXPRESSION,
node,
builders.callExpression(
node.callee,
[node.arguments[0]]
)
builders.callExpression(
node.callee,
[node.arguments[0]]
)
);
return false;
} else if (namedTypes.Identifier.check(node.callee) &&
node.callee.name === 'warning') {
// Eliminate warning(condition, ...) statements based on NODE_ENV
// (dead code removal will remove the extra bytes).
// Eliminate warning(condition, ...) statements
this.replace(
builders.conditionalExpression(
DEV_EXPRESSION,
node,
builders.literal(null)
)
builders.literal(null)
);
}
}
Expand Down