refactor(build): introduce AngularBuilder facade and clean up many things
This commit is contained in:
		
							parent
							
								
									4c9b8ebb0c
								
							
						
					
					
						commit
						1cbdb9cd17
					
				
							
								
								
									
										117
									
								
								gulpfile.js
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								gulpfile.js
									
									
									
									
									
								
							| @ -12,7 +12,6 @@ var madge = require('madge'); | ||||
| var merge = require('merge'); | ||||
| var merge2 = require('merge2'); | ||||
| var path = require('path'); | ||||
| var Q = require('q'); | ||||
| 
 | ||||
| var gulpTraceur = require('./tools/transpiler/gulp-traceur'); | ||||
| var clean = require('./tools/build/clean'); | ||||
| @ -35,11 +34,19 @@ var bundler = require('./tools/build/bundle'); | ||||
| var replace = require('gulp-replace'); | ||||
| var insert = require('gulp-insert'); | ||||
| 
 | ||||
| // dynamic require in build.broccoli.tools so we can bootstrap TypeScript compilation
 | ||||
| function missingDynamicBroccoli() { | ||||
|   throw new Error('ERROR: build.broccoli.tools task should have been run before using broccoli'); | ||||
| 
 | ||||
| // dynamic require in build.tools so we can bootstrap TypeScript compilation
 | ||||
| function throwToolsBuildMissingError() { | ||||
|   throw new Error('ERROR: build.tools task should have been run before using angularBuilder'); | ||||
| } | ||||
| var getBroccoli = missingDynamicBroccoli; | ||||
| 
 | ||||
| var angularBuilder = { | ||||
|   rebuildBrowserDevTree: throwToolsBuildMissingError, | ||||
|   rebuildBrowserProdTree: throwToolsBuildMissingError, | ||||
|   rebuildNodeTree: throwToolsBuildMissingError, | ||||
|   rebuildDartTree: throwToolsBuildMissingError, | ||||
|   cleanup: function() {} | ||||
| }; | ||||
| 
 | ||||
| // Note: when DART_SDK is not found, all gulp tasks ending with `.dart` will be skipped.
 | ||||
| 
 | ||||
| @ -240,7 +247,7 @@ gulp.task('build/clean.docs', clean(gulp, gulpPlugins, { | ||||
| // transpile
 | ||||
| 
 | ||||
| gulp.task('build/tree.dart', ['build.broccoli.tools'], function() { | ||||
|   return getBroccoli().forDartTree().buildOnce(); | ||||
|   return angularBuilder.rebuildDartTree(); | ||||
| }); | ||||
| 
 | ||||
| // ------------
 | ||||
| @ -255,13 +262,6 @@ gulp.task('build/pubspec.dart', pubget.subDir(gulp, gulpPlugins, { | ||||
|   command: DART_SDK.PUB | ||||
| })); | ||||
| 
 | ||||
| // ------------
 | ||||
| // linknodemodules
 | ||||
| 
 | ||||
| gulp.task('build/linknodemodules.js.cjs', linknodemodules(gulp, gulpPlugins, { | ||||
|   dir: CONFIG.dest.js.cjs | ||||
| })); | ||||
| 
 | ||||
| // ------------
 | ||||
| // dartanalyzer
 | ||||
| 
 | ||||
| @ -464,44 +464,19 @@ gulp.task('test.unit.dart/ci', function (done) { | ||||
|   karma.start({configFile: __dirname + '/karma-dart.conf.js', | ||||
|       singleRun: true, reporters: ['dots'], browsers: getBrowsersFromCLI()}, done); | ||||
| }); | ||||
| gulp.task('test.unit.cjs/ci', function () { | ||||
|   return gulp.src(CONFIG.test.js.cjs).pipe(jasmine({includeStackTrace: true, timeout: 1000})); | ||||
| }); | ||||
| gulp.task('test.unit.cjs', ['build.js.cjs'], function () { | ||||
|   //Run tests once
 | ||||
|   runSequence('test.unit.cjs/ci', function() {}); | ||||
| }); | ||||
| 
 | ||||
| function runNodeJasmineTests() { | ||||
|   var doneDeferred = Q.defer(); | ||||
|   var jasmineProcess = fork('./tools/traceur-jasmine', ['dist/js/cjs/angular2/test/**/*_spec.js'], { | ||||
| 
 | ||||
| gulp.task('test.unit.cjs/ci', function(done) { | ||||
|   fork('./tools/traceur-jasmine', ['dist/js/cjs/angular2/test/**/*_spec.js'], { | ||||
|     stdio: 'inherit' | ||||
|   }).on('close', function (exitCode) { | ||||
|     done(exitCode); | ||||
|   }); | ||||
| 
 | ||||
|   jasmineProcess.on('close', function (code) { | ||||
|     doneDeferred.resolve(); | ||||
|   }); | ||||
| 
 | ||||
|   return doneDeferred.promise; | ||||
| } | ||||
| 
 | ||||
| gulp.task('test.unit.cjs/ci', runNodeJasmineTests); | ||||
| 
 | ||||
| gulp.task('test.unit.cjs', ['build.broccoli.tools'], function (done) { | ||||
|   //Run tests once
 | ||||
|   var nodeBroccoliBuilder = getBroccoli().forNodeTree(); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
|   nodeBroccoliBuilder.doBuild().then(function() { | ||||
|     gulp.start('build/linknodemodules.js.cjs'); | ||||
|     return runNodeJasmineTests(); | ||||
|   }).then(function() { | ||||
|     //Watcher to transpile file changed
 | ||||
|     gulp.watch('modules/**', function(event) { | ||||
|       console.log("fs changes detected", event); | ||||
|       nodeBroccoliBuilder.doBuild().then(runNodeJasmineTests); | ||||
|     }); | ||||
|   }); | ||||
| gulp.task('test.unit.cjs', ['test.unit.cjs/ci'], function () { | ||||
|   gulp.watch('modules/**', ['test.unit.cjs/ci']); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| @ -636,12 +611,9 @@ gulp.task('build.broccoli.tools', function() { | ||||
| }); | ||||
| 
 | ||||
| gulp.task('broccoli.js.dev', ['build.broccoli.tools'], function() { | ||||
|   return getBroccoli().forDevTree().buildOnce(); | ||||
|   return angularBuilder.rebuildBrowserDevTree(); | ||||
| }); | ||||
| 
 | ||||
| gulp.task('broccoli.js.prod', ['build.broccoli.tools'], function() { | ||||
|   return getBroccoli().forProdTree().buildOnce(); | ||||
| }); | ||||
| 
 | ||||
| gulp.task('build.js.dev', function(done) { | ||||
|   runSequence( | ||||
| @ -652,19 +624,27 @@ gulp.task('build.js.dev', function(done) { | ||||
|   ); | ||||
| }); | ||||
| 
 | ||||
| gulp.task('build.js.prod', ['broccoli.js.prod']); | ||||
| gulp.task('build.js.prod', ['build.broccoli.tools'], function() { | ||||
|   return angularBuilder.rebuildBrowserProdTree(); | ||||
| }); | ||||
| 
 | ||||
| gulp.task('broccoli.js.cjs', ['build.broccoli.tools'], function() { | ||||
|   return getBroccoli().forNodeTree().buildOnce(); | ||||
| }); | ||||
| gulp.task('build.js.cjs', function(done) { | ||||
|   runSequence( | ||||
|     'broccoli.js.cjs', | ||||
|     'build/linknodemodules.js.cjs', | ||||
|     done | ||||
|   ); | ||||
| 
 | ||||
| var firstBuildJsCjs = true; | ||||
| 
 | ||||
| gulp.task('build.js.cjs', ['build.broccoli.tools'], function() { | ||||
|   return angularBuilder.rebuildNodeTree().then(function() { | ||||
|     if (firstBuildJsCjs) { | ||||
|       firstBuildJsCjs = false; | ||||
|       console.log('creating node_modules symlink hack'); | ||||
|       // linknodemodules is all sync
 | ||||
|       linknodemodules(gulp, gulpPlugins, { | ||||
|         dir: CONFIG.dest.js.cjs | ||||
|       })(); | ||||
|     } | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| var bundleConfig = { | ||||
|   paths: { | ||||
|     "*": "dist/js/prod/es6/*.es6", | ||||
| @ -789,3 +769,20 @@ gulp.task('build/css.dart', function() { | ||||
| }); | ||||
| 
 | ||||
| gulp.task('build.material', ['build.js.dev', 'build/css.js.dev']); | ||||
| 
 | ||||
| 
 | ||||
| gulp.task('cleanup.builder', function() { | ||||
|   angularBuilder.cleanup(); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| // register cleanup listener for ctrl+c/kill used to quit any persistent task (autotest or serve tasks)
 | ||||
| process.on('SIGINT', function() { | ||||
|   gulp.start('cleanup.builder'); | ||||
|   process.exit(); | ||||
| }); | ||||
| 
 | ||||
| // register cleanup listener for all non-persistent tasks
 | ||||
| process.on('beforeExit', function() { | ||||
|   gulp.start('cleanup.builder'); | ||||
| }); | ||||
|  | ||||
							
								
								
									
										98
									
								
								tools/broccoli/angular_builder.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								tools/broccoli/angular_builder.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | ||||
| var broccoli = require('broccoli'); | ||||
| var fse = require('fs-extra'); | ||||
| var makeBrowserTree = require('./trees/browser_tree'); | ||||
| var makeNodeTree = require('./trees/node_tree'); | ||||
| var makeDartTree = require('./trees/dart_tree'); | ||||
| var path = require('path'); | ||||
| var printSlowTrees = require('broccoli-slow-trees'); | ||||
| var Q = require('q'); | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * BroccoliBuilder facade for all of our build pipelines. | ||||
|  */ | ||||
| export class AngularBuilder { | ||||
|   private nodeBuilder: BroccoliBuilder; | ||||
|   private browserDevBuilder: BroccoliBuilder; | ||||
|   private browserProdBuilder: BroccoliBuilder; | ||||
|   private dartBuilder: BroccoliBuilder; | ||||
| 
 | ||||
| 
 | ||||
|   constructor(private outputPath: string) {} | ||||
| 
 | ||||
| 
 | ||||
|   public rebuildBrowserDevTree(): Promise<BuildResult> { | ||||
|     this.browserDevBuilder = this.browserDevBuilder || this.makeBrowserDevBuilder(); | ||||
|     return this.rebuild(this.browserDevBuilder); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   public rebuildBrowserProdTree(): Promise<BuildResult> { | ||||
|     this.browserProdBuilder = this.browserProdBuilder || this.makeBrowserProdBuilder(); | ||||
|     return this.rebuild(this.browserProdBuilder); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   public rebuildNodeTree(): Promise<BuildResult> { | ||||
|     this.nodeBuilder = this.nodeBuilder || this.makeNodeBuilder(); | ||||
|     return this.rebuild(this.nodeBuilder); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   public rebuildDartTree(): Promise<BuildResult> { | ||||
|     this.dartBuilder = this.dartBuilder || this.makeDartBuilder(); | ||||
|     return this.rebuild(this.dartBuilder); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   cleanup(): Promise<any> { | ||||
|     return Q.all([ | ||||
|       this.nodeBuilder && this.nodeBuilder.cleanup(), | ||||
|       this.browserDevBuilder && this.browserDevBuilder.cleanup(), | ||||
|       this.browserProdBuilder && this.browserProdBuilder.cleanup() | ||||
|     ]); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   private makeBrowserDevBuilder(): BroccoliBuilder { | ||||
|     let tree = makeBrowserTree({name: 'dev', typeAssertions: true}, | ||||
|                                path.join(this.outputPath, 'js', 'dev')); | ||||
|     return new broccoli.Builder(tree); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   private makeBrowserProdBuilder(): BroccoliBuilder { | ||||
|     let tree = makeBrowserTree({name: 'prod', typeAssertions: false}, | ||||
|                                path.join(this.outputPath, 'js', 'prod')); | ||||
|     return new broccoli.Builder(tree); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   private makeNodeBuilder(): BroccoliBuilder { | ||||
|     let tree = makeNodeTree(path.join(this.outputPath, 'js', 'cjs')); | ||||
|     return new broccoli.Builder(tree); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   private makeDartBuilder(): BroccoliBuilder { | ||||
|     let tree = makeDartTree(path.join(this.outputPath, 'dart')); | ||||
|     return new broccoli.Builder(tree); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   private rebuild(builder) { | ||||
|     return builder.build() | ||||
|         .then((result) => { printSlowTrees(result.graph); }) | ||||
|         .catch((err) => { | ||||
|           console.error(err.toString()); | ||||
|           // Should show file and line/col if present
 | ||||
|           if (err.file) { | ||||
|             console.error('File: ' + err.file); | ||||
|           } | ||||
|           if (err.stack) { | ||||
|             console.error(err.stack); | ||||
|           } | ||||
|           throw err; | ||||
|         }); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										2
									
								
								tools/broccoli/broccoli.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								tools/broccoli/broccoli.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -73,7 +73,7 @@ interface BroccoliBuilder { | ||||
|    * Cleans up the whole build tree by calling `.cleanup()` method on all trees that are part of the | ||||
|    * pipeline. | ||||
|    */ | ||||
|   cleanup(); | ||||
|   cleanup(): Promise<any>; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,89 +0,0 @@ | ||||
| var broccoli = require('broccoli'); | ||||
| var destCopy = require('./broccoli-dest-copy'); | ||||
| var fse = require('fs-extra'); | ||||
| var makeBrowserTree = require('./trees/browser_tree'); | ||||
| var makeNodeTree = require('./trees/node_tree'); | ||||
| var makeDartTree = require('./trees/dart_tree'); | ||||
| var path = require('path'); | ||||
| var printSlowTrees = require('broccoli-slow-trees'); | ||||
| 
 | ||||
| /** | ||||
|  * Helper for building with broccoli. | ||||
|  */ | ||||
| export class BroccoliBuilder { | ||||
|   private builder; | ||||
|   private broccoliExecuted: {[s: string]: boolean} = {}; | ||||
| 
 | ||||
|   // Named constructors
 | ||||
|   static forDevTree(): BroccoliBuilder { | ||||
|     return new BroccoliBuilder(makeBrowserTree({name: 'dev', typeAssertions: true}), | ||||
|                                path.join('js', 'dev')); | ||||
|   } | ||||
|   static forNodeTree(): BroccoliBuilder { | ||||
|     return new BroccoliBuilder(makeNodeTree(), path.join('js', 'cjs')); | ||||
|   } | ||||
|   static forProdTree(): BroccoliBuilder { | ||||
|     return new BroccoliBuilder(makeBrowserTree({name: 'prod', typeAssertions: false}), | ||||
|                                path.join('js', 'prod')); | ||||
|   } | ||||
|   static forDartTree(): BroccoliBuilder { return new BroccoliBuilder(makeDartTree(), 'dart'); } | ||||
| 
 | ||||
|   constructor(tree, private outputRoot: string) { | ||||
|     if (this.broccoliExecuted[outputRoot]) { | ||||
|       throw new Error('The broccoli task can be called only once for outputRoot ' + outputRoot); | ||||
|     } | ||||
|     this.broccoliExecuted[outputRoot] = true; | ||||
| 
 | ||||
|     var distPath = path.join('dist', outputRoot); | ||||
| 
 | ||||
|     // We do a clean build every time to avoid stale outputs.
 | ||||
|     // Broccoli's cache folders allow it to remain incremental without reading this dir.
 | ||||
|     fse.removeSync(distPath); | ||||
| 
 | ||||
|     tree = destCopy(tree, 'dist'); | ||||
| 
 | ||||
|     this.builder = new broccoli.Builder(tree); | ||||
|   } | ||||
| 
 | ||||
|   doBuild(): Promise<any> { | ||||
|     return this.builder.build() | ||||
|         .then(hash => | ||||
|               { | ||||
|                 console.log('=== Stats for %s (total: %ds) ===', this.outputRoot, | ||||
|                             Math.round(hash.totalTime / 1000000) / 1000); | ||||
|                 printSlowTrees(hash.graph); | ||||
|               }) | ||||
|         .catch(err => { | ||||
|           console.log(err.toString()); | ||||
|           // Should show file and line/col if present
 | ||||
|           if (err.file) { | ||||
|             console.error('File: ' + err.file); | ||||
|           } | ||||
|           if (err.stack) { | ||||
|             console.error(err.stack); | ||||
|           } | ||||
|           throw err; | ||||
|         }); | ||||
|   } | ||||
| 
 | ||||
|   buildOnce(): Promise<any> { | ||||
|     // es6-promise doesn't have finally()
 | ||||
|     return (<any>this.doBuild()) | ||||
|         .finally(() => | ||||
|                  { | ||||
|                    this.time('Build cleanup', () => this.builder.cleanup()); | ||||
|                    console.log('=== Done building %s ===', this.outputRoot); | ||||
|                  }) | ||||
|         .catch(err => { | ||||
|           console.error('\nBuild failed'); | ||||
|           process.exit(1); | ||||
|         }); | ||||
|   } | ||||
| 
 | ||||
|   time(label, work) { | ||||
|     var start = Date.now(); | ||||
|     work(); | ||||
|     var duration = Date.now() - start; | ||||
|     console.log("%s: %dms", label, duration); | ||||
|   } | ||||
| } | ||||
| @ -1,5 +1,5 @@ | ||||
| /// <reference path="../../typings/node/node.d.ts" />
 | ||||
| /// <reference path="../../typings/fs-extra/fs-extra.d.ts" />
 | ||||
| /// <reference path="../typings/node/node.d.ts" />
 | ||||
| /// <reference path="../typings/fs-extra/fs-extra.d.ts" />
 | ||||
| import Writer = require('broccoli-writer'); | ||||
| import fs = require('fs'); | ||||
| import fsx = require('fs-extra'); | ||||
| @ -1,5 +1,6 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var destCopy = require('../broccoli-dest-copy'); | ||||
| var Funnel = require('broccoli-funnel'); | ||||
| var flatten = require('broccoli-flatten'); | ||||
| var htmlReplace = require('../html-replace'); | ||||
| @ -10,10 +11,11 @@ var stew = require('broccoli-stew'); | ||||
| var ts2dart = require('../broccoli-ts2dart'); | ||||
| var traceurCompiler = require('../traceur'); | ||||
| 
 | ||||
| 
 | ||||
| var projectRootDir = path.normalize(path.join(__dirname, '..', '..', '..')); | ||||
| 
 | ||||
| 
 | ||||
| module.exports = function makeBrowserTree(options) { | ||||
| module.exports = function makeBrowserTree(options, destinationPath) { | ||||
|   var modulesTree = new Funnel( | ||||
|       'modules', | ||||
|       {include: ['**/**'], exclude: ['**/*.cjs', 'benchmarks/e2e_test/**'], destDir: '/'}); | ||||
| @ -113,8 +115,7 @@ module.exports = function makeBrowserTree(options) { | ||||
| 
 | ||||
|   es5Tree = mergeTrees([es5Tree, htmlTree]); | ||||
| 
 | ||||
|   return mergeTrees([ | ||||
|     stew.mv(es6Tree, 'js/' + options.name + '/es6'), | ||||
|     stew.mv(es5Tree, 'js/' + options.name + '/es5') | ||||
|   ]); | ||||
|   var mergedTree = mergeTrees([stew.mv(es6Tree, '/es6'), stew.mv(es5Tree, '/es5')]); | ||||
| 
 | ||||
|   return destCopy(mergedTree, destinationPath); | ||||
| }; | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| /// <reference path="../../typings/node/node.d.ts" />
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| import {MultiCopy} from './multi_copy'; | ||||
| import {MultiCopy} from './../multi_copy'; | ||||
| var destCopy = require('../broccoli-dest-copy'); | ||||
| var Funnel = require('broccoli-funnel'); | ||||
| var glob = require('glob'); | ||||
| var mergeTrees = require('broccoli-merge-trees'); | ||||
| @ -137,12 +138,11 @@ function getDocsTree() { | ||||
|   return mergeTrees([licenses, mdTree, docs]); | ||||
| } | ||||
| 
 | ||||
| module.exports = function makeDartTree() { | ||||
| module.exports = function makeDartTree(destinationPath) { | ||||
|   var sourceTree = mergeTrees([getSourceTree(), getHtmlSourcesTree()]); | ||||
|   sourceTree = fixDartFolderLayout(sourceTree); | ||||
| 
 | ||||
|   var mergedResult = mergeTrees([sourceTree, getTemplatedPubspecsTree(), getDocsTree()]); | ||||
|   var dartTree = mergeTrees([sourceTree, getTemplatedPubspecsTree(), getDocsTree()]); | ||||
| 
 | ||||
|   // Move the tree under the 'dart' folder.
 | ||||
|   return stew.mv(mergedResult, 'dart'); | ||||
|   return destCopy(dartTree, destinationPath); | ||||
| }; | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var destCopy = require('../broccoli-dest-copy'); | ||||
| var Funnel = require('broccoli-funnel'); | ||||
| var mergeTrees = require('broccoli-merge-trees'); | ||||
| var path = require('path'); | ||||
| @ -13,7 +14,7 @@ var TypescriptCompiler = require('../typescript'); | ||||
| var projectRootDir = path.normalize(path.join(__dirname, '..', '..', '..')); | ||||
| 
 | ||||
| 
 | ||||
| module.exports = function makeNodeTree() { | ||||
| module.exports = function makeNodeTree(destinationPath) { | ||||
|   // list of npm packages that this build will create
 | ||||
|   var outputPackages = ['angular2', 'benchpress', 'rtts_assert']; | ||||
| 
 | ||||
| @ -112,5 +113,5 @@ module.exports = function makeNodeTree() { | ||||
|   nodeTree = mergeTrees([nodeTree, typescriptTree], { overwrite: true }); | ||||
|   nodeTree = mergeTrees([nodeTree, docs, packageJsons]); | ||||
| 
 | ||||
|   return stew.mv(nodeTree, 'js/cjs'); | ||||
|   return destCopy(nodeTree, destinationPath); | ||||
| }; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user