diff --git a/gulpfile.js b/gulpfile.js
index 3bc39b871..53548d648 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -22,11 +22,30 @@ var gulp = require('gulp');
 var gutil = require('gulp-util');
 var rimraf = require('rimraf');
 var stream = require('stream');
+var exec = require('child_process').exec;
+var streamqueue = require('streamqueue');
 
 var BUILD_DIR = 'build/';
 var L10N_DIR = 'l10n/';
 
-require('./make.js');
+var makeFile = require('./make.js');
+var stripCommentHeaders = makeFile.stripCommentHeaders;
+var builder = makeFile.builder;
+
+var CONFIG_FILE = 'pdfjs.config';
+var config = JSON.parse(fs.readFileSync(CONFIG_FILE).toString());
+
+var DEFINES = {
+  PRODUCTION: true,
+  // The main build targets:
+  GENERIC: false,
+  FIREFOX: false,
+  MOZCENTRAL: false,
+  CHROME: false,
+  MINIFIED: false,
+  SINGLE_FILE: false,
+  COMPONENTS: false
+};
 
 function createStringSource(filename, content) {
   var source = stream.Readable({ objectMode: true });
@@ -42,6 +61,193 @@ function createStringSource(filename, content) {
   return source;
 }
 
+function stripUMDHeaders(content) {
+  var reg = new RegExp(
+    'if \\(typeof define === \'function\' && define.amd\\) \\{[^}]*' +
+    '\\} else if \\(typeof exports !== \'undefined\'\\) \\{[^}]*' +
+    '\\} else ', 'g');
+  return content.replace(reg, '');
+}
+
+function bundle(filename, outfilename, pathPrefix, initFiles, amdName, defines,
+                isMainFile, versionInfo) {
+  // Reading UMD headers and building loading orders of modules. The
+  // readDependencies returns AMD module names: removing 'pdfjs' prefix and
+  // adding '.js' extensions to the name.
+  var umd = require('./external/umdutils/verifier.js');
+  initFiles = initFiles.map(function (p) { return pathPrefix + p; });
+  var files = umd.readDependencies(initFiles).loadOrder.map(function (name) {
+    return pathPrefix + name.replace(/^[\w\-]+\//, '') + '.js';
+  });
+
+  var crlfchecker = require('./external/crlfchecker/crlfchecker.js');
+  crlfchecker.checkIfCrlfIsPresent(files);
+
+  var bundleContent = files.map(function (file) {
+    var content = fs.readFileSync(file);
+
+    // Prepend a newline because stripCommentHeaders only strips comments that
+    // follow a line feed. The file where bundleContent is inserted already
+    // contains a license header, so the header of bundleContent can be removed.
+    content = stripCommentHeaders('\n' + content);
+
+    // Removes AMD and CommonJS branches from UMD headers.
+    content = stripUMDHeaders(content);
+
+    return content;
+  }).join('');
+
+  var jsName = amdName.replace(/[\-_\.\/]\w/g, function (all) {
+    return all[1].toUpperCase();
+  });
+
+  // Avoiding double processing of the bundle file.
+  var templateContent = fs.readFileSync(filename).toString();
+  var tmpFile = outfilename + '.tmp';
+  fs.writeFileSync(tmpFile, templateContent.replace(
+    /\/\/#expand\s+__BUNDLE__\s*\n/, function (all) { return bundleContent; }));
+  bundleContent = null;
+  templateContent = null;
+
+  // This just preprocesses the empty pdf.js file, we don't actually want to
+  // preprocess everything yet since other build targets use this file.
+  builder.preprocess(tmpFile, outfilename,
+    builder.merge(defines, {
+      BUNDLE_VERSION: versionInfo.version,
+      BUNDLE_BUILD: versionInfo.commit,
+      BUNDLE_AMD_NAME: amdName,
+      BUNDLE_JS_NAME: jsName,
+      MAIN_FILE: isMainFile
+    }));
+  fs.unlinkSync(tmpFile);
+}
+
+function createBundle(defines) {
+  defines = defines || DEFINES;
+
+  var versionJSON = JSON.parse(
+    fs.readFileSync(BUILD_DIR + 'version.json').toString());
+
+  console.log();
+  console.log('### Bundling files into pdf.js');
+
+  var mainFiles = [
+    'display/global.js'
+  ];
+
+  var workerFiles = [
+    'core/worker.js'
+  ];
+
+  var mainAMDName = 'pdfjs-dist/build/pdf';
+  var workerAMDName = 'pdfjs-dist/build/pdf.worker';
+  var mainOutputName = 'pdf.js';
+  var workerOutputName = 'pdf.worker.js';
+
+  // Extension does not need network.js file.
+  if (!defines.FIREFOX && !defines.MOZCENTRAL) {
+    workerFiles.push('core/network.js');
+  }
+
+  if (defines.SINGLE_FILE) {
+    // In singlefile mode, all of the src files will be bundled into
+    // the main pdf.js output.
+    mainFiles = mainFiles.concat(workerFiles);
+    workerFiles = null; // no need for worker file
+    mainAMDName = 'pdfjs-dist/build/pdf.combined';
+    workerAMDName = null;
+    mainOutputName = 'pdf.combined.js';
+    workerOutputName = null;
+  }
+
+  var state = 'mainfile';
+  var source = stream.Readable({ objectMode: true });
+  source._read = function () {
+    var tmpFile;
+    switch (state) {
+      case 'mainfile':
+        // 'buildnumber' shall create BUILD_DIR for us
+        tmpFile = BUILD_DIR + '~' + mainOutputName + '.tmp';
+        bundle('src/pdf.js', tmpFile, 'src/', mainFiles,  mainAMDName,
+          defines, true, versionJSON);
+        this.push(new gutil.File({
+          cwd: '',
+          base: '',
+          path: mainOutputName,
+          contents: fs.readFileSync(tmpFile)
+        }));
+        fs.unlinkSync(tmpFile);
+        state = workerFiles ? 'workerfile' : 'stop';
+        break;
+      case 'workerfile':
+        // 'buildnumber' shall create BUILD_DIR for us
+        tmpFile = BUILD_DIR + '~' + workerOutputName + '.tmp';
+        bundle('src/pdf.js', tmpFile, 'src/', workerFiles, workerAMDName,
+          defines, false, versionJSON);
+        this.push(new gutil.File({
+          cwd: '',
+          base: '',
+          path: workerOutputName,
+          contents: fs.readFileSync(tmpFile)
+        }));
+        fs.unlinkSync(tmpFile);
+        state = 'stop';
+        break;
+      case 'stop':
+        this.push(null);
+        break;
+    }
+  };
+  return source;
+}
+
+function createWebBundle(defines) {
+  var versionJSON = JSON.parse(
+    fs.readFileSync(BUILD_DIR + 'version.json').toString());
+
+  var template, files, outputName, amdName;
+  if (defines.COMPONENTS) {
+    amdName = 'pdfjs-dist/web/pdf_viewer';
+    template = 'web/pdf_viewer.component.js';
+    files = [
+      'pdf_viewer.js',
+      'pdf_history.js',
+      'pdf_find_controller.js',
+      'download_manager.js'
+    ];
+    outputName = 'pdf_viewer.js';
+  } else {
+    amdName = 'pdfjs-dist/web/viewer';
+    outputName = 'viewer.js';
+    template = 'web/viewer.js';
+    files = ['app.js'];
+    if (defines.FIREFOX || defines.MOZCENTRAL) {
+      files.push('firefoxcom.js');
+    } else if (defines.CHROME) {
+      files.push('chromecom.js', 'mozPrintCallback_polyfill.js');
+    } else if (defines.GENERIC) {
+      files.push('mozPrintCallback_polyfill.js');
+    }
+  }
+
+  var source = stream.Readable({ objectMode: true });
+  source._read = function () {
+    // 'buildnumber' shall create BUILD_DIR for us
+    var tmpFile = BUILD_DIR + '~' + outputName + '.tmp';
+    bundle(template, tmpFile, 'web/', files, amdName, defines, false,
+      versionJSON);
+    this.push(new gutil.File({
+      cwd: '',
+      base: '',
+      path: outputName,
+      contents: fs.readFileSync(tmpFile)
+    }));
+    fs.unlinkSync(tmpFile);
+    this.push(null);
+  };
+  return source;
+}
+
 gulp.task('default', function() {
   console.log('Available tasks:');
   var tasks = Object.keys(gulp.tasks);
@@ -51,6 +257,88 @@ gulp.task('default', function() {
   });
 });
 
+gulp.task('buildnumber', function (done) {
+  console.log();
+  console.log('### Getting extension build number');
+
+  exec('git log --format=oneline ' + config.baseVersion + '..',
+      function (err, stdout, stderr) {
+    var buildNumber = 0;
+    if (!err) {
+      // Build number is the number of commits since base version
+      buildNumber = stdout ? stdout.match(/\n/g).length : 0;
+    }
+
+    console.log('Extension build number: ' + buildNumber);
+
+    var version = config.versionPrefix + buildNumber;
+
+    exec('git log --format="%h" -n 1', function (err, stdout, stderr) {
+      var buildCommit = '';
+      if (!err) {
+        buildCommit = stdout.replace('\n', '');
+      }
+
+      createStringSource('version.json', JSON.stringify({
+        version: version,
+        build: buildNumber,
+        commit: buildCommit
+      }, null, 2))
+        .pipe(gulp.dest(BUILD_DIR))
+        .on('end', done);
+    });
+  });
+});
+
+gulp.task('bundle-firefox', ['buildnumber'], function () {
+  var defines = builder.merge(DEFINES, {FIREFOX: true});
+  return streamqueue({ objectMode: true },
+    createBundle(defines), createWebBundle(defines))
+    .pipe(gulp.dest(BUILD_DIR));
+});
+
+gulp.task('bundle-mozcentral', ['buildnumber'], function () {
+  var defines = builder.merge(DEFINES, {MOZCENTRAL: true});
+  return streamqueue({ objectMode: true },
+    createBundle(defines), createWebBundle(defines))
+    .pipe(gulp.dest(BUILD_DIR));
+});
+
+gulp.task('bundle-chromium', ['buildnumber'], function () {
+  var defines = builder.merge(DEFINES, {CHROME: true});
+  return streamqueue({ objectMode: true },
+    createBundle(defines), createWebBundle(defines))
+    .pipe(gulp.dest(BUILD_DIR));
+});
+
+gulp.task('bundle-singlefile', ['buildnumber'], function () {
+  var defines = builder.merge(DEFINES, {SINGLE_FILE: true});
+  return createBundle(defines).pipe(gulp.dest(BUILD_DIR));
+});
+
+gulp.task('bundle-generic', ['buildnumber'], function () {
+  var defines = builder.merge(DEFINES, {GENERIC: true});
+  return streamqueue({ objectMode: true },
+    createBundle(), createWebBundle(defines))
+    .pipe(gulp.dest(BUILD_DIR));
+});
+
+gulp.task('bundle-minified', ['buildnumber'], function () {
+  var defines = builder.merge(DEFINES, {MINIFIED: true, GENERIC: true});
+  return streamqueue({ objectMode: true },
+    createBundle(), createWebBundle(defines))
+    .pipe(gulp.dest(BUILD_DIR));
+});
+
+gulp.task('bundle-components', ['buildnumber'], function () {
+  var defines = builder.merge(DEFINES, {COMPONENTS: true, GENERIC: true});
+  return createWebBundle(defines).pipe(gulp.dest(BUILD_DIR));
+});
+
+gulp.task('bundle', ['buildnumber'], function () {
+  return createBundle().pipe(gulp.dest(BUILD_DIR));
+});
+
 gulp.task('server', function (done) {
   console.log();
   console.log('### Starting local server');
diff --git a/make.js b/make.js
index a6df503e9..9272813fa 100644
--- a/make.js
+++ b/make.js
@@ -27,18 +27,12 @@ try {
 }
 
 var builder = require('./external/builder/builder.js');
-var crlfchecker = require('./external/crlfchecker/crlfchecker.js');
 var path = require('path');
 var fs = require('fs');
 
 var CONFIG_FILE = 'pdfjs.config';
 var config = JSON.parse(fs.readFileSync(CONFIG_FILE));
 
-// Defined by buildnumber target.
-var BUILD_NUMBER,
-    BUILD_COMMIT,
-    VERSION;
-
 var ROOT_DIR = __dirname + '/', // absolute path to project's root
     BUILD_DIR = 'build/',
     SRC_DIR = 'src/',
@@ -77,6 +71,12 @@ var DEFINES = {
   COMPONENTS: false
 };
 
+function getCurrentVersion() {
+  // The 'build/version.json' file is created by 'buildnumber' task.
+  return JSON.parse(fs.readFileSync(ROOT_DIR + 'build/version.json').toString())
+    .version;
+}
+
 //
 // make all
 //
@@ -112,7 +112,8 @@ var COMMON_WEB_FILES =
 // modern HTML5 browsers.
 //
 target.generic = function() {
-  target.bundle({});
+  exec('gulp bundle-generic');
+
   target.locale();
 
   cd(ROOT_DIR);
@@ -127,16 +128,11 @@ target.generic = function() {
 
   var defines = builder.merge(DEFINES, {GENERIC: true});
 
-  var TMP_VIEWER = GENERIC_DIR + '/web/viewer.js.tmp';
-  cd('web/');
-  var viewerBundleFiles = ['app.js', 'mozPrintCallback_polyfill.js'];
-  bundle('viewer.js', ROOT_DIR + TMP_VIEWER,  viewerBundleFiles,
-    'pdfjs-dist/web/viewer', defines, true);
-  cd(ROOT_DIR);
-
   var setup = {
     defines: defines,
     copy: [
+      [BUILD_TARGETS, GENERIC_DIR + BUILD_DIR],
+      [BUILD_DIR + 'viewer.js', GENERIC_DIR + '/web'],
       [COMMON_WEB_FILES, GENERIC_DIR + '/web'],
       ['LICENSE', GENERIC_DIR],
       ['external/webL10n/l10n.js', GENERIC_DIR + '/web'],
@@ -146,8 +142,6 @@ target.generic = function() {
       ['web/locale', GENERIC_DIR + '/web']
     ],
     preprocess: [
-      [BUILD_TARGETS, GENERIC_DIR + BUILD_DIR],
-      [TMP_VIEWER, GENERIC_DIR + '/web/viewer.js'],
       [COMMON_WEB_FILES_PREPROCESS, GENERIC_DIR + '/web']
     ],
     preprocessCSS: [
@@ -160,10 +154,11 @@ target.generic = function() {
   cleanupJSSource(GENERIC_DIR + '/build/pdf.js');
   cleanupJSSource(GENERIC_DIR + '/web/viewer.js');
   cleanupCSSSource(GENERIC_DIR + '/web/viewer.css');
-  rm(TMP_VIEWER);
 };
 
 target.components = function() {
+  exec('gulp bundle-components');
+
   cd(ROOT_DIR);
   echo();
   echo('### Creating generic components');
@@ -174,18 +169,6 @@ target.components = function() {
 
   var defines = builder.merge(DEFINES, {COMPONENTS: true, GENERIC: true});
 
-  var TMP_PDF_VIEWER = COMPONENTS_DIR + 'pdf_viewer.js.tmp';
-  cd('web/');
-  var bundleFiles = [
-    'pdf_viewer.js',
-    'pdf_history.js',
-    'pdf_find_controller.js',
-    'download_manager.js'
-  ];
-  bundle('pdf_viewer.component.js', ROOT_DIR + TMP_PDF_VIEWER, bundleFiles,
-    'pdfjs-dist/web/pdf_viewer', defines, true);
-  cd(ROOT_DIR);
-
   var COMPONENTS_IMAGES = [
     'web/images/annotation-*.svg',
     'web/images/loading-icon.gif',
@@ -196,12 +179,11 @@ target.components = function() {
   var setup = {
     defines: defines,
     copy: [
+      [BUILD_DIR + 'pdf_viewer.js', COMPONENTS_DIR],
       [COMPONENTS_IMAGES, COMPONENTS_DIR + 'images'],
       ['web/compatibility.js', COMPONENTS_DIR],
     ],
-    preprocess: [
-      [TMP_PDF_VIEWER, COMPONENTS_DIR + 'pdf_viewer.js'],
-    ],
+    preprocess: [],
     preprocessCSS: [
       ['components', 'web/pdf_viewer.css', COMPONENTS_DIR + 'pdf_viewer.css'],
     ]
@@ -210,7 +192,6 @@ target.components = function() {
 
   cleanupJSSource(COMPONENTS_DIR + 'pdf_viewer.js');
   cleanupCSSSource(COMPONENTS_DIR + 'pdf_viewer.css');
-  rm(TMP_PDF_VIEWER);
 };
 
 target.jsdoc = function() {
@@ -287,6 +268,7 @@ target.web = function() {
         GH_PAGES_DIR + '/getting_started/index.html');
     echo('Done building with wintersmith.');
 
+    var VERSION = getCurrentVersion();
     var reason = process.env['PDFJS_UPDATE_REASON'];
     cd(GH_PAGES_DIR);
     exec('git init');
@@ -308,6 +290,7 @@ target.dist = function() {
 
   var DIST_DIR = BUILD_DIR + 'dist/';
   var DIST_REPO_URL = 'https://github.com/mozilla/pdfjs-dist';
+  var VERSION = getCurrentVersion();
 
   cd(ROOT_DIR);
 
@@ -403,6 +386,7 @@ target.dist = function() {
 
 target.publish = function() {
   target.generic();
+  var VERSION = getCurrentVersion();
   config.stableVersion = config.betaVersion;
   config.betaVersion = VERSION;
   fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
@@ -501,101 +485,12 @@ target.cmaps = function () {
   compressCmaps(CMAP_INPUT, VIEWER_CMAP_OUTPUT, true);
 };
 
-function bundle(filename, outfilename, initFiles, amdName, defines,
-                isMainFile) {
-  // Reading UMD headers and building loading orders of modules. The
-  // readDependencies returns AMD module names: removing 'pdfjs' prefix and
-  // adding '.js' extensions to the name.
-  var umd = require('./external/umdutils/verifier.js');
-  var files = umd.readDependencies(initFiles).loadOrder.map(
-    function (name) { return name.replace(/^[\w\-]+\//, '') + '.js'; });
-
-  crlfchecker.checkIfCrlfIsPresent(files);
-
-  var bundleContent = cat(files),
-      bundleVersion = VERSION,
-      bundleBuild = BUILD_COMMIT;
-
-  // Prepend a newline because stripCommentHeaders only strips comments that
-  // follow a line feed. The file where bundleContent is inserted already
-  // contains a license header, so the header of bundleContent can be removed.
-  bundleContent = stripCommentHeaders('\n' + bundleContent);
-
-  // Removes AMD and CommonJS branches from UMD headers.
-  bundleContent = stripUMDHeaders(bundleContent);
-
-  var jsName = amdName.replace(/[\-_\.\/]\w/g, function (all) {
-    return all[1].toUpperCase();
-  });
-
-  // This just preprocesses the empty pdf.js file, we don't actually want to
-  // preprocess everything yet since other build targets use this file.
-  builder.preprocess(filename, outfilename,
-    builder.merge(defines, {
-      BUNDLE: bundleContent,
-      BUNDLE_VERSION: bundleVersion,
-      BUNDLE_BUILD: bundleBuild,
-      BUNDLE_AMD_NAME: amdName,
-      BUNDLE_JS_NAME: jsName,
-      MAIN_FILE: isMainFile
-    }));
-}
-
 //
 // make bundle
 // Bundles all source files into one wrapper 'pdf.js' file, in the given order.
 //
 target.bundle = function(args) {
-  args = args || {};
-  var defines = args.defines || DEFINES;
-
-  target.buildnumber();
-
-  cd(ROOT_DIR);
-  echo();
-  echo('### Bundling files into ' + BUILD_TARGET);
-
-  if (!test('-d', BUILD_DIR)) {
-    mkdir(BUILD_DIR);
-  }
-
-  var mainFiles = [
-    'display/global.js'
-  ];
-
-  var workerFiles = [
-    'core/worker.js'
-  ];
-
-  var mainAMDName = 'pdfjs-dist/build/pdf';
-  var workerAMDName = 'pdfjs-dist/build/pdf.worker';
-
-  // Extension does not need network.js file.
-  if (!defines.FIREFOX && !defines.MOZCENTRAL) {
-    workerFiles.push('core/network.js');
-  }
-
-  if (defines.SINGLE_FILE) {
-    // In singlefile mode, all of the src files will be bundled into
-    // the main pdf.js output.
-    mainFiles = mainFiles.concat(workerFiles);
-    workerFiles = null; // no need for worker file
-    mainAMDName = 'pdfjs-dist/build/pdf.combined';
-    workerAMDName = null;
-  }
-
-  cd(SRC_DIR);
-
-  bundle('pdf.js', ROOT_DIR + BUILD_TARGET, mainFiles, mainAMDName, defines,
-         true);
-
-  if (workerFiles) {
-    var srcCopy = ROOT_DIR + BUILD_DIR + 'pdf.worker.js.temp';
-    cp('pdf.js', srcCopy);
-    bundle(srcCopy, ROOT_DIR + BUILD_WORKER_TARGET, workerFiles, workerAMDName,
-           defines, false);
-    rm(srcCopy);
-  }
+  exec('gulp bundle');
 };
 
 //
@@ -608,36 +503,17 @@ target.singlefile = function() {
   echo();
   echo('### Creating singlefile build');
 
-  var SINGLE_FILE_TARGET = BUILD_DIR + 'pdf.combined.js';
+  var SINGLE_FILE_BUILD_DIR = SINGLE_FILE_DIR + 'build/';
 
-  var defines = builder.merge(DEFINES, {SINGLE_FILE: true});
-  target.bundle({defines: defines});
+  exec('gulp bundle-singlefile');
 
   cd(ROOT_DIR);
 
   rm('-rf', SINGLE_FILE_DIR);
   mkdir('-p', SINGLE_FILE_DIR);
-  mkdir('-p', SINGLE_FILE_DIR + BUILD_DIR);
-
-  var setup = {
-    defines: defines,
-    copy: [],
-    preprocess: [
-      [BUILD_TARGETS, SINGLE_FILE_DIR + BUILD_DIR]
-    ]
-  };
-  builder.build(setup);
-
-  cd(SINGLE_FILE_DIR);
-
-  echo();
-  echo('### Moving pdf.js to pdf.combined.js');
-  var pdfJs = cat(BUILD_TARGET);
-  pdfJs.to(SINGLE_FILE_TARGET);
-
-  rm(BUILD_TARGET);
-  rm(BUILD_WORKER_TARGET);
+  mkdir('-p', SINGLE_FILE_BUILD_DIR);
 
+  cp(BUILD_DIR + 'pdf.combined.js', SINGLE_FILE_BUILD_DIR);
 };
 
 function stripCommentHeaders(content) {
@@ -650,14 +526,6 @@ function stripCommentHeaders(content) {
   return content;
 }
 
-function stripUMDHeaders(content) {
-  var reg = new RegExp(
-    'if \\(typeof define === \'function\' && define.amd\\) \\{[^}]*' +
-    '\\} else if \\(typeof exports !== \'undefined\'\\) \\{[^}]*' +
-    '\\} else ', 'g');
-  return content.replace(reg, '');
-}
-
 function cleanupJSSource(file) {
   var content = cat(file);
 
@@ -682,7 +550,7 @@ function cleanupCSSSource(file) {
 // modern HTML5 browsers.
 //
 target.minified = function() {
-  target.bundle({});
+  exec('gulp bundle-minified');
   target.locale();
 
   cd(ROOT_DIR);
@@ -697,24 +565,17 @@ target.minified = function() {
 
   var defines = builder.merge(DEFINES, {GENERIC: true, MINIFIED: true});
 
-  var TMP_VIEWER = MINIFIED_DIR + '/web/viewer.js.tmp';
-  cd('web/');
-  var viewerBundleFiles = ['app.js'];
-  bundle('viewer.js', ROOT_DIR + TMP_VIEWER, viewerBundleFiles,
-    'pdfjs-dist/web/viewer', defines, true);
-  cd(ROOT_DIR);
-
   var setup = {
     defines: defines,
     copy: [
+      [BUILD_TARGETS, MINIFIED_DIR + BUILD_DIR],
+      [BUILD_DIR + 'viewer.js', MINIFIED_DIR + '/web'],
       [COMMON_WEB_FILES, MINIFIED_DIR + '/web'],
       ['web/compressed.tracemonkey-pldi-09.pdf', MINIFIED_DIR + '/web'],
       ['external/bcmaps/*', MINIFIED_DIR + '/web/cmaps'],
       ['web/locale', MINIFIED_DIR + '/web']
     ],
     preprocess: [
-      [BUILD_TARGETS, MINIFIED_DIR + BUILD_DIR],
-      [TMP_VIEWER, MINIFIED_DIR + '/web/viewer.js'],
       [COMMON_WEB_FILES_PREPROCESS, MINIFIED_DIR + '/web']
     ],
     preprocessCSS: [
@@ -725,7 +586,6 @@ target.minified = function() {
   builder.build(setup);
 
   cleanupCSSSource(MINIFIED_DIR + '/web/viewer.css');
-  rm(TMP_VIEWER);
 
   var viewerFiles = [
     'web/compatibility.js',
@@ -780,21 +640,7 @@ target.extension = function() {
 };
 
 target.buildnumber = function() {
-  cd(ROOT_DIR);
-  echo();
-  echo('### Getting extension build number');
-
-  var lines = exec('git log --format=oneline ' +
-                   config.baseVersion + '..', {silent: true}).output;
-  // Build number is the number of commits since base version
-  BUILD_NUMBER = lines ? lines.match(/\n/g).length : 0;
-
-  echo('Extension build number: ' + BUILD_NUMBER);
-
-  VERSION = config.versionPrefix + BUILD_NUMBER;
-
-  BUILD_COMMIT = exec('git log --format="%h" -n 1',  {silent: true}).
-    output.replace('\n', '');
+  exec('gulp buildnumber');
 };
 
 //
@@ -831,7 +677,7 @@ target.firefox = function() {
       FIREFOX_AMO_EXTENSION_NAME = 'pdf.js.amo.xpi';
 
   target.locale();
-  target.bundle({ defines: defines });
+  exec('gulp bundle-firefox');
   cd(ROOT_DIR);
 
   // Clear out everything in the firefox extension build directory
@@ -852,17 +698,11 @@ target.firefox = function() {
   cp('-R', FIREFOX_EXTENSION_FILES_TO_COPY, ROOT_DIR + FIREFOX_BUILD_DIR);
   cd(ROOT_DIR);
 
-  var TMP_VIEWER = FIREFOX_BUILD_CONTENT_DIR + '/web/viewer.js.tmp';
-  cd('web/');
-  var viewerBundleFiles = ['app.js', 'firefoxcom.js'];
-  bundle('viewer.js', ROOT_DIR + TMP_VIEWER, viewerBundleFiles,
-    'pdfjs-dist/web/viewer', defines, true);
-  cd(ROOT_DIR);
-
-
   var setup = {
     defines: defines,
     copy: [
+      [BUILD_TARGETS, FIREFOX_BUILD_CONTENT_DIR + BUILD_DIR],
+      [BUILD_DIR + 'viewer.js', FIREFOX_BUILD_CONTENT_DIR + '/web'],
       [COMMON_WEB_FILES, FIREFOX_BUILD_CONTENT_DIR + '/web'],
       ['web/compatibility.js', FIREFOX_BUILD_CONTENT_DIR + '/web'],
       ['external/bcmaps/*', FIREFOX_BUILD_CONTENT_DIR + '/web/cmaps'],
@@ -870,9 +710,7 @@ target.firefox = function() {
        FIREFOX_BUILD_CONTENT_DIR + '/web']
     ],
     preprocess: [
-      [TMP_VIEWER, FIREFOX_BUILD_CONTENT_DIR + '/web/viewer.js'],
       [COMMON_WEB_FILES_PREPROCESS, FIREFOX_BUILD_CONTENT_DIR + '/web'],
-      [BUILD_TARGETS, FIREFOX_BUILD_CONTENT_DIR + BUILD_DIR],
       [COMMON_FIREFOX_FILES_PREPROCESS, FIREFOX_BUILD_CONTENT_DIR],
       [SRC_DIR + 'core/network.js', FIREFOX_BUILD_CONTENT_DIR],
       [FIREFOX_EXTENSION_DIR + 'bootstrap.js', FIREFOX_BUILD_DIR]
@@ -888,7 +726,6 @@ target.firefox = function() {
   cleanupJSSource(FIREFOX_BUILD_DIR + 'bootstrap.js');
   cleanupJSSource(FIREFOX_BUILD_CONTENT_DIR + 'PdfjsChromeUtils.jsm');
   cleanupCSSSource(FIREFOX_BUILD_CONTENT_DIR + '/web/viewer.css');
-  rm(TMP_VIEWER);
 
   // Remove '.DS_Store' and other hidden files
   find(FIREFOX_BUILD_DIR).forEach(function(file) {
@@ -898,6 +735,7 @@ target.firefox = function() {
   });
 
   // Update the build version number
+  var VERSION = getCurrentVersion();
   sed('-i', /PDFJSSCRIPT_VERSION/, VERSION,
       FIREFOX_BUILD_DIR + '/install.rdf');
   sed('-i', /PDFJSSCRIPT_VERSION/, VERSION,
@@ -968,7 +806,7 @@ target.mozcentral = function() {
         ['icon.png',
          'icon64.png'];
 
-  target.bundle({ defines: defines });
+  exec('gulp bundle-mozcentral');
   cd(ROOT_DIR);
 
   // Clear out everything in the firefox extension build directory
@@ -989,25 +827,18 @@ target.mozcentral = function() {
            ROOT_DIR + MOZCENTRAL_EXTENSION_DIR + '/chrome.manifest');
   cd(ROOT_DIR);
 
-  var TMP_VIEWER = MOZCENTRAL_CONTENT_DIR + '/web/viewer.js.tmp';
-  cd('web/');
-  var viewerBundleFiles = ['app.js', 'firefoxcom.js'];
-  bundle('viewer.js', ROOT_DIR + TMP_VIEWER, viewerBundleFiles,
-    'pdfjs-dist/web/viewer', defines, true);
-  cd(ROOT_DIR);
-
   var setup = {
     defines: defines,
     copy: [
+      [BUILD_TARGETS, MOZCENTRAL_CONTENT_DIR + BUILD_DIR],
+      [BUILD_DIR + 'viewer.js', MOZCENTRAL_CONTENT_DIR + '/web'],
       [COMMON_WEB_FILES, MOZCENTRAL_CONTENT_DIR + '/web'],
       ['external/bcmaps/*', MOZCENTRAL_CONTENT_DIR + '/web/cmaps'],
       ['extensions/firefox/tools/l10n.js', MOZCENTRAL_CONTENT_DIR + '/web']
     ],
     preprocess: [
-      [TMP_VIEWER, MOZCENTRAL_CONTENT_DIR + '/web/viewer.js'],
       [COMMON_WEB_FILES_PREPROCESS, MOZCENTRAL_CONTENT_DIR + '/web'],
       [FIREFOX_CONTENT_DIR + 'pdfjschildbootstrap.js', MOZCENTRAL_CONTENT_DIR],
-      [BUILD_TARGETS, MOZCENTRAL_CONTENT_DIR + BUILD_DIR],
       [SRC_DIR + 'core/network.js', MOZCENTRAL_CONTENT_DIR],
       [COMMON_FIREFOX_FILES_PREPROCESS, MOZCENTRAL_CONTENT_DIR],
       [FIREFOX_CONTENT_DIR + 'PdfJs.jsm', MOZCENTRAL_CONTENT_DIR]
@@ -1024,7 +855,6 @@ target.mozcentral = function() {
   cleanupJSSource(MOZCENTRAL_CONTENT_DIR + '/PdfJs.jsm');
   cleanupJSSource(MOZCENTRAL_CONTENT_DIR + '/PdfjsChromeUtils.jsm');
   cleanupCSSSource(MOZCENTRAL_CONTENT_DIR + '/web/viewer.css');
-  rm(TMP_VIEWER);
 
   // Remove '.DS_Store' and other hidden files
   find(MOZCENTRAL_DIR).forEach(function(file) {
@@ -1046,6 +876,7 @@ target.mozcentral = function() {
   cp(DEFAULT_LOCALE_FILES, MOZCENTRAL_L10N_DIR);
 
   // Update the build version number
+  var VERSION = getCurrentVersion();
   sed('-i', /PDFJSSCRIPT_VERSION/, VERSION,
       MOZCENTRAL_EXTENSION_DIR + 'README.mozilla');
 
@@ -1068,7 +899,6 @@ target.b2g = function() {
   echo();
   echo('### Building B2G (Firefox OS App)');
   var B2G_BUILD_CONTENT_DIR = B2G_BUILD_DIR + '/content/';
-  target.bundle();
 
   // Clear out everything in the b2g build directory
   cd(ROOT_DIR);
@@ -1121,7 +951,7 @@ target.chromium = function() {
   var CHROME_BUILD_DIR = BUILD_DIR + '/chromium/',
       CHROME_BUILD_CONTENT_DIR = CHROME_BUILD_DIR + '/content/';
 
-  target.bundle({ defines: defines });
+  exec('gulp bundle-chromium');
   cd(ROOT_DIR);
 
   // Clear out everything in the chrome extension build directory
@@ -1130,17 +960,11 @@ target.chromium = function() {
   mkdir('-p', CHROME_BUILD_CONTENT_DIR + BUILD_DIR);
   mkdir('-p', CHROME_BUILD_CONTENT_DIR + '/web');
 
-  var TMP_VIEWER = CHROME_BUILD_CONTENT_DIR + '/web/viewer.js.tmp';
-  cd('web/');
-  var viewerBundleFiles = ['app.js', 'chromecom.js',
-                           'mozPrintCallback_polyfill.js'];
-  bundle('viewer.js', ROOT_DIR + TMP_VIEWER, viewerBundleFiles,
-    'pdfjs-dist/web/viewer', defines, true);
-  cd(ROOT_DIR);
-
   var setup = {
     defines: defines,
     copy: [
+      [BUILD_TARGETS, CHROME_BUILD_CONTENT_DIR + BUILD_DIR],
+      [BUILD_DIR + 'viewer.js', CHROME_BUILD_CONTENT_DIR + '/web'],
       [COMMON_WEB_FILES, CHROME_BUILD_CONTENT_DIR + '/web'],
       [['extensions/chromium/*.json',
         'extensions/chromium/*.html',
@@ -1155,8 +979,6 @@ target.chromium = function() {
       ['web/locale', CHROME_BUILD_CONTENT_DIR + '/web']
     ],
     preprocess: [
-      [BUILD_TARGETS, CHROME_BUILD_CONTENT_DIR + BUILD_DIR],
-      [TMP_VIEWER, CHROME_BUILD_CONTENT_DIR + '/web/viewer.js'],
       [COMMON_WEB_FILES_PREPROCESS, CHROME_BUILD_CONTENT_DIR + '/web']
     ],
     preprocessCSS: [
@@ -1168,9 +990,9 @@ target.chromium = function() {
 
   cleanupJSSource(CHROME_BUILD_CONTENT_DIR + '/web/viewer.js');
   cleanupCSSSource(CHROME_BUILD_CONTENT_DIR + '/web/viewer.css');
-  rm(TMP_VIEWER);
 
   // Update the build version number
+  var VERSION = getCurrentVersion();
   sed('-i', /PDFJSSCRIPT_VERSION/, VERSION,
       CHROME_BUILD_DIR + '/manifest.json');
 
@@ -1597,3 +1419,6 @@ target.makefile = function () {
 target.importl10n = function() {
   exit(exec('gulp importl10n'));
 };
+
+exports.stripCommentHeaders = stripCommentHeaders;
+exports.builder = builder;
diff --git a/package.json b/package.json
index d79065175..7266e6a8b 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
     "requirejs": "^2.1.22",
     "rimraf": "^2.4.1",
     "shelljs": "~0.4.0",
+    "streamqueue": "^1.1.1",
     "typogr": "~0.6.5",
     "uglify-js": "^2.6.1",
     "wintersmith": "^2.0.0",
diff --git a/web/app.js b/web/app.js
index 98c784779..adae4d761 100644
--- a/web/app.js
+++ b/web/app.js
@@ -2146,7 +2146,7 @@ window.addEventListener('afterprint', function afterPrint(evt) {
 exports.PDFViewerApplication = PDFViewerApplication;
 exports.DefaultExernalServices = DefaultExernalServices;
 
-// TODO remove circular reference of pdfjs-web/secondary_toolbar on app.
+//// TODO remove circular reference of pdfjs-web/secondary_toolbar on app.
 secondaryToolbarLib._setApp(exports);
 
 }));