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

[TIMOB-12127] Upgraded Uglify from v1 to v2. Added uglify error handling... #3741

Merged
merged 2 commits into from
Jan 22, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
110 changes: 59 additions & 51 deletions iphone/cli/commands/_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ var ti = require('titanium-sdk'),
Buffer = require('buffer').Buffer,
wrench = require('wrench'),
cleanCSS = require('clean-css'),
uglify = require('uglify-js'),
uglifyProcessor = uglify.uglify,
uglifyParser = uglify.parser,
UglifyJS = require('uglify-js'),
DOMParser = require('xmldom').DOMParser,
uuid = require('node-uuid'),
appc = require('node-appc'),
Expand Down Expand Up @@ -63,6 +61,9 @@ var ti = require('titanium-sdk'),
'dist-adhoc': 'production'
};

// silence uglify's default warn mechanism
UglifyJS.AST_Node.warn_function = function () {};

exports.config = function (logger, config, cli) {
return function (callback) {
ios.detect(function (env) {
Expand Down Expand Up @@ -2246,15 +2247,7 @@ build.prototype = {
this.logger.debug(__('Writing minifying JavaScript file: %s', c.to.cyan));
fs.writeFileSync(
c.to,
uglifyProcessor.gen_code(
uglifyProcessor.ast_squeeze(
uglifyProcessor.ast_mangle(
uglifyParser.parse(
fs.readFileSync(c.from).toString().replace(/Titanium\./g,'Ti.')
)
)
)
)
UglifyJS.minify(c.from).code.replace(/Titanium\./g,'Ti.')
);
}, this);
}
Expand All @@ -2280,22 +2273,27 @@ build.prototype = {
},

findSymbols: function (ast) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this just finding variable/function identifiers? If so, you can accomplish it a lot easier using figure_out_scope. http://lisperator.net/uglifyjs/scope

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'll try playing around with the scope stuff tomorrow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

function scan(node) {
if (node[0] == 'name') {
return node[1] == 'Ti' ? node[1] : '';
} else if (node[0] == 'dot') {
var s = scan(node[1]);
return s && node.length > 2 ? s + '.' + node[2] : '';
}
}
var walker = new UglifyJS.TreeWalker(function (node, descend) {
if (node instanceof UglifyJS.AST_SymbolRef && node.name == 'Ti') {
var p = walker.stack,
buffer = [],
i = p.length - 1; // we already know the top of the stack is Ti

// loop until 2nd from bottom of stack since the bottom is the toplevel node which we don't care about
while (--i) {
if (p[i] instanceof UglifyJS.AST_Dot) {
buffer.push(p[i].property);
} else if (p[i] instanceof UglifyJS.AST_Symbol || p[i] instanceof UglifyJS.AST_SymbolRef) {
buffer.push(p[i].name);
} else {
break;
}
}
buffer.length && this.addSymbol(buffer.join('.'));
}
}.bind(this));

appc.astwalker(ast, {
dot: function (node, next) {
var s = scan(node);
s && this.addSymbol(s.substring(3));
next();
}.bind(this)
});
ast.walk(walker);
},

addSymbol: function (symbol) {
Expand All @@ -2316,37 +2314,27 @@ build.prototype = {
},

compileJsFile: function (id, file) {
var contents = fs.readFileSync(file).toString().replace(/Titanium\./g,'Ti.');
var original = fs.readFileSync(file).toString(),
contents = original.replace(/Titanium\./g,'Ti.'),
ast;

try {
var ast = uglifyParser.parse(contents);

if (!this.cli.argv['skip-js-minify'] && this.deployType != 'development') {
contents = uglifyProcessor.gen_code(
uglifyProcessor.ast_squeeze(
uglifyProcessor.ast_mangle(ast)
)
);
}

this.logger.info(__('Finding Titanium symbols in file %s', file.cyan));
this.findSymbols(ast);

id = path.join(this.assetsDir, id);
wrench.mkdirSyncRecursive(path.dirname(id));

this.logger.debug(__('Writing JavaScript file: %s', id.cyan));
fs.writeFileSync(id, contents);
ast = UglifyJS.parse(contents, { filename: file })
} catch (ex) {
this.logger.error(__('Failed to minify %s', file));
this.logger.error(__('%s [line %s, column %s]', ex.message, ex.line, ex.col));
if (ex.line) {
this.logger.error(__('%s [line %s, column %s]', ex.message, ex.line, ex.col));
} else {
this.logger.error(__('%s', ex.message));
}
try {
contents = contents.split('\n');
if (ex.line && ex.line <= contents.length) {
original = original.split('\n');
if (ex.line && ex.line <= original.length) {
this.logger.error('');
this.logger.error(' ' + contents[ex.line-1]);
this.logger.error(' ' + original[ex.line-1]);
if (ex.col) {
var i = 0,
len = ex.col - 1;
len = ex.col;
buffer = ' ';
for (; i < len; i++) {
buffer += '-';
Expand All @@ -2358,6 +2346,26 @@ build.prototype = {
} catch (ex2) {}
process.exit(1);
}

this.logger.info(__('Finding Titanium symbols in file %s', file.cyan));
this.findSymbols(ast);

if (!this.cli.argv['skip-js-minify'] && this.deployType != 'development') {
ast.figure_out_scope();
ast = ast.transform(UglifyJS.Compressor());
ast.figure_out_scope();
ast.compute_char_frequency();
ast.mangle_names();
var stream = UglifyJS.OutputStream();
ast.print(stream);
contents = stream.toString();
}

id = path.join(this.assetsDir, id);
wrench.mkdirSyncRecursive(path.dirname(id));

this.logger.debug(__('Writing JavaScript file: %s', id.cyan));
fs.writeFileSync(id, contents);
},

xcodePrecompilePhase: function (finished) {
Expand Down
72 changes: 63 additions & 9 deletions mobileweb/cli/commands/_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var ti = require('titanium-sdk'),
afs = appc.fs,
xml = appc.xml,
parallel = appc.async.parallel,
uglify = require('uglify-js'),
UglifyJS = require('uglify-js'),
fs = require('fs'),
path = require('path'),
wrench = require('wrench'),
Expand All @@ -39,6 +39,9 @@ var ti = require('titanium-sdk'),
'.jpeg': 'image/jpg'
};

// silence uglify's default warn mechanism
UglifyJS.AST_Node.warn_function = function () {};

exports.config = function (logger, config, cli) {
return {
options: {
Expand Down Expand Up @@ -524,12 +527,37 @@ build.prototype = {

if (/^url\:/.test(moduleName)) {
if (this.minifyJS) {
var pro = uglify.uglify,
source = file + '.uncompressed.js';

var source = file + '.uncompressed.js';
fs.renameSync(file, source);
this.logger.debug(__('Minifying include %s', file));
fs.writeFileSync(file, pro.gen_code(pro.ast_squeeze(pro.ast_mangle(uglify.parser.parse(fs.readFileSync(source).toString())))));
try {
fs.writeFileSync(file, UglifyJS.minify(source).code);
} catch (ex) {
this.logger.error(__('Failed to minify %s', source));
if (ex.line) {
this.logger.error(__('%s [line %s, column %s]', ex.message, ex.line, ex.col));
} else {
this.logger.error(__('%s', ex.message));
}
try {
var contents = fs.readFileSync(source).toString().split('\n');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can move this read inside the if statement, that way we don't have to read the file if we don't have a line. Also, what about windows newlines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't fix. Contents is needed to check if the line # is valid.

if (ex.line && ex.line <= contents.length) {
this.logger.error('');
this.logger.error(' ' + contents[ex.line-1]);
if (ex.col) {
var i = 0,
len = ex.col;
buffer = ' ';
for (; i < len; i++) {
buffer += '-';
}
this.logger.error(buffer + '^');
}
this.logger.log();
}
} catch (ex2) {}
process.exit(1);
}
}
tiJS.push('"' + moduleName + '":"' + fs.readFileSync(file).toString().trim().replace(/\\/g, '\\\\').replace(/\n/g, '\\n\\\n').replace(/"/g, '\\"') + '"');
} else if (isCommonJS) {
Expand Down Expand Up @@ -589,8 +617,7 @@ build.prototype = {
minifyJavaScript: function () {
if (this.minifyJS) {
this.logger.info(__('Minifying JavaScript'));
var pro = uglify.uglify,
self = this;
var self = this;
(function walk(dir) {
fs.readdirSync(dir).sort().forEach(function (dest) {
var stat = fs.statSync(dir + '/' + dest);
Expand All @@ -601,10 +628,37 @@ build.prototype = {
var source = dest + '.uncompressed.js';
fs.renameSync(dest, source);
self.logger.debug(__('Minifying include %s', dest));
fs.writeFileSync(dest, pro.gen_code(pro.ast_squeeze(pro.ast_mangle(uglify.parser.parse(fs.readFileSync(source).toString())))));
try {
fs.writeFileSync(dest, UglifyJS.minify(source).code);
} catch (ex) {
self.logger.error(__('Failed to minify %s', dest));
if (ex.line) {
self.logger.error(__('%s [line %s, column %s]', ex.message, ex.line, ex.col));
} else {
self.logger.error(__('%s', ex.message));
}
try {
var contents = fs.readFileSync(source).toString().split('\n');
if (ex.line && ex.line <= contents.length) {
self.logger.error('');
self.logger.error(' ' + contents[ex.line-1]);
if (ex.col) {
var i = 0,
len = ex.col;
buffer = ' ';
for (; i < len; i++) {
buffer += '-';
}
self.logger.error(buffer + '^');
}
self.logger.log();
}
} catch (ex2) {}
process.exit(1);
}
}
});
}(this.buildDir))
}(this.buildDir));
}
},

Expand Down
2 changes: 1 addition & 1 deletion support/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"titanium-code-processor": ">=0.1.0",
"node-uuid": "1.3.x",
"titanium-sdk": ">=0.1.0",
"uglify-js": "1.3.x",
"uglify-js": "2.2.x",
"wrench": "1.3.x",
"xmldom": "0.1.11"
},
Expand Down