Skip to content

Commit 2fd3343

Browse files
committed
Initial seed of build tools.
0 parents  commit 2fd3343

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+4343
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
.DS_Store
3+
npm*.log

.npmignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
src
2+
node_modules
3+
.gitignore
4+
.gitattributes
5+
.editorconfig
6+
gulpfile.js

README.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# MS core build tools
2+
3+
Common Gulp tasks to support building web app modules.
4+
5+
# Available tasks
6+
7+
All tasks are executed with gulp using the standard gulp syntax:
8+
9+
```bash
10+
gulp <taskname>
11+
```
12+
13+
Tasks include:
14+
15+
* **build** - Builds the inputs, drops to the output folder.
16+
* **build-watch** - Watches files and auto builds on changes.
17+
* **test** - Builds, and then runs tests.
18+
* **test-watch** - Watches all files and auto builds/runs tests on changes.
19+
* **bundle** - TBD
20+
* **serve** - Spins up a localhost server that lets you browse static pages.
21+
* **nuke** - Deletes build output.
22+
23+
For quick app development, use `gulp serve`. This will spin up the express server and host the content.
24+
25+
For quick library testing flows, use `gulp test-watch`.
26+
27+
# Using the build
28+
29+
Your gulpfile simply needs to initialize the core tasks:
30+
31+
```javascript
32+
'use strict';
33+
34+
let build = require('ms-core-build');
35+
36+
build.initializeTasks(
37+
require('gulp'), // the gulp instance to use for building
38+
{ ... } // optional options
39+
);
40+
```
41+
42+
43+
# Build options
44+
45+
TBD
46+
47+
48+
# Build input
49+
50+
Your repo source should live under the 'src' directory. The default build will support the following formats:
51+
52+
```text
53+
/src
54+
**/*.ts - Typescript source files
55+
**/*.test.ts - Typescript test files, which should live next to sources.
56+
**/*.less - Less css files that get converted into AMD modules that you can require as './filename.css'
57+
**/*.html - Static HTML files that get minified
58+
**/*.png - PNGs that get minified
59+
**/*.jpg - JPEGs that get minified
60+
```
61+
62+
63+
# Build output
64+
65+
Building the source will drop under the 'lib' folder, preserving the directory structure from the src folder:
66+
67+
```text
68+
/lib
69+
**/* - All unbundled js/static resources will be dropped into lib.
70+
**/*.d.ts - All typescript definitions will be dropped as well.
71+
```
72+
73+
74+
# Adding custom build tasks to the task dependency tree
75+
76+
In cases where the general build tools don't cover every scenario you have, you can use helpers to inject custom
77+
build steps into the common build task dependencies.
78+
79+
```javascript
80+
let build = require('ms-core-build');
81+
82+
// Create a custom gulp task as you normally would.
83+
gulp.task('build-custom-stuff', () => { ... });
84+
85+
// Register the task to execute before "build" starts, if build things depend on this step.
86+
build.doBefore('build', 'build-custom-stuff');
87+
88+
// Or, register it to execute while "build" is executing, if nothing depends on this step.
89+
build.doDuring('build', 'build-custom-stuff');
90+
91+
// Or, register it to execute after "build" is complete if this step depends on build to be complete.
92+
build.doAfter('build', 'build-custom-stuff');
93+
94+
// After dependencies are registered, initialize core tasks. They will make sure all of the instructions
95+
// you've provided will be merged correctly into the gulp task dependencies.
96+
build.initializeTasks(
97+
_dirname,
98+
require('gulp')
99+
);
100+
```
101+
102+
103+
104+
105+
106+
107+

gulpfile.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
3+
let build = require('./lib/index');
4+
5+
// Use the build tools to build the build tools.
6+
build.initializeTasks(
7+
require('gulp'),
8+
{
9+
build: {
10+
paths: {
11+
lessMatch: null,
12+
staticsMatch: null,
13+
htmlMatch: null
14+
},
15+
isLintingEnabled: true
16+
}
17+
});
18+

jsconfig.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES6",
4+
"module": "commonjs"
5+
}
6+
}

karma.conf.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
'use strict';
2+
3+
// Karma configuration
4+
// Generated on Thu Oct 08 2015 18:13:05 GMT-0700 (PDT)
5+
6+
let build = require('./lib/index');
7+
let testConfig = build.config.test;
8+
let path = require('path');
9+
let bindPolyfillPath = require.resolve('phantomjs-polyfill/bind-polyfill.js');
10+
11+
module.exports = function(config) {
12+
13+
config.set({
14+
15+
// base path that will be used to resolve all patterns (eg. files, exclude)
16+
basePath: build.rootDir,
17+
18+
19+
// frameworks to use
20+
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
21+
frameworks: ['mocha', 'common_js'],
22+
23+
24+
// list of files / patterns to load in the browser
25+
files: [ bindPolyfillPath ].concat(testConfig.paths.include),
26+
27+
28+
// list of files to exclude
29+
exclude: testConfig.paths.exclude,
30+
31+
32+
// preprocess matching files before serving them to the browser
33+
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
34+
preprocessors: {
35+
'lib/**/!(*.test).js': ['coverage', 'common_js'],
36+
'**/*.test.js': ['common_js']
37+
},
38+
39+
common_js: {
40+
transforms: {
41+
},
42+
// Array of globs to auto require when the tests run. You can use
43+
// this to control the entry point for your tests.
44+
autoRequire: [
45+
'**/*.test.js'
46+
]
47+
},
48+
49+
// test results reporter to use
50+
// possible values: 'dots', 'progress'
51+
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
52+
reporters: ['mocha-clean', 'coverage'],
53+
54+
55+
// web server port
56+
port: 9876,
57+
58+
59+
// enable / disable colors in the output (reporters and logs)
60+
colors: true,
61+
62+
63+
// level of logging
64+
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
65+
logLevel: config.LOG_INFO,
66+
67+
68+
// enable / disable watching file and executing tests whenever any file changes
69+
autoWatch: false,
70+
71+
72+
// start these browsers
73+
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
74+
browsers: ['PhantomJS'],
75+
76+
77+
// Continuous Integration mode
78+
// if true, Karma captures browsers, runs the tests and exits
79+
singleRun: true
80+
})
81+
}

lib/index.d.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
declare let build: {
2+
rootDir: any;
3+
gulp: any;
4+
preDependencies: {};
5+
dependencies: {};
6+
postDependencies: {};
7+
config: {};
8+
initializeTasks: (gulp: any, userOptions?: any, buildPath?: string) => void;
9+
task: (taskName: any, dependencies: any, callback: any) => any;
10+
doBefore: (parentTaskName: any, taskName: any) => void;
11+
doDuring: (parentTaskName: any, taskName: any) => void;
12+
doAfter: (parentTaskName: any, taskName: any) => void;
13+
log: (message: any) => void;
14+
logError: (errorMessage: any) => void;
15+
logVerbose: (message: any) => void;
16+
};
17+
export = build;

lib/index.js

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/// <reference path="../typings/tsd" />
2+
'use strict';
3+
var runSequence = require('run-sequence');
4+
var _ = require('lodash');
5+
var path = require('path');
6+
var fs = require('fs');
7+
var chalk = require('chalk');
8+
var isVerbose = process.argv.indexOf('--verbose') > -1;
9+
var build = {
10+
rootDir: null,
11+
gulp: null,
12+
preDependencies: {},
13+
dependencies: {},
14+
postDependencies: {},
15+
config: {},
16+
initializeTasks: function (gulp, userOptions, buildPath) {
17+
this.gulp = gulp;
18+
this.rootDir = process.cwd();
19+
// Initialize runSequence.
20+
runSequence = runSequence.use(gulp);
21+
// Fetch tasks and options dynamically.
22+
var tasks = requireDir(path.resolve(__dirname, './tasks'));
23+
var localTasks = buildPath ? requireDir(path.resolve(buildPath, 'tasks')) : {};
24+
var allDefaultOptions = requireDir(path.resolve(__dirname, './options'));
25+
var allLocalDefaultOptions = buildPath ? requireDir(path.resolve(buildPath, 'options')) : {};
26+
function initializeTask(taskName, task) {
27+
if (task.registerTasks) {
28+
var localDefaultOptions = allLocalDefaultOptions[taskName];
29+
var defaultOptions = allDefaultOptions[taskName];
30+
var taskOptions = _.merge({}, (localDefaultOptions || {}).default, (defaultOptions || {}).default, (userOptions || {})[taskName]);
31+
build.config[taskName] = taskOptions;
32+
task.registerTasks(build, taskOptions);
33+
}
34+
}
35+
// Initialize local tasks first.
36+
for (var taskName in localTasks) {
37+
if (localTasks.hasOwnProperty(taskName)) {
38+
initializeTask(taskName, localTasks[taskName].default);
39+
}
40+
}
41+
// Initialize core tasks, which need to be registered after dependencies are mapped out.
42+
for (var taskName in tasks) {
43+
if (tasks.hasOwnProperty(taskName)) {
44+
initializeTask(taskName, tasks[taskName].default);
45+
}
46+
}
47+
},
48+
task: function (taskName, dependencies, callback) {
49+
var _this = this;
50+
var gulp = build.gulp;
51+
// Support no dependencies.
52+
if (arguments.length === 2 && typeof dependencies === 'function') {
53+
callback = dependencies;
54+
dependencies = null;
55+
}
56+
// Merge dependencies provided with those registered.
57+
dependencies = (build.dependencies[taskName] || []).concat(dependencies || []);
58+
var preDependencies = build.preDependencies[taskName] || [];
59+
var postDependencies = build.postDependencies[taskName] || [];
60+
if (preDependencies.length || postDependencies.length) {
61+
var internalTask = taskName + '-complete';
62+
gulp.task(internalTask, callback);
63+
return gulp.task(taskName, function (cb) {
64+
var args = [];
65+
if (preDependencies.length) {
66+
args.push(preDependencies);
67+
}
68+
if (dependencies.length) {
69+
args.push(dependencies);
70+
}
71+
args.push(internalTask);
72+
if (postDependencies.length) {
73+
args.push(postDependencies);
74+
}
75+
args.push(cb);
76+
runSequence.apply(_this, args);
77+
});
78+
}
79+
else {
80+
return gulp.task(taskName, dependencies, callback);
81+
}
82+
},
83+
doBefore: function (parentTaskName, taskName) {
84+
if (typeof taskName === 'object' && taskName.length) {
85+
// Support arrays of tasks to register.
86+
taskName.forEach(function (task) { return build.doBefore(task, parentTaskName); });
87+
}
88+
else {
89+
addToMap(parentTaskName, taskName, build.preDependencies);
90+
}
91+
},
92+
doDuring: function (parentTaskName, taskName) {
93+
if (typeof taskName === 'object' && taskName.length) {
94+
// Support arrays of tasks to register.
95+
taskName.forEach(function (task) { return build.doDuring(task, parentTaskName); });
96+
}
97+
else {
98+
addToMap(parentTaskName, taskName, build.dependencies);
99+
}
100+
},
101+
doAfter: function (parentTaskName, taskName) {
102+
if (typeof taskName === 'object' && taskName.length) {
103+
// Support arrays of tasks to register.
104+
taskName.forEach(function (task) { return build.doAfter(task, parentTaskName); });
105+
}
106+
else {
107+
addToMap(parentTaskName, taskName, build.postDependencies);
108+
}
109+
},
110+
log: function (message) {
111+
console.log(message);
112+
},
113+
logError: function (errorMessage) {
114+
build.log(chalk.red('Error: ') + errorMessage);
115+
},
116+
logVerbose: function (message) {
117+
if (isVerbose) {
118+
build.log(message);
119+
}
120+
}
121+
};
122+
function requireDir(requirePath) {
123+
var loadDir = require('require-dir');
124+
return (fs.existsSync(requirePath)) ? loadDir(requirePath) : {};
125+
}
126+
function addToMap(parentTaskName, taskName, map) {
127+
if (!map[parentTaskName]) {
128+
map[parentTaskName] = [];
129+
}
130+
map[parentTaskName].push(taskName);
131+
}
132+
module.exports = build;

lib/interfaces/ITaskGroup.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
interface ITaskGroup {
2+
registerTasks(options: any): any;
3+
}
4+
export default ITaskGroup;

lib/interfaces/ITaskGroup.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

0 commit comments

Comments
 (0)