/
build.js
212 lines (177 loc) · 5.62 KB
/
build.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/**
* Module dependencies.
*/
var fs = require('fs')
, package = JSON.parse(fs.readFileSync(__dirname+ '/../package.json'))
, uglify = require('uglify-js');
/**
* License headers.
*
* @api private
*/
var template = '/*! binary.%ext% build:' + package.version + ', %type%. Copyright(c) 2012 Eric Zhang <eric@ericzhang.com> MIT Licensed */\n(function(exports){\n'
, development = template.replace('%type%', 'development').replace('%ext%', 'js')
, production = template.replace('%type%', 'production').replace('%ext%', 'min.js')
, suffix = '\n})(this);\n';
/**
* If statements, these allows you to create serveride & client side compatible
* code using specially designed `if` statements that remove serverside
* designed code from the source files
*
* @api private
*/
var starttagIF = '// if node'
, endtagIF = '// end node';
/**
* The modules that are required to create a base build of BinaryJS client.
*
* @const
* @type {Array}
* @api private
*/
var base = [
'../deps/EventEmitter.js'
, 'util.js'
, 'client/stream.js'
, 'client/blob_stream.js'
, 'stream.js'
, 'client.js'
];
/**
* Builds a custom BinaryJS client distribution based on the transports that you
* need. You can configure the build to create development build or production
* build (minified).
*
* @param {Array} transports The transports that needs to be bundled.
* @param {Object} [options] Options to configure the building process.
* @param {Function} callback Last argument should always be the callback
* @callback {String|Boolean} err An optional argument, if it exists than an error
* occurred during the build process.
* @callback {String} result The result of the build process.
* @api public
*/
var builder = module.exports = function () {
var options, callback, error = null
, args = Array.prototype.slice.call(arguments, 0)
, settings = {
minify: true
, node: false
, custom: []
};
// Fancy pancy argument support this makes any pattern possible mainly
// because we require only one of each type
args.forEach(function (arg) {
var type = Object.prototype.toString.call(arg)
.replace(/\[object\s(\w+)\]/gi , '$1' ).toLowerCase();
switch (type) {
case 'object':
return options = arg;
case 'function':
return callback = arg;
}
});
// Add defaults
options = options || {};
// Merge the data
for(var option in options) {
settings[option] = options[option];
}
// Start creating a dependencies chain with all the required files for the
// custom BinaryJS client bundle.
var files = [];
base.forEach(function (file) {
files.push(__dirname + '/../lib/' + file);
});
var results = {};
files.forEach(function (file) {
fs.readFile(file, function (err, content) {
if (err) error = err;
results[file] = content;
// check if we are done yet, or not.. Just by checking the size of the result
// object.
if (Object.keys(results).length !== files.length) return;
// concatinate the file contents in order
var code = development
, ignore = 0;
files.forEach(function (file) {
code += results[file];
});
// check if we need to add custom code
if (settings.custom.length) {
settings.custom.forEach(function (content) {
code += content;
});
}
// Search for conditional code blocks that need to be removed as they
// where designed for a server side env. but only if we don't want to
// make this build node compatible.
if (!settings.node) {
code = code.split('\n').filter(function (line) {
// check if there are tags in here
var start = line.indexOf(starttagIF) >= 0
, end = line.indexOf(endtagIF) >= 0
, ret = ignore;
// ignore the current line
if (start) {
ignore++;
ret = ignore;
}
// stop ignoring the next line
if (end) {
ignore--;
}
return ret == 0;
}).join('\n');
}
code += suffix;
// check if we need to process it any further
if (settings.minify) {
var ast = uglify.parser.parse(code);
ast = uglify.uglify.ast_mangle(ast);
ast = uglify.uglify.ast_squeeze(ast);
code = production + uglify.uglify.gen_code(ast, { ascii_only: true });
}
callback(error, code);
})
})
};
/**
* Builder version is also the current client version
* this way we don't have to do another include for the
* clients version number and we can just include the builder.
*
* @type {String}
* @api public
*/
builder.version = package.version;
/**
* Command line support, this allows us to generate builds without having
* to load it as module.
*/
if (!module.parent){
// the first 2 are `node` and the path to this file, we don't need them
var args = process.argv.slice(2);
// build a development build
builder(args.length ? args : false, { minify:false }, function (err, content) {
if (err) return console.error(err);
console.log(__dirname);
fs.write(
fs.openSync(__dirname + '/../dist/binary.js', 'w')
, content
, 0
, 'utf8'
);
console.log('Successfully generated the development build: binary.js');
});
// and build a production build
builder(args.length ? args : false, function (err, content) {
if (err) return console.error(err);
fs.write(
fs.openSync(__dirname + '/../dist/binary.min.js', 'w')
, content
, 0
, 'utf8'
);
console.log('Successfully generated the production build: binary.min.js');
});
}