Skip to content

feat(tools): do not invoke tasks if not necessary #1443

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions tools/tasks/assets_task.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Task } from './task';

export abstract class AssetsTask extends Task {
shallRun(files: String[]) {
return files.reduce((a, f) => {
return a || (!f.endsWith('.css') && !f.endsWith('.sass') &&
!f.endsWith('.scss') && !f.endsWith('.ts'));
}, false);
}
}
10 changes: 10 additions & 0 deletions tools/tasks/css_task.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Task } from './task';

export abstract class CssTask extends Task {

shallRun(files: String[]) {
return files.some(f =>
f.endsWith('.css') || f.endsWith('.sass') || f.endsWith('.scss'));
}

}
25 changes: 15 additions & 10 deletions tools/tasks/seed/build.assets.dev.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import * as gulp from 'gulp';
import { join } from 'path';

import { AssetsTask } from '../assets_task';
import Config from '../../config';

/**
* Executes the build process, copying the assets located in `src/client` over to the appropriate
* `dist/dev` directory.
*/
export = () => {
let paths: string[] = [
join(Config.APP_SRC, '**'),
'!' + join(Config.APP_SRC, '**', '*.ts'),
'!' + join(Config.APP_SRC, '**', '*.scss'),
'!' + join(Config.APP_SRC, '**', '*.sass')
].concat(Config.TEMP_FILES.map((p) => { return '!' + p; }));
export =
class BuildAssetsTask extends AssetsTask {
run() {
let paths: string[] = [
join(Config.APP_SRC, '**'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation problem

'!' + join(Config.APP_SRC, '**', '*.ts'),
'!' + join(Config.APP_SRC, '**', '*.scss'),
'!' + join(Config.APP_SRC, '**', '*.sass')
].concat(Config.TEMP_FILES.map((p) => { return '!' + p; }));

return gulp.src(paths)
.pipe(gulp.dest(Config.APP_DEST));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation problem

}
};

return gulp.src(paths)
.pipe(gulp.dest(Config.APP_DEST));
};
2 changes: 1 addition & 1 deletion tools/tasks/seed/build.bundle.rxjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

const Builder = require('systemjs-builder');

export = (done:any) => {
export = (done: any) => {
const options = {
normalize: true,
runtime: false,
Expand Down
13 changes: 12 additions & 1 deletion tools/tasks/seed/build.html_css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as util from 'gulp-util';
import { join } from 'path';

import Config from '../../config';
import { CssTask } from '../css_task';

const plugins = <any>gulpLoadPlugins();
const cleanCss = require('gulp-clean-css');
Expand Down Expand Up @@ -147,4 +148,14 @@ function processExternalCss() {
/**
* Executes the build process, processing the HTML and CSS files.
*/
export = () => merge(processComponentStylesheets(), prepareTemplates(), processExternalStylesheets());
export =
class BuildHtmlCss extends CssTask {

shallRun(files: String[]) {
return super.shallRun(files) || files.some(f => f.endsWith('.html'));
}

run() {
return merge(processComponentStylesheets(), prepareTemplates(), processExternalStylesheets());
}
};
108 changes: 57 additions & 51 deletions tools/tasks/seed/build.js.dev.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import * as gulp from 'gulp';
import * as gulpLoadPlugins from 'gulp-load-plugins';
import * as merge from 'merge-stream';
Expand All @@ -6,6 +7,7 @@ import { join/*, sep, relative*/ } from 'path';

import Config from '../../config';
import { makeTsProject, templateLocals } from '../../utils';
import { TypeScriptTask } from '../typescript_task';

const plugins = <any>gulpLoadPlugins();

Expand All @@ -17,60 +19,64 @@ let typedBuildCounter = Config.TYPED_COMPILE_INTERVAL; // Always start with the
* Executes the build process, transpiling the TypeScript files (except the spec and e2e-spec files) for the development
* environment.
*/
export = () => {
let tsProject: any;
let typings = gulp.src([
Config.TOOLS_DIR + '/manual_typings/**/*.d.ts'
]);
let src = [
join(Config.APP_SRC, '**/*.ts'),
'!' + join(Config.APP_SRC, '**/*.spec.ts'),
'!' + join(Config.APP_SRC, '**/*.e2e-spec.ts'),
'!' + join(Config.APP_SRC, `**/${Config.NG_FACTORY_FILE}.ts`)
];
export =
class BuildJsDev extends TypeScriptTask {
run() {
let tsProject: any;
let typings = gulp.src([
Config.TOOLS_DIR + '/manual_typings/**/*.d.ts'
]);
let src = [
join(Config.APP_SRC, '**/*.ts'),
'!' + join(Config.APP_SRC, '**/*.spec.ts'),
'!' + join(Config.APP_SRC, '**/*.e2e-spec.ts'),
'!' + join(Config.APP_SRC, `**/${Config.NG_FACTORY_FILE}.ts`)
];

let projectFiles = gulp.src(src);
let result: any;
let isFullCompile = true;
let projectFiles = gulp.src(src);
let result: any;
let isFullCompile = true;

// Only do a typed build every X builds, otherwise do a typeless build to speed things up
if (typedBuildCounter < Config.TYPED_COMPILE_INTERVAL) {
isFullCompile = false;
tsProject = makeTsProject({isolatedModules: true});
projectFiles = projectFiles.pipe(plugins.cached());
util.log('Performing typeless TypeScript compile.');
} else {
tsProject = makeTsProject();
projectFiles = merge(typings, projectFiles);
}
// Only do a typed build every X builds, otherwise do a typeless build to speed things up
if (typedBuildCounter < Config.TYPED_COMPILE_INTERVAL) {
isFullCompile = false;
tsProject = makeTsProject({isolatedModules: true});
projectFiles = projectFiles.pipe(plugins.cached());
util.log('Performing typeless TypeScript compile.');
} else {
tsProject = makeTsProject();
projectFiles = merge(typings, projectFiles);
}

result = projectFiles
.pipe(plugins.plumber())
.pipe(plugins.sourcemaps.init())
.pipe(tsProject())
.on('error', () => {
typedBuildCounter = Config.TYPED_COMPILE_INTERVAL;
});
result = projectFiles
.pipe(plugins.plumber())
.pipe(plugins.sourcemaps.init())
.pipe(tsProject())
.on('error', () => {
typedBuildCounter = Config.TYPED_COMPILE_INTERVAL;
});

if (isFullCompile) {
typedBuildCounter = 0;
} else {
typedBuildCounter++;
}
if (isFullCompile) {
typedBuildCounter = 0;
} else {
typedBuildCounter++;
}

return result.js
.pipe(plugins.sourcemaps.write())
// Use for debugging with Webstorm/IntelliJ
// https://github.com/mgechev/angular2-seed/issues/1220
// .pipe(plugins.sourcemaps.write('.', {
// includeContent: false,
// sourceRoot: (file: any) =>
// relative(file.path, PROJECT_ROOT + '/' + APP_SRC).replace(sep, '/') + '/' + APP_SRC
// }))
.pipe(plugins.template(Object.assign(
templateLocals(), {
SYSTEM_CONFIG_DEV: jsonSystemConfig
return result.js
.pipe(plugins.sourcemaps.write())
// Use for debugging with Webstorm/IntelliJ
// https://github.com/mgechev/angular2-seed/issues/1220
// .pipe(plugins.sourcemaps.write('.', {
// includeContent: false,
// sourceRoot: (file: any) =>
// relative(file.path, PROJECT_ROOT + '/' + APP_SRC).replace(sep, '/') + '/' + APP_SRC
// }))
.pipe(plugins.template(Object.assign(
templateLocals(), {
SYSTEM_CONFIG_DEV: jsonSystemConfig
}
)))
.pipe(gulp.dest(Config.APP_DEST));
}
)))
.pipe(gulp.dest(Config.APP_DEST));
};
};

25 changes: 25 additions & 0 deletions tools/tasks/task.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Base class for all tasks.
*/
export abstract class Task {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could provide another abstract class which uses a regular expression to test file endings. This way a subclass would only need to pass an array of file endings to this abstract class instead of overridingprecondition (shallRun respectively, see below)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I considered this idea here. It might be a good idea but I'd prefer to keep the API minimalistic for now. Maybe in future will turn out that the most important precondition is not related to file type.

/**
* Override this task if you want to implement some custom
* task activation mechanism. By default each task will be always executed.
*
* @param {string[]} files A list of files changed since the previous watch.
*/
shallRun(files: string[]): boolean {
return true;
}

/**
* Implements your task behavior.
*
* @param {any} done A function which should be activated once your task completes.
* @return {ReadWriteStream | Promise<any> | void} This method can either return a promise
* which should be resolved once your task execution completes, a stream
* which should throw an end event once your task execution completes
* or nothing in case you will manually invoke the `done` method.
*/
abstract run(done?: any): any | Promise<any> | void;
}
9 changes: 9 additions & 0 deletions tools/tasks/typescript_task.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Task } from './task';

export abstract class TypeScriptTask extends Task {
shallRun(files: String[]) {
return files.reduce((a, f) => {
return a || f.endsWith('.ts');
}, false);
}
}
28 changes: 28 additions & 0 deletions tools/utils/seed/code_change_tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,34 @@ import * as browserSync from 'browser-sync';

import Config from '../../config';

class ChangeFileManager {
private _files: string[] = [];
private _pristine = true;

get lastChangedFiles() {
return this._files.slice();
}

get pristine() {
return this._pristine;
}

addFile(file: string) {
this._pristine = false;
this._files.push(file);
}

addFiles(files: string[]) {
files.forEach(f => this.addFile(f));
}

clear() {
this._files = [];
}
}

export let changeFileManager = new ChangeFileManager();

/**
* Initialises BrowserSync with the configuration defined in seed.config.ts (or if overriden: project.config.ts).
*/
Expand Down
46 changes: 35 additions & 11 deletions tools/utils/seed/tasks_tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import * as isstream from 'isstream';
import { join } from 'path';
import * as tildify from 'tildify';

import { changeFileManager } from './code_change_tools';
import { Task } from '../../tasks/task';

/**
* Loads the tasks within the given path.
* @param {string} path - The path to load the tasks from.
Expand All @@ -14,6 +17,33 @@ export function loadTasks(path: string): void {
readDir(path, taskname => registerTask(taskname, path));
}

function normalizeTask(task: any, taskName: string) {
if (task instanceof Task) {
return task;
}
if (task.prototype && task.prototype instanceof Task) {
return new task();
}
if (typeof task === 'function') {
return new class AnonTask extends Task {
run(done: any) {
if (task.length > 0) {
Copy link
Contributor

@robstoll robstoll Oct 9, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation for the run method seems to be wrong starting from here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm... here it looks good, not sure if it is a bug in the review view of github or if it is shown nicely here (the same for the other hints about indentation)

return task(done);
}

const taskReturnedValue = task();
if (isstream(taskReturnedValue)) {
return taskReturnedValue;
}

done();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ending here (indentation problem)

}
};
}
throw new Error(taskName + ' should be instance of the class ' +
'Task, a function or a class which extends Task.');
}

/**
* Registers the task by the given taskname and path.
* @param {string} taskname - The name of the task.
Expand All @@ -24,19 +54,13 @@ function registerTask(taskname: string, path: string): void {
util.log('Registering task', util.colors.yellow(tildify(TASK)));

gulp.task(taskname, (done: any) => {
const task = require(TASK);
if (task.length > 0) {
return task(done);
}
const task = normalizeTask(require(TASK), TASK);

const taskReturnedValue = task();
if (isstream(taskReturnedValue)) {
return taskReturnedValue;
if (changeFileManager.pristine || task.shallRun(changeFileManager.lastChangedFiles)) {
return task.run(done);
} else {
done();
}

// TODO: add promise handling if needed at some point.

done();
});
}

Expand Down
12 changes: 9 additions & 3 deletions tools/utils/seed/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { join } from 'path';
import * as runSequence from 'run-sequence';

import Config from '../../config';
import { changeFileManager } from './code_change_tools';
import { notifyLiveReload } from '../../utils';

const plugins = <any>gulpLoadPlugins();
Expand All @@ -17,8 +18,13 @@ export function watch(taskname: string) {
join(Config.APP_SRC,'**')
].concat(Config.TEMP_FILES.map((p) => { return '!'+p; }));

plugins.watch(paths, (e:any) =>
runSequence(taskname, () => notifyLiveReload(e))
);
plugins.watch(paths, (e: any) => {
changeFileManager.addFile(e.path);

runSequence(taskname, () => {
changeFileManager.clear();
notifyLiveReload(e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation problem

});
});
};
}