diff --git a/Brocfile-js_prod.js b/Brocfile-js_prod.js new file mode 100644 index 0000000000..90a9652ee3 --- /dev/null +++ b/Brocfile-js_prod.js @@ -0,0 +1,108 @@ +var Funnel = require('broccoli-funnel'); +var flatten = require('broccoli-flatten'); +var mergeTrees = require('broccoli-merge-trees'); +var stew = require('broccoli-stew'); +var TraceurCompiler = require('./tools/broccoli/traceur'); +var replace = require('broccoli-replace'); +var htmlReplace = require('./tools/broccoli/html-replace'); +var path = require('path'); + +var modulesTree = new Funnel('modules', {include: ['**/**'], destDir: '/'}); + +// Use Traceur to transpile original sources to ES6 +var es6ProdTree = new TraceurCompiler(modulesTree, '.es6', { + sourceMaps: true, + annotations: true, // parse annotations + types: true, // parse types + script: false, // parse as a module + memberVariables: true, // parse class fields + modules: 'instantiate', + typeAssertionModule: 'rtts_assert/rtts_assert', + typeAssertions: false, + outputLanguage: 'es6' +}); +// Munge the filenames since we use an '.es6' extension +es6ProdTree = stew.rename(es6ProdTree, function(relativePath) { + return relativePath.replace(/\.(js|es6)\.map$/, '.map').replace(/\.js$/, '.es6'); +}); + +// Call Traceur again to lower the ES6 build tree to ES5 +var es5ProdTree = new TraceurCompiler(es6ProdTree, '.js', {modules: 'instantiate', sourceMaps: true}); +es5ProdTree = stew.rename(es5ProdTree, '.es6.map', '.js.map'); + +// Now we add a few more files to the es6 tree that Traceur should not see +['angular2', 'benchmarks', 'benchmarks_external', 'benchpress', 'examples', 'rtts_assert'].forEach( + function(destDir) { + var extras = new Funnel('tools/build', {files: ['es5build.js'], destDir: destDir}); + es6ProdTree = mergeTrees([es6ProdTree, extras]); + }); + +var vendorScriptsTree = flatten(new Funnel('.', { + files: [ + 'node_modules/es6-module-loader/dist/es6-module-loader-sans-promises.src.js', + 'node_modules/zone.js/zone.js', + 'node_modules/zone.js/long-stack-trace-zone.js', + 'node_modules/systemjs/dist/system.src.js', + 'node_modules/systemjs/lib/extension-register.js', + 'node_modules/systemjs/lib/extension-cjs.js', + 'node_modules/rx/dist/rx.all.js', + 'tools/build/snippets/runtime_paths.js', + path.relative(__dirname, TraceurCompiler.RUNTIME_PATH) + ] +})); +var vendorScripts_benchmark = + new Funnel('tools/build/snippets', {files: ['url_params_to_form.js'], destDir: '/'}); +var vendorScripts_benchmarks_external = + new Funnel('node_modules/angular', {files: ['angular.js'], destDir: '/'}); + +var servingTrees = []; +function copyVendorScriptsTo(destDir) { + servingTrees.push(new Funnel(vendorScriptsTree, {srcDir: '/', destDir: destDir})); + if (destDir.indexOf('benchmarks') > -1) { + servingTrees.push(new Funnel(vendorScripts_benchmark, {srcDir: '/', destDir: destDir})); + } + if (destDir.indexOf('benchmarks_external') > -1) { + servingTrees.push( + new Funnel(vendorScripts_benchmarks_external, {srcDir: '/', destDir: destDir})); + } +} + +function writeScriptsForPath(relativePath, result) { + copyVendorScriptsTo(path.dirname(relativePath)); + return result.replace('@@FILENAME_NO_EXT', relativePath.replace(/\.\w+$/, '')); +} + +var htmlTree = new Funnel(modulesTree, {include: ['*/src/**/*.html'], destDir: '/'}); +htmlTree = replace(htmlTree, { + files: ['examples*/**'], + patterns: [{match: /\$SCRIPTS\$/, replacement: htmlReplace('SCRIPTS')}], + replaceWithPath: writeScriptsForPath +}); +htmlTree = replace(htmlTree, { + files: ['benchmarks/**'], + patterns: [{match: /\$SCRIPTS\$/, replacement: htmlReplace('SCRIPTS_benchmarks')}], + replaceWithPath: writeScriptsForPath +}); +htmlTree = replace(htmlTree, { + files: ['benchmarks_external/**'], + patterns: [{match: /\$SCRIPTS\$/, replacement: htmlReplace('SCRIPTS_benchmarks_external')}], + replaceWithPath: writeScriptsForPath +}); +// TODO(broccoli): are these needed here, if not loaded by a script tag?? +['benchmarks/src', 'benchmarks_external/src', 'examples/src/benchpress'].forEach( + copyVendorScriptsTo); + +var scripts = mergeTrees(servingTrees, {overwrite: true}); +var css = new Funnel(modulesTree, {include: ["**/*.css"]}); +var polymerFiles = new Funnel('.', { + files: [ + 'bower_components/polymer/lib/polymer.html', + 'tools/build/snippets/url_params_to_form.js' + ] +}); +var polymer = stew.mv(flatten(polymerFiles), 'benchmarks_external/src/tree/polymer'); +htmlTree = mergeTrees([htmlTree, scripts, polymer, css]); + +es5ProdTree = mergeTrees([es5ProdTree, htmlTree]); + +module.exports = mergeTrees([stew.mv(es6ProdTree, 'js/prod/es6'), stew.mv(es5ProdTree, 'js/prod/es5')]); diff --git a/gulpfile.js b/gulpfile.js index a60fd6cc99..311280421e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -758,6 +758,11 @@ gulp.task('build.dart', function(done) { gulp.task('broccoli.js.dev', function() { return broccoliBuild(require('./Brocfile-js_dev.js'), path.join('js', 'dev')); }); + +gulp.task('broccoli.js.prod', function() { + return broccoliBuild(require('./Brocfile-js_prod.js'), path.join('js', 'prod')); +}); + gulp.task('build.js.dev', function(done) { runSequence( 'broccoli.js.dev', @@ -766,12 +771,7 @@ gulp.task('build.js.dev', function(done) { ); }); -gulp.task('build.js.prod', function(done) { - runSequence( - ['build/transpile.js.prod', 'build/html.js.prod', 'build/copy.js.prod', 'build/multicopy.js.prod.es6'], - done - ); -}); +gulp.task('build.js.prod', ['broccoli.js.prod']); gulp.task('broccoli.js.cjs', function() { return broccoliBuild(require('./Brocfile-js_cjs.js'), path.join('js', 'cjs')); diff --git a/tools/broccoli/gulp/index.js b/tools/broccoli/gulp/index.js index 222326d769..f4a150e030 100644 --- a/tools/broccoli/gulp/index.js +++ b/tools/broccoli/gulp/index.js @@ -33,6 +33,7 @@ function broccoliBuild(tree, outputRoot) { var builder = new broccoli.Builder(tree); return builder.build() .then(function (hash) { + console.log('=== Stats for %s (total: %ds) ===', outputRoot, Math.round(hash.totalTime/1000000)/1000); printSlowTrees(hash.graph); var dir = hash.directory; @@ -49,6 +50,8 @@ function broccoliBuild(tree, outputRoot) { time('Build cleanup', function() { builder.cleanup(); }); + + console.log('=== Done building %s ===', outputRoot); }) .catch(function (err) { // Should show file and line/col if present