From 05cf5bc8dbd4233f0ab813570972616b3c0a0f65 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 27 Dec 2012 09:53:14 -0600 Subject: [PATCH] Defer downloading required minifies until the `lodash` command-line executable is used for the first time. Former-commit-id: 83df0ac5875e8647168fffb7043a4cc197d27d79 --- build/minify.js | 155 ++++++++++++++++++++++++++++++++++++++---- build/post-install.js | 135 ------------------------------------ package.json | 3 +- 3 files changed, 141 insertions(+), 152 deletions(-) delete mode 100644 build/post-install.js diff --git a/build/minify.js b/build/minify.js index 794a5a805..904301d08 100755 --- a/build/minify.js +++ b/build/minify.js @@ -2,26 +2,56 @@ ;(function() { 'use strict'; - /** The Node filesystem, path, `zlib`, and child process modules */ + /** Load Node modules */ var fs = require('fs'), - gzip = require('zlib').gzip, + https = require('https'), path = require('path'), - spawn = require('child_process').spawn; + spawn = require('child_process').spawn, + tar = require('../vendor/tar/tar.js'), + zlib = require('zlib'); + + /** Load other modules */ + var preprocess = require('./pre-compile.js'), + postprocess = require('./post-compile.js'); + + /** The Git object ID of `closure-compiler.tar.gz` */ + var closureId = 'a2787b470c577cee2404d186c562dd9835f779f5'; + + /** The Git object ID of `uglifyjs.tar.gz` */ + var uglifyId = '505f1be36ef60fd25a992a522f116d5179ab317f'; /** The path of the directory that is the base of the repository */ var basePath = fs.realpathSync(path.join(__dirname, '..')); - /** The path of the directory where the Closure Compiler is located */ - var closurePath = path.join(basePath, 'vendor', 'closure-compiler', 'compiler.jar'); + /** The path of the `vendor` directory */ + var vendorPath = path.join(basePath, 'vendor'); - /** Load other modules */ - var preprocess = require('./pre-compile.js'), - postprocess = require('./post-compile.js'), - uglifyJS = require('../vendor/uglifyjs/tools/node.js'); + /** The path to the Closure Compiler `.jar` */ + var closurePath = path.join(vendorPath, 'closure-compiler', 'compiler.jar'); + + /** The path to the UglifyJS module */ + var uglifyPath = path.join(vendorPath, 'uglifyjs', 'tools', 'node.js'); /** The Closure Compiler command-line options */ var closureOptions = ['--warning_level=QUIET']; + /** The media type for raw blob data */ + var mediaType = 'application/vnd.github.v3.raw'; + + /** Used to reference parts of the blob href */ + var location = (function() { + var host = 'api.github.com', + origin = 'https://api.github.com', + pathname = '/repos/bestiejs/lodash/git/blobs'; + + return { + 'host': host, + 'href': origin + pathname, + 'origin': origin, + 'pathname': pathname + }; + }()); + /** The Closure Compiler optimization modes */ var optimizationModes = { 'simple': 'SIMPLE_OPTIMIZATIONS', @@ -79,7 +109,30 @@ source = fs.readFileSync(filePath, 'utf8'); } - new Minify(source, options); + // fetch the Closure Compiler + getDependency({ + 'id': 'closure-compiler', + 'hashId': closureId, + 'path': vendorPath, + 'title': 'the Closure Compiler', + 'onComplete': function(exception) { + var error = exception; + + // fetch UglifyJS + getDependency({ + 'id': 'uglifyjs', + 'hashId': uglifyId, + 'title': 'UglifyJS', + 'path': vendorPath, + 'onComplete': function(exception) { + error || (error = exception); + if (!error) { + new Minify(source, options); + } + } + }); + } + }); } /** @@ -121,6 +174,76 @@ /*--------------------------------------------------------------------------*/ + /** + * Fetches a required `.tar.gz` dependency with the given Git object ID from + * the Lo-Dash repo on GitHub. The object ID may be obtained by running + * `git hash-object path/to/dependency.tar.gz`. + * + * @private + * @param {Object} options The options object. + * id - The Git object ID of the `.tar.gz` file. + * onComplete - The function, invoked with one argument (exception), + * called once the extraction has finished. + * path - The path of the extraction directory. + * title - The dependency's title used in status updates logged to the console. + */ + function getDependency(options) { + options || (options = {}); + + var ran, + destPath = options.path, + hashId = options.hashId, + id = options.id, + onComplete = options.onComplete, + title = options.title; + + // exit early if dependency exists + if (fs.existsSync(path.join(destPath, id))) { + onComplete(); + return; + } + var callback = function(exception) { + if (ran) { + return; + } + if (exception) { + console.error([ + 'There was a problem installing ' + title + '.', + 'Try running the command as root, via `sudo`, or manually install by running:', + '', + "curl -H 'Accept: " + mediaType + "' " + location.href + '/' + hashId + " | tar xvz -C '" + destPath + "'", + '' + ].join('\n')); + } + ran = true; + process.removeListener('uncaughtException', callback); + onComplete(exception); + }; + + console.log('Downloading ' + title + '...'); + process.on('uncaughtException', callback); + + https.get({ + 'host': location.host, + 'path': location.pathname + '/' + hashId, + 'headers': { + // By default, all GitHub blob API endpoints return a JSON document + // containing Base64-encoded blob data. Overriding the `Accept` header + // with the GitHub raw media type returns the blob data directly. + // See http://developer.github.com/v3/media/. + 'Accept': mediaType + } + }, function(response) { + var decompressor = zlib.createUnzip(), + parser = new tar.Extract({ 'path': destPath }); + + parser.on('end', callback); + response.pipe(decompressor).pipe(parser); + }); + } + + /*--------------------------------------------------------------------------*/ + /** * Compresses a `source` string using the Closure Compiler. Yields the * minified result, and any exceptions encountered, to a `callback` function. @@ -181,6 +304,8 @@ console.log('Compressing ' + path.basename(this.outputPath, '.js') + ' using ' + label + '...'); } try { + var uglifyJS = require(uglifyPath); + // 1. parse var toplevel = uglifyJS.parse(source); @@ -232,7 +357,7 @@ } result = postprocess(result); this.compiled.simple.source = result; - gzip(result, onClosureSimpleGzip.bind(this)); + zlib.gzip(result, onClosureSimpleGzip.bind(this)); } /** @@ -268,7 +393,7 @@ } result = postprocess(result); this.compiled.advanced.source = result; - gzip(result, onClosureAdvancedGzip.bind(this)); + zlib.gzip(result, onClosureAdvancedGzip.bind(this)); } /** @@ -304,7 +429,7 @@ } result = postprocess(result); this.uglified.source = result; - gzip(result, onUglifyGzip.bind(this)); + zlib.gzip(result, onUglifyGzip.bind(this)); } /** @@ -340,7 +465,7 @@ } result = postprocess(result); this.hybrid.simple.source = result; - gzip(result, onSimpleHybridGzip.bind(this)); + zlib.gzip(result, onSimpleHybridGzip.bind(this)); } /** @@ -376,7 +501,7 @@ } result = postprocess(result); this.hybrid.advanced.source = result; - gzip(result, onAdvancedHybridGzip.bind(this)); + zlib.gzip(result, onAdvancedHybridGzip.bind(this)); } /** diff --git a/build/post-install.js b/build/post-install.js deleted file mode 100644 index b83dd1fb9..000000000 --- a/build/post-install.js +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env node -;(function() { - 'use strict'; - - /** Load Node modules */ - var fs = require('fs'), - path = require('path'); - - /** The path of the directory that is the base of the repository */ - var basePath = fs.realpathSync(path.join(__dirname, '..')); - - /** The path of the `vendor` directory */ - var vendorPath = path.join(basePath, 'vendor'); - - /** The Git object ID of `closure-compiler.tar.gz` */ - var closureId = 'a2787b470c577cee2404d186c562dd9835f779f5'; - - /** The Git object ID of `uglifyjs.tar.gz` */ - var uglifyId = '505f1be36ef60fd25a992a522f116d5179ab317f'; - - /** The media type for raw blob data */ - var mediaType = 'application/vnd.github.v3.raw'; - - /** Used to reference parts of the blob href */ - var location = (function() { - var host = 'api.github.com', - origin = 'https://api.github.com', - pathname = '/repos/bestiejs/lodash/git/blobs'; - - return { - 'host': host, - 'href': origin + pathname, - 'origin': origin, - 'pathname': pathname - }; - }()); - - /*--------------------------------------------------------------------------*/ - - /** - * Fetches a required `.tar.gz` dependency with the given Git object ID from - * the Lo-Dash repo on GitHub. The object ID may be obtained by running - * `git hash-object path/to/dependency.tar.gz`. - * - * @private - * @param {Object} options The options object. - * id - The Git object ID of the `.tar.gz` file. - * onComplete - The function, invoked with one argument (exception), - * called once the extraction has finished. - * path - The path of the extraction directory. - * title - The dependency's title used in status updates logged to the console. - */ - function getDependency(options) { - options || (options = {}); - - var id = options.id, - onComplete = options.onComplete, - path = options.path, - title = options.title; - - function callback(exception) { - if (exception) { - console.error([ - 'There was a problem installing ' + title + '. To manually install, run:', - '', - "curl -H 'Accept: " + mediaType + "' " + location.href + '/' + id + " | tar xvz -C '" + path + "'" - ].join('\n')); - } - onComplete(exception); - } - - console.log('Downloading ' + title + '...'); - - https.get({ - 'host': location.host, - 'path': location.pathname + '/' + id, - 'headers': { - // By default, all GitHub blob API endpoints return a JSON document - // containing Base64-encoded blob data. Overriding the `Accept` header - // with the GitHub raw media type returns the blob data directly. - // See http://developer.github.com/v3/media/. - 'Accept': mediaType - } - }, function(response) { - var decompressor = zlib.createUnzip(), - parser = new tar.Extract({ 'path': path }); - - decompressor.on('error', callback); - parser.on('end', callback).on('error', callback); - response.pipe(decompressor).pipe(parser); - }) - .on('error', callback); - } - - /*--------------------------------------------------------------------------*/ - - if (process.env.npm_config_global === 'true') { - // catch module load errors - try { - var https = require('https'), - tar = require('../vendor/tar/tar.js'), - zlib = require('zlib'); - - // download the Closure Compiler - getDependency({ - 'title': 'the Closure Compiler', - 'id': closureId, - 'path': vendorPath, - 'onComplete': function() { - // download UglifyJS - getDependency({ - 'title': 'UglifyJS', - 'id': uglifyId, - 'path': vendorPath, - 'onComplete': function() { - process.exit(); - } - }); - } - }); - } catch(e) { - console.log([ - 'Oops! There was a problem installing dependencies required by the Lo-Dash', - 'command-line executable. To manually install UglifyJS and the Closure Compiler', - 'run:', - '', - "curl -H 'Accept: " + mediaType + "' " + location.href + '/' + closureId + " | tar xvz -C '" + vendorPath + "'", - "curl -H 'Accept: " + mediaType + "' " + location.href + '/' + uglifyId + " | tar xvz -C '" + vendorPath + "'", - '' - ].join('\n')); - - console.log(e); - } - } -}()); diff --git a/package.json b/package.json index ef471b85c..f0e2776d9 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ }, "scripts": { "build": "node ./build.js", - "test": "node ./test/test.js && node ./test/test-build.js", - "install": "node ./build/post-install.js" + "test": "node ./test/test.js && node ./test/test-build.js" } }