Skip to content

Commit 65945b8

Browse files
committed
feat(tools): do not invoke tasks if not required
In dev executes tasks only when a specific file type has changed. Fix #1432.
1 parent 8c11045 commit 65945b8

11 files changed

+211
-77
lines changed

tools/tasks/assets_task.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Task } from './task';
2+
3+
export abstract class AssetsTask extends Task {
4+
shallRun(files: String[]) {
5+
return files.reduce((a, f) => {
6+
return a || (!f.endsWith('.css') && !f.endsWith('.sass') &&
7+
!f.endsWith('.scss') && !f.endsWith('.ts'));
8+
}, false);
9+
}
10+
}

tools/tasks/css_task.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Task } from './task';
2+
3+
export abstract class CssTask extends Task {
4+
5+
shallRun(files: String[]) {
6+
return files.some(f =>
7+
f.endsWith('.css') || f.endsWith('.sass') || f.endsWith('.scss'));
8+
}
9+
10+
}
11+

tools/tasks/seed/build.assets.dev.ts

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
import * as gulp from 'gulp';
22
import { join } from 'path';
33

4+
import { AssetsTask } from '../assets_task';
45
import Config from '../../config';
56

67
/**
78
* Executes the build process, copying the assets located in `src/client` over to the appropriate
89
* `dist/dev` directory.
910
*/
10-
export = () => {
11-
let paths: string[] = [
12-
join(Config.APP_SRC, '**'),
13-
'!' + join(Config.APP_SRC, '**', '*.ts'),
14-
'!' + join(Config.APP_SRC, '**', '*.scss'),
15-
'!' + join(Config.APP_SRC, '**', '*.sass')
16-
].concat(Config.TEMP_FILES.map((p) => { return '!' + p; }));
11+
export =
12+
class BuildAssetsTask extends AssetsTask {
13+
run() {
14+
let paths: string[] = [
15+
join(Config.APP_SRC, '**'),
16+
'!' + join(Config.APP_SRC, '**', '*.ts'),
17+
'!' + join(Config.APP_SRC, '**', '*.scss'),
18+
'!' + join(Config.APP_SRC, '**', '*.sass')
19+
].concat(Config.TEMP_FILES.map((p) => { return '!' + p; }));
20+
21+
return gulp.src(paths)
22+
.pipe(gulp.dest(Config.APP_DEST));
23+
}
24+
};
1725

18-
return gulp.src(paths)
19-
.pipe(gulp.dest(Config.APP_DEST));
20-
};

tools/tasks/seed/build.bundle.rxjs.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

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

7-
export = (done:any) => {
7+
export = (done: any) => {
88
const options = {
99
normalize: true,
1010
runtime: false,

tools/tasks/seed/build.html_css.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as util from 'gulp-util';
77
import { join } from 'path';
88

99
import Config from '../../config';
10+
import { CssTask } from '../css_task';
1011

1112
const plugins = <any>gulpLoadPlugins();
1213
const cleanCss = require('gulp-clean-css');
@@ -147,4 +148,14 @@ function processExternalCss() {
147148
/**
148149
* Executes the build process, processing the HTML and CSS files.
149150
*/
150-
export = () => merge(processComponentStylesheets(), prepareTemplates(), processExternalStylesheets());
151+
export =
152+
class BuildHtmlCss extends CssTask {
153+
154+
shallRun(files: String[]) {
155+
return super.shallRun(files) || files.some(f => f.endsWith('.html'));
156+
}
157+
158+
run() {
159+
return merge(processComponentStylesheets(), prepareTemplates(), processExternalStylesheets());
160+
}
161+
};

tools/tasks/seed/build.js.dev.ts

+56-51
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { join/*, sep, relative*/ } from 'path';
66

77
import Config from '../../config';
88
import { makeTsProject, templateLocals } from '../../utils';
9+
import { TypeScriptTask } from '../typescript_task';
910

1011
const plugins = <any>gulpLoadPlugins();
1112

@@ -17,60 +18,64 @@ let typedBuildCounter = Config.TYPED_COMPILE_INTERVAL; // Always start with the
1718
* Executes the build process, transpiling the TypeScript files (except the spec and e2e-spec files) for the development
1819
* environment.
1920
*/
20-
export = () => {
21-
let tsProject: any;
22-
let typings = gulp.src([
23-
Config.TOOLS_DIR + '/manual_typings/**/*.d.ts'
24-
]);
25-
let src = [
26-
join(Config.APP_SRC, '**/*.ts'),
27-
'!' + join(Config.APP_SRC, '**/*.spec.ts'),
28-
'!' + join(Config.APP_SRC, '**/*.e2e-spec.ts'),
29-
'!' + join(Config.TMP_DIR, `**/${Config.NG_FACTORY_FILE}.ts`)
30-
];
21+
export =
22+
class BuildJsDev extends TypeScriptTask {
23+
run() {
24+
let tsProject: any;
25+
let typings = gulp.src([
26+
Config.TOOLS_DIR + '/manual_typings/**/*.d.ts'
27+
]);
28+
let src = [
29+
join(Config.APP_SRC, '**/*.ts'),
30+
'!' + join(Config.APP_SRC, '**/*.spec.ts'),
31+
'!' + join(Config.APP_SRC, '**/*.e2e-spec.ts'),
32+
'!' + join(Config.TMP_DIR, `**/${Config.NG_FACTORY_FILE}.ts`)
33+
];
3134

32-
let projectFiles = gulp.src(src);
33-
let result: any;
34-
let isFullCompile = true;
35+
let projectFiles = gulp.src(src);
36+
let result: any;
37+
let isFullCompile = true;
3538

36-
// Only do a typed build every X builds, otherwise do a typeless build to speed things up
37-
if (typedBuildCounter < Config.TYPED_COMPILE_INTERVAL) {
38-
isFullCompile = false;
39-
tsProject = makeTsProject({isolatedModules: true});
40-
projectFiles = projectFiles.pipe(plugins.cached());
41-
util.log('Performing typeless TypeScript compile.');
42-
} else {
43-
tsProject = makeTsProject();
44-
projectFiles = merge(typings, projectFiles);
45-
}
39+
// Only do a typed build every X builds, otherwise do a typeless build to speed things up
40+
if (typedBuildCounter < Config.TYPED_COMPILE_INTERVAL) {
41+
isFullCompile = false;
42+
tsProject = makeTsProject({isolatedModules: true});
43+
projectFiles = projectFiles.pipe(plugins.cached());
44+
util.log('Performing typeless TypeScript compile.');
45+
} else {
46+
tsProject = makeTsProject();
47+
projectFiles = merge(typings, projectFiles);
48+
}
4649

47-
result = projectFiles
48-
.pipe(plugins.plumber())
49-
.pipe(plugins.sourcemaps.init())
50-
.pipe(tsProject())
51-
.on('error', () => {
52-
typedBuildCounter = Config.TYPED_COMPILE_INTERVAL;
53-
});
50+
result = projectFiles
51+
.pipe(plugins.plumber())
52+
.pipe(plugins.sourcemaps.init())
53+
.pipe(tsProject())
54+
.on('error', () => {
55+
typedBuildCounter = Config.TYPED_COMPILE_INTERVAL;
56+
});
5457

55-
if (isFullCompile) {
56-
typedBuildCounter = 0;
57-
} else {
58-
typedBuildCounter++;
59-
}
58+
if (isFullCompile) {
59+
typedBuildCounter = 0;
60+
} else {
61+
typedBuildCounter++;
62+
}
6063

61-
return result.js
62-
.pipe(plugins.sourcemaps.write())
63-
// Use for debugging with Webstorm/IntelliJ
64-
// https://github.com/mgechev/angular2-seed/issues/1220
65-
// .pipe(plugins.sourcemaps.write('.', {
66-
// includeContent: false,
67-
// sourceRoot: (file: any) =>
68-
// relative(file.path, PROJECT_ROOT + '/' + APP_SRC).replace(sep, '/') + '/' + APP_SRC
69-
// }))
70-
.pipe(plugins.template(Object.assign(
71-
templateLocals(), {
72-
SYSTEM_CONFIG_DEV: jsonSystemConfig
64+
return result.js
65+
.pipe(plugins.sourcemaps.write())
66+
// Use for debugging with Webstorm/IntelliJ
67+
// https://github.com/mgechev/angular2-seed/issues/1220
68+
// .pipe(plugins.sourcemaps.write('.', {
69+
// includeContent: false,
70+
// sourceRoot: (file: any) =>
71+
// relative(file.path, PROJECT_ROOT + '/' + APP_SRC).replace(sep, '/') + '/' + APP_SRC
72+
// }))
73+
.pipe(plugins.template(Object.assign(
74+
templateLocals(), {
75+
SYSTEM_CONFIG_DEV: jsonSystemConfig
76+
}
77+
)))
78+
.pipe(gulp.dest(Config.APP_DEST));
7379
}
74-
)))
75-
.pipe(gulp.dest(Config.APP_DEST));
76-
};
80+
};
81+

tools/tasks/task.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Base class for all tasks.
3+
*/
4+
export abstract class Task {
5+
/**
6+
* Override this task if you want to implement some custom
7+
* task activation mechanism. By default each task will be always executed.
8+
*
9+
* @param {string[]} files A list of files changed since the previous watch.
10+
*/
11+
shallRun(files: string[]): boolean {
12+
return true;
13+
}
14+
15+
/**
16+
* Implements your task behavior.
17+
*
18+
* @param {any} done A function which should be activated once your task completes.
19+
* @return {ReadWriteStream | Promise<any> | void} This method can either return a promise
20+
* which should be resolved once your task execution completes, a stream
21+
* which should throw an end event once your task execution completes
22+
* or nothing in case you will manually invoke the `done` method.
23+
*/
24+
abstract run(done?: any): any | Promise<any> | void;
25+
}

tools/tasks/typescript_task.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Task } from './task';
2+
3+
export abstract class TypeScriptTask extends Task {
4+
shallRun(files: String[]) {
5+
return files.reduce((a, f) => {
6+
return a || f.endsWith('.ts');
7+
}, false);
8+
}
9+
}

tools/utils/seed/code_change_tools.ts

+28
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,34 @@ import * as browserSync from 'browser-sync';
33

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

6+
class ChangeFileManager {
7+
private _files: string[] = [];
8+
private _pristine = true;
9+
10+
get lastChangedFiles() {
11+
return this._files.slice();
12+
}
13+
14+
get pristine() {
15+
return this._pristine;
16+
}
17+
18+
addFile(file: string) {
19+
this._pristine = false;
20+
this._files.push(file);
21+
}
22+
23+
addFiles(files: string[]) {
24+
files.forEach(f => this.addFile(f));
25+
}
26+
27+
clear() {
28+
this._files = [];
29+
}
30+
}
31+
32+
export let changeFileManager = new ChangeFileManager();
33+
634
/**
735
* Initialises BrowserSync with the configuration defined in seed.config.ts (or if overriden: project.config.ts).
836
*/

tools/utils/seed/tasks_tools.ts

+35-11
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import * as isstream from 'isstream';
55
import { join } from 'path';
66
import * as tildify from 'tildify';
77

8+
import { changeFileManager } from './code_change_tools';
9+
import { Task } from '../../tasks/task';
10+
811
/**
912
* Loads the tasks within the given path.
1013
* @param {string} path - The path to load the tasks from.
@@ -14,6 +17,33 @@ export function loadTasks(path: string): void {
1417
readDir(path, taskname => registerTask(taskname, path));
1518
}
1619

20+
function normalizeTask(task: any, taskName: string) {
21+
if (task instanceof Task) {
22+
return task;
23+
}
24+
if (task.prototype && task.prototype instanceof Task) {
25+
return new task();
26+
}
27+
if (typeof task === 'function') {
28+
return new class AnonTask extends Task {
29+
run(done: any) {
30+
if (task.length > 0) {
31+
return task(done);
32+
}
33+
34+
const taskReturnedValue = task();
35+
if (isstream(taskReturnedValue)) {
36+
return taskReturnedValue;
37+
}
38+
39+
done();
40+
}
41+
};
42+
}
43+
throw new Error(taskName + ' should be instance of the class ' +
44+
'Task, a function or a class which extends Task.');
45+
}
46+
1747
/**
1848
* Registers the task by the given taskname and path.
1949
* @param {string} taskname - The name of the task.
@@ -24,19 +54,13 @@ function registerTask(taskname: string, path: string): void {
2454
util.log('Registering task', util.colors.yellow(tildify(TASK)));
2555

2656
gulp.task(taskname, (done: any) => {
27-
const task = require(TASK);
28-
if (task.length > 0) {
29-
return task(done);
30-
}
57+
const task = normalizeTask(require(TASK), TASK);
3158

32-
const taskReturnedValue = task();
33-
if (isstream(taskReturnedValue)) {
34-
return taskReturnedValue;
59+
if (changeFileManager.pristine || task.shallRun(changeFileManager.lastChangedFiles)) {
60+
return task.run(done);
61+
} else {
62+
done();
3563
}
36-
37-
// TODO: add promise handling if needed at some point.
38-
39-
done();
4064
});
4165
}
4266

tools/utils/seed/watch.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { join } from 'path';
33
import * as runSequence from 'run-sequence';
44

55
import Config from '../../config';
6+
import { changeFileManager } from './code_change_tools';
67
import { notifyLiveReload } from '../../utils';
78

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

20-
plugins.watch(paths, (e:any) =>
21-
runSequence(taskname, () => notifyLiveReload(e))
22-
);
21+
plugins.watch(paths, (e: any) => {
22+
changeFileManager.addFile(e.path);
23+
24+
runSequence(taskname, () => {
25+
changeFileManager.clear();
26+
notifyLiveReload(e);
27+
});
28+
});
2329
};
2430
}

0 commit comments

Comments
 (0)