Since editors and IDEs do typechecking and show errors in place, often there is no benefit to running type checking in our test pipeline. This PR allows you to disable type checking: gulp test.unit.js --noTypeChecks This commit also makes es6 generation optional. fix(build): removes unnecessary circular dependencies Closes #5299
163 lines
5.0 KiB
TypeScript
163 lines
5.0 KiB
TypeScript
var broccoli = require('broccoli');
|
|
var fs = require('fs');
|
|
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');
|
|
|
|
type ProjectMap = {
|
|
[key: string]: boolean
|
|
};
|
|
|
|
type Options = {
|
|
projects: ProjectMap;
|
|
noTypeChecks: boolean;
|
|
generateEs6: boolean;
|
|
}
|
|
;
|
|
|
|
/**
|
|
* BroccoliBuilder facade for all of our build pipelines.
|
|
*/
|
|
export class AngularBuilder {
|
|
private nodeBuilder: BroccoliBuilder;
|
|
private browserDevBuilder: BroccoliBuilder;
|
|
private browserProdBuilder: BroccoliBuilder;
|
|
private dartBuilder: BroccoliBuilder;
|
|
private outputPath: string;
|
|
private firstResult: BuildResult;
|
|
|
|
constructor(public options: AngularBuilderOptions) { this.outputPath = options.outputPath; }
|
|
|
|
|
|
public rebuildBrowserDevTree(opts: Options): Promise<BuildResult> {
|
|
this.browserDevBuilder = this.browserDevBuilder || this.makeBrowserDevBuilder(opts);
|
|
return this.rebuild(this.browserDevBuilder, 'js.dev');
|
|
}
|
|
|
|
|
|
public rebuildBrowserProdTree(opts: Options): Promise<BuildResult> {
|
|
this.browserProdBuilder = this.browserProdBuilder || this.makeBrowserProdBuilder(opts);
|
|
return this.rebuild(this.browserProdBuilder, 'js.prod');
|
|
}
|
|
|
|
|
|
public rebuildNodeTree(opts: Options): Promise<BuildResult> {
|
|
this.nodeBuilder = this.nodeBuilder || this.makeNodeBuilder(opts.projects);
|
|
return this.rebuild(this.nodeBuilder, 'js.cjs');
|
|
}
|
|
|
|
|
|
public rebuildDartTree(projects: ProjectMap): Promise<BuildResult> {
|
|
this.dartBuilder = this.dartBuilder || this.makeDartBuilder(projects);
|
|
return this.rebuild(this.dartBuilder, 'dart');
|
|
}
|
|
|
|
|
|
cleanup(): Promise<any> {
|
|
return Q.all([
|
|
this.nodeBuilder && this.nodeBuilder.cleanup(),
|
|
this.browserDevBuilder && this.browserDevBuilder.cleanup(),
|
|
this.browserProdBuilder && this.browserProdBuilder.cleanup()
|
|
]);
|
|
}
|
|
|
|
|
|
private makeBrowserDevBuilder(opts: Options): BroccoliBuilder {
|
|
let tree = makeBrowserTree(
|
|
{
|
|
name: 'dev',
|
|
typeAssertions: true,
|
|
projects: opts.projects,
|
|
noTypeChecks: opts.noTypeChecks,
|
|
generateEs6: opts.generateEs6
|
|
},
|
|
path.join(this.outputPath, 'js', 'dev'));
|
|
return new broccoli.Builder(tree);
|
|
}
|
|
|
|
|
|
private makeBrowserProdBuilder(opts: Options): BroccoliBuilder {
|
|
let tree = makeBrowserTree(
|
|
{
|
|
name: 'prod',
|
|
typeAssertions: false,
|
|
projects: opts.projects,
|
|
noTypeChecks: opts.noTypeChecks,
|
|
generateEs6: opts.generateEs6
|
|
},
|
|
path.join(this.outputPath, 'js', 'prod'));
|
|
return new broccoli.Builder(tree);
|
|
}
|
|
|
|
|
|
private makeNodeBuilder(projects: ProjectMap): BroccoliBuilder {
|
|
let tree = makeNodeTree(projects, path.join(this.outputPath, 'js', 'cjs'));
|
|
return new broccoli.Builder(tree);
|
|
}
|
|
|
|
|
|
private makeDartBuilder(projects: ProjectMap): BroccoliBuilder {
|
|
let options = {
|
|
outputPath: path.join(this.outputPath, 'dart'),
|
|
dartSDK: this.options.dartSDK,
|
|
logs: this.options.logs,
|
|
projects: projects
|
|
};
|
|
let tree = makeDartTree(options);
|
|
return new broccoli.Builder(tree);
|
|
}
|
|
|
|
|
|
private rebuild(builder, name) {
|
|
return builder.build().then(
|
|
(result) => {
|
|
if (!this.firstResult) {
|
|
this.firstResult = result;
|
|
}
|
|
|
|
printSlowTrees(result.graph);
|
|
writeBuildLog(result, name);
|
|
},
|
|
(error) => {
|
|
// the build tree is the same during rebuilds, only leaf properties of the nodes change
|
|
// so let's traverse it and get updated values for input/cache/output paths
|
|
if (this.firstResult) {
|
|
writeBuildLog(this.firstResult, name);
|
|
}
|
|
throw error;
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
function writeBuildLog(result: BuildResult, name: string) {
|
|
let logPath = `tmp/build.${name}.log`;
|
|
let prevLogPath = logPath + '.previous';
|
|
let formattedLogContent = JSON.stringify(broccoliNodeToBuildNode(result.graph), null, 2);
|
|
|
|
if (fs.existsSync(prevLogPath)) fs.unlinkSync(prevLogPath);
|
|
if (fs.existsSync(logPath)) fs.renameSync(logPath, prevLogPath);
|
|
fs.writeFileSync(logPath, formattedLogContent, {encoding: 'utf-8'});
|
|
}
|
|
|
|
|
|
function broccoliNodeToBuildNode(broccoliNode) {
|
|
let tree = broccoliNode.tree.newStyleTree || broccoliNode.tree;
|
|
|
|
return new BuildNode(tree.description || tree.constructor.name,
|
|
tree.inputPath ? [tree.inputPath] : tree.inputPaths, tree.cachePath,
|
|
tree.outputPath, broccoliNode.selfTime / (1000 * 1000 * 1000),
|
|
broccoliNode.totalTime / (1000 * 1000 * 1000),
|
|
broccoliNode.subtrees.map(broccoliNodeToBuildNode));
|
|
}
|
|
|
|
|
|
class BuildNode {
|
|
constructor(public pluginName: string, public inputPaths: string[], public cachePath: string,
|
|
public outputPath: string, public selfTime: number, public totalTime: number,
|
|
public inputNodes: BroccoliNode[]) {}
|
|
}
|