├── .gitignore
├── .jshintignore
├── .jshintrc
├── Makefile
├── changelog.md
├── fixtures
├── README.md
├── app
│ ├── app.js
│ ├── appImports.js
│ ├── appJadeImport.js
│ └── badapp.js
├── build1
│ ├── app.deadbeef.min.js
│ └── styles.deadbeef.min.css
├── build2
│ ├── app.deadbeef.min.js
│ └── styles.deadbeef.min.css
├── libraries
│ ├── iife-no-semicolon.js
│ └── lib.js
├── modules
│ ├── README.md
│ ├── bar.js
│ ├── baz.js
│ ├── foo.js
│ └── qux.jade
└── stylesheets
│ ├── app.css
│ └── style.css
├── index.js
├── package.json
├── readme.md
└── test
├── build.js
├── consistentHash.js
├── css.js
├── dev.js
├── errors.js
├── html.js
├── jade.js
├── js.js
├── sourceMaps.js
└── timing.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | sample/.build
4 | sample-build/
5 | npm-debug.loh
6 |
--------------------------------------------------------------------------------
/.jshintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | sample
3 | fixtures/build1/app.deadbeef.min.js
4 | fixtures/app/app.js
5 | fixtures/app/badapp.js
6 | fixtures/app/appImports.js
7 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "indent": 4,
3 | "asi": false,
4 | "expr": true,
5 | "loopfunc": true,
6 | "curly": false,
7 | "evil": true,
8 | "white": true,
9 | "undef": true,
10 | "unused": true,
11 | "node": true
12 | }
13 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | test:
2 | @node node_modules/lab/bin/lab -t 100 -m 40000
3 | test-no-cov:
4 | @node node_modules/lab/bin/lab
5 | test-cov-html:
6 | @node node_modules/lab/bin/lab -r html -o coverage.html
7 | complexity:
8 | @node node_modules/complexity-report/src/index.js -o complexity.md -f markdown index.js
9 |
10 | .PHONY: test test-no-cov test-cov-html complexity
11 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # 5.0.0 (2016-04-15)
2 |
3 | - Update to Browserify v13 [#71](https://github.com/HenrikJoreteg/moonboots/pull/71)
4 |
5 | # 4.0.0 (2015-03-03)
6 |
7 | - Update to Browserify v9 [#62](https://github.com/HenrikJoreteg/moonboots/pull/62)
8 | - Allow setting individual transform options [#65](https://github.com/HenrikJoreteg/moonboots/pull/65)
9 | - Allow transforms to be passed in using the correct `browserify.transform` option name [#52](https://github.com/HenrikJoreteg/moonboots/pull/52)
--------------------------------------------------------------------------------
/fixtures/README.md:
--------------------------------------------------------------------------------
1 | # Test fixtures
2 |
--------------------------------------------------------------------------------
/fixtures/app/app.js:
--------------------------------------------------------------------------------
1 | module.exports = function () {
2 | var x = 1;
3 | };
4 |
5 | module.exports();
6 |
--------------------------------------------------------------------------------
/fixtures/app/appImports.js:
--------------------------------------------------------------------------------
1 | var foo = require('../modules/foo');
2 | var bar = require('../modules/bar');
3 | var baz = require('../modules/baz');
4 |
5 |
6 | (function () {
7 | console.log(1);
8 | })();
--------------------------------------------------------------------------------
/fixtures/app/appJadeImport.js:
--------------------------------------------------------------------------------
1 | require('../modules/qux.jade');
2 |
3 |
4 | (function () {
5 | console.log(1);
6 | })();
--------------------------------------------------------------------------------
/fixtures/app/badapp.js:
--------------------------------------------------------------------------------
1 | var foo = require('not-a-module');
2 |
3 | module.exports = function () {
4 | var x = 1;
5 | };
6 |
7 | module.exports();
8 |
9 |
--------------------------------------------------------------------------------
/fixtures/build1/app.deadbeef.min.js:
--------------------------------------------------------------------------------
1 | nothing
--------------------------------------------------------------------------------
/fixtures/build1/styles.deadbeef.min.css:
--------------------------------------------------------------------------------
1 | readable
2 |
--------------------------------------------------------------------------------
/fixtures/build2/app.deadbeef.min.js:
--------------------------------------------------------------------------------
1 | undefined;
2 |
--------------------------------------------------------------------------------
/fixtures/build2/styles.deadbeef.min.css:
--------------------------------------------------------------------------------
1 | nothing
--------------------------------------------------------------------------------
/fixtures/libraries/iife-no-semicolon.js:
--------------------------------------------------------------------------------
1 | /*jshint asi:true, browser:true, unused:false*/
2 | (function () {
3 | if (typeof window !== 'undefined') {
4 | window.BadLib = function (foo) {
5 | if (this.baz && this.baz === foo) {
6 | this.console.log('baz is', foo)
7 | }
8 | };
9 | }
10 | })()
--------------------------------------------------------------------------------
/fixtures/libraries/lib.js:
--------------------------------------------------------------------------------
1 | /*jshint asi:true, browser:true, unused:false*/
2 | (function () {
3 | if (typeof window !== 'undefined') {
4 | window.Lib = function (bar) {
5 | if (this.biz && this.biz === bar) {
6 | this.console.log('biz is', bar);
7 | }
8 | };
9 | }
10 | })();
--------------------------------------------------------------------------------
/fixtures/modules/README.md:
--------------------------------------------------------------------------------
1 | # This file will be ignored by moonboots modulesDir
2 |
--------------------------------------------------------------------------------
/fixtures/modules/bar.js:
--------------------------------------------------------------------------------
1 | var baz = require('./baz');
2 | var Backbone = require('backbone');
3 |
4 |
5 | module.exports = function () {
6 | baz.apply(null, arguments);
7 | return Backbone;
8 | };
9 |
--------------------------------------------------------------------------------
/fixtures/modules/baz.js:
--------------------------------------------------------------------------------
1 | var async = require('async');
2 |
3 | module.exports = function (arr, iterator, done) {
4 | async.map([1, 2, 3], iterator, done);
5 | };
6 |
--------------------------------------------------------------------------------
/fixtures/modules/foo.js:
--------------------------------------------------------------------------------
1 | module.exports = 'foo';
2 |
--------------------------------------------------------------------------------
/fixtures/modules/qux.jade:
--------------------------------------------------------------------------------
1 | p All that you require to crash
2 |
--------------------------------------------------------------------------------
/fixtures/stylesheets/app.css:
--------------------------------------------------------------------------------
1 | div {border: 1px solid #000;}
2 |
--------------------------------------------------------------------------------
/fixtures/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {background: #ccc;}
2 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var crypto = require('crypto');
3 | var async = require('async');
4 | var EventEmitter = require('events').EventEmitter;
5 | var browserify = require('browserify');
6 | var UglifyJS = require('uglify-js');
7 | var cssmin = require('cssmin');
8 | var path = require('path');
9 |
10 |
11 | function Moonboots(opts) {
12 | var item;
13 | //'opts' has to be an object
14 | if (typeof opts !== 'object') {
15 | throw new Error('Invalid options');
16 | }
17 | //'main' is the only required parameter, throw if it's missing
18 | if (!opts.main) {
19 | throw new Error("You must supply at minimum a `main` file for your moonboots app: {main: 'myApp.js'}");
20 | }
21 |
22 | //Defaults
23 | this.config = {
24 | libraries: [],
25 | stylesheets: [],
26 | jsFileName: 'app',
27 | cssFileName: 'styles',
28 | browserify: {}, // overridable browserify options
29 | uglify: {}, // overridable uglify options
30 | beforeBuildJS: function (cb) { cb(); },
31 | beforeBuildCSS: function (cb) { cb(); },
32 | sourceMaps: false, //turns on browserify debug
33 | resourcePrefix: '/',
34 | minify: true,
35 | cache: true,
36 | developmentMode: false,
37 | timingMode: false
38 | };
39 |
40 | // Were we'll store generated source code, etc.
41 | this.result = {
42 | js: {ext: 'js', source: ''},
43 | css: {ext: 'css'},
44 | html: {}
45 | };
46 |
47 | for (item in opts) {
48 | this.config[item] = opts[item];
49 | }
50 |
51 | // Uglify fromString must be true
52 | this.config.uglify.fromString = true;
53 |
54 | // Use sourceMaps option to set browserify.debug if its not set already
55 | if (typeof this.config.browserify.debug === 'undefined') {
56 | this.config.browserify.debug = this.config.sourceMaps;
57 | }
58 |
59 | // Replace transforms with transform in the browserify config since
60 | // that is how browserify expects them
61 | if (this.config.browserify.transforms && !this.config.browserify.transform) {
62 | this.config.browserify.transform = this.config.browserify.transforms;
63 | delete this.config.browserify.transforms;
64 | }
65 |
66 | // Ensure browserify transforms is set
67 | if (typeof this.config.browserify.transform === 'undefined') {
68 | this.config.browserify.transform = [];
69 | }
70 |
71 | // developmentMode forces minify to false and never build no matter what
72 | if (this.config.developmentMode) {
73 | this.config.minify = false;
74 | this.config.buildDirectory = undefined;
75 | this.config.cache = false;
76 | }
77 |
78 | //We'll re-add extensions later
79 | if (path.extname(this.config.jsFileName) === '.js') {
80 | this.config.jsFileName = this.config.jsFileName.slice(0, -3);
81 | }
82 | if (path.extname(this.config.cssFileName) === '.css') {
83 | this.config.cssFileName = this.config.cssFileName.slice(0, -4);
84 | }
85 |
86 | // inherit from event emitter and then wait for nextTick to do anything so that our parent has a chance to listen for events
87 | EventEmitter.call(this);
88 | process.nextTick(this.build.bind(this));
89 | }
90 |
91 | // Inherit from event emitter
92 | Moonboots.prototype = Object.create(EventEmitter.prototype, {
93 | constructor: {
94 | value: Moonboots
95 | }
96 | });
97 |
98 | //Initial build, in development mode we just set hashes and filenames, otherwise we prime the sources
99 | //Emits 'ready' when done
100 | Moonboots.prototype.build = function () {
101 | var self = this;
102 |
103 | self.timing('timing', 'build start');
104 | async.series([
105 | function _buildFiles(buildFilesDone) {
106 | var parts;
107 | if (!self.config.buildDirectory) {
108 | return buildFilesDone();
109 | }
110 | fs.readdir(self.config.buildDirectory, function (err, files) {
111 | self.timing('reading buildDirectory start');
112 | if (err) {
113 | self.config.buildDirectory = undefined;
114 | return buildFilesDone();
115 | }
116 | async.each(files, function (fileName, next) {
117 | if (path.extname(fileName) === '.js' && fileName.indexOf(self.config.jsFileName) === 0) {
118 | return fs.readFile(path.join(self.config.buildDirectory, fileName), 'utf8', function (err, data) {
119 | if (err) {
120 | self.config.buildDirectory = undefined;
121 | return next(true);
122 | }
123 | parts = fileName.split('.');
124 | self.result.js.hash = parts[1];
125 | self.result.js.source = data;
126 | self.result.js.filename = fileName;
127 | self.result.js.fromBuild = true;
128 | next();
129 | });
130 | }
131 | if (path.extname(fileName) === '.css' && fileName.indexOf(self.config.cssFileName) === 0) {
132 | return fs.readFile(path.join(self.config.buildDirectory, fileName), 'utf8', function (err, data) {
133 | if (err) {
134 | self.config.buildDirectory = undefined;
135 | return next(true);
136 | }
137 | parts = fileName.split('.');
138 | self.result.css.hash = parts[1];
139 | self.result.css.source = data;
140 | self.result.css.filename = fileName;
141 | self.result.css.fromBuild = true;
142 | next();
143 | });
144 | }
145 | next();
146 | }, function () {
147 | self.timing('reading buildDirectory finish');
148 | buildFilesDone();
149 | });
150 | });
151 | },
152 | function _buildBundles(buildBundlesDone) {
153 | if (self.result.js.filename && self.result.css.filename) {
154 | //buildFiles found existing files we don't have to build bundles
155 | return buildBundlesDone();
156 | }
157 | async.parallel([
158 | function _buildCSS(buildCSSDone) {
159 | self.timing('build css start');
160 | //If we're rebuilding on each request we just have to set the hash
161 | if (!self.config.cache) {
162 | self.result.css.hash = 'nonCached';
163 | return buildCSSDone();
164 | }
165 | self.bundleCSS(true, buildCSSDone);
166 | },
167 | function _buildJS(buildJSDone) {
168 | //If we're rebuilding on each request we just have to set the hash
169 | if (!self.config.cache) {
170 | self.result.js.hash = 'nonCached';
171 | return buildJSDone();
172 | }
173 | self.bundleJS(true, buildJSDone);
174 | }
175 | ], buildBundlesDone);
176 | },
177 | function _setResults(setResultsDone) {
178 | var cssFileName = self.config.cssFileName + '.' + self.result.css.hash;
179 | var jsFileName = self.config.jsFileName + '.' + self.result.js.hash;
180 |
181 | if (self.config.minify) {
182 | cssFileName += '.min';
183 | jsFileName += '.min';
184 | }
185 |
186 | cssFileName += '.css';
187 | jsFileName += '.js';
188 |
189 | self.result.css.fileName = cssFileName;
190 | self.result.js.fileName = jsFileName;
191 |
192 | self.result.html.source = '\n';
193 | if (self.config.stylesheets.length > 0) {
194 | self.result.html.source += linkTag(self.config.resourcePrefix + self.cssFileName());
195 | }
196 | self.result.html.source += scriptTag(self.config.resourcePrefix + self.jsFileName());
197 | self.result.html.context = {
198 | jsFileName: self.result.js.fileName,
199 | cssFileName: self.result.css.fileName
200 | };
201 | setResultsDone();
202 | },
203 | function _createBuildFiles(createBuildFilesDone) {
204 | if (!self.config.buildDirectory) {
205 | return createBuildFilesDone();
206 | }
207 |
208 | async.parallel([
209 | function (next) {
210 | if (self.result.js.fromBuild) {
211 | return next();
212 | }
213 | fs.writeFile(path.join(self.config.buildDirectory, self.result.css.fileName), self.result.css.source, next);
214 | }, function (next) {
215 | if (self.result.css.fromBuild) {
216 | return next();
217 | }
218 | fs.writeFile(path.join(self.config.buildDirectory, self.result.js.fileName), self.result.js.source, next);
219 | }
220 | ], createBuildFilesDone);
221 | }
222 | ], function () {
223 | self.timing('build finish');
224 | self.emit('ready');
225 | });
226 | };
227 |
228 | // Actually generate the CSS bundle
229 | Moonboots.prototype.bundleCSS = function (setHash, done) {
230 | var self = this;
231 | async.series([
232 | function _beforeBuildCSS(next) {
233 | self.timing('beforeBuildCSS start');
234 | if (self.config.beforeBuildCSS.length) {
235 | self.config.beforeBuildCSS(function (err) {
236 | self.timing('beforeBuildCSS finish');
237 | next(err);
238 | });
239 | } else {
240 | self.config.beforeBuildCSS();
241 | self.timing('beforeBuildCSS finish');
242 | next();
243 | }
244 | },
245 | function _buildCSS(next) {
246 | var csssha;
247 | self.timing('buildCSS start');
248 | self.result.css.source = concatFiles(self.config.stylesheets);
249 | if (setHash) {
250 | csssha = crypto.createHash('sha1'); // we'll calculate this to know whether to change the filename
251 | csssha.update(self.result.css.source);
252 | self.result.css.hash = csssha.digest('hex').slice(0, 8);
253 | }
254 | if (self.config.minify) {
255 | self.result.css.source = cssmin(self.result.css.source);
256 | }
257 | self.timing('buildCSS finish');
258 | next();
259 | }
260 | ], function _bundleCSSDone(err) {
261 | if (err) {
262 | self.emit('log', ['moonboots', 'error'], err);
263 | }
264 | done(null, self.result.css.source);
265 | });
266 | };
267 |
268 | // Actually generate the JS bundle
269 | Moonboots.prototype.bundleJS = function (setHash, done) {
270 | var self = this;
271 | var jssha = crypto.createHash('sha1'); // we'll calculate this to know whether to change the filename
272 | async.series([
273 | function _beforeBuildJS(next) {
274 | self.timing('beforeBuildJS start');
275 | if (self.config.beforeBuildJS.length) {
276 | self.config.beforeBuildJS(function (err) {
277 | self.timing('beforeBuildJS finish');
278 | next(err);
279 | });
280 | } else {
281 | self.config.beforeBuildJS();
282 | self.timing('beforeBuildJS finish');
283 | next();
284 | }
285 | },
286 | function _concatLibs(next) {
287 | //Start w/ external libraries
288 | self.timing('build libraries start');
289 | self.result.js.source = concatFiles(self.config.libraries);
290 | self.timing('build libraries finish');
291 | next();
292 | },
293 | function (next) {
294 | self.browserify(next);
295 | },
296 | function (next) {
297 | if (setHash) {
298 | jssha.update(self.result.js.source);
299 | self.result.js.hash = jssha.digest('hex').slice(0, 8);
300 | }
301 | if (self.config.minify) {
302 | self.timing('minify start');
303 | self.result.js.source = UglifyJS.minify(self.result.js.source, self.config.uglify).code;
304 | self.timing('minify finish');
305 | }
306 | next();
307 | }
308 | ], function _bundleJSDone(err) {
309 | if (err) {
310 | self.emit('log', ['moonboots', 'error'], err);
311 | if (self.config.developmentMode) {
312 | self.result.js.source = errorTrace(err);
313 | } else {
314 | throw err;
315 | }
316 | }
317 | done(null, self.result.js.source);
318 | });
319 | };
320 |
321 |
322 | Moonboots.prototype.browserify = function (done) {
323 | var modules, args, bundle;
324 | var self = this;
325 |
326 | self.timing('browserify start');
327 |
328 | bundle = browserify(self.config.browserify);
329 |
330 | // handle module folder that you want to be able to require without relative paths.
331 | if (self.config.modulesDir) {
332 | modules = fs.readdirSync(self.config.modulesDir);
333 | modules.forEach(function (moduleFileName) {
334 | if (path.extname(moduleFileName) === '.js') {
335 | args = [
336 | path.join(self.config.modulesDir, moduleFileName),
337 | {expose: path.basename(moduleFileName, '.js')}
338 | ];
339 | bundle.require.apply(bundle, args);
340 | }
341 | });
342 | }
343 |
344 | // add main import
345 | bundle.add(self.config.main);
346 |
347 | bundle.bundle(function (err, js) {
348 | if (self.result.js.source.trim().slice(-1) !== ';') {
349 | js = ';' + js;
350 | }
351 | self.result.js.source = self.result.js.source + js;
352 |
353 | self.timing('browserify finish');
354 | done(err);
355 | });
356 | };
357 |
358 | /*
359 | * Main moonboots functions.
360 | * These should be the only methods you call.
361 | */
362 |
363 | //Send jsSource to callback, rebuilding every time if in development mode
364 | Moonboots.prototype.jsSource = function (cb) {
365 | if (this.config.cache) {
366 | return cb(null, this.result.js.source);
367 | }
368 | this.bundleJS(false, cb);
369 | };
370 |
371 | //Send cssSource to callback, rebuilding every time if in development mode
372 | Moonboots.prototype.cssSource = function (cb) {
373 | if (this.config.cache) {
374 | return cb(null, this.result.css.source);
375 | }
376 | this.bundleCSS(false, cb);
377 | };
378 |
379 | //Return jsFileName, which never changes
380 | Moonboots.prototype.jsFileName = function () {
381 | return this.result.js.fileName;
382 | };
383 |
384 | //Return jsFileName, which never changes
385 | Moonboots.prototype.cssFileName = function () {
386 | return this.result.css.fileName;
387 | };
388 |
389 | //Return htmlContext, which never changes
390 | Moonboots.prototype.htmlContext = function () {
391 | return this.result.html.context;
392 | };
393 |
394 | //Return htmlSource, which never changes
395 | Moonboots.prototype.htmlSource = function () {
396 | return this.result.html.source;
397 | };
398 |
399 | Moonboots.prototype.timing = function (message) {
400 | if (this.config.timingMode) {
401 | this.emit('log', ['moonboots', 'timing', 'debug'], message, Date.now());
402 | }
403 | };
404 |
405 | /*
406 | * End main moonboots functions.
407 | */
408 |
409 | // Main export
410 | module.exports = Moonboots;
411 |
412 |
413 | // a few helpers
414 | function concatFiles(arrayOfFiles) {
415 | return arrayOfFiles.map(function (fileName) {
416 | var source = fs.readFileSync(fileName, 'utf8');
417 | if (path.extname(fileName) !== '.js') {
418 | return source;
419 | }
420 | if (source.trim().slice(-1) !== ';') {
421 | source = source + ';';
422 | }
423 | return source;
424 | }).join('\n');
425 | }
426 |
427 | function linkTag(filename) {
428 | return '\n';
429 | }
430 |
431 | function scriptTag(filename) {
432 | return '';
433 | }
434 |
435 | function errorTrace(err) {
436 | var trace;
437 | if (err.stack) {
438 | trace = err.stack;
439 | } else {
440 | trace = JSON.stringify(err);
441 | }
442 | trace = trace.split('\n').join('
').replace(/"/g, '"');
443 | return 'document.write("
' + trace + '");'; 444 | } 445 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moonboots", 3 | "description": "A set of tools and conventions for building/serving clientside apps with node.js", 4 | "version": "5.0.1", 5 | "author": "Henrik Joreteg
All that you require to crash
"'); 23 | done(); 24 | }); 25 | }); 26 | }); 27 | lab.test('ran with pretty:true', function (done) { 28 | var moonboots = new Moonboots(options(['jadeify', {pretty: true}])); 29 | moonboots.on('ready', function () { 30 | moonboots.jsSource(function (err, js) { 31 | Code.expect(js).to.contain('"\\nAll that you require to crash
"'); 32 | done(); 33 | }); 34 | }); 35 | }); 36 | }); 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/js.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var Code = require('code'); 3 | var lab = exports.lab = Lab.script(); 4 | var Moonboots = require('..'); 5 | var moonboots; 6 | 7 | var EXPECTED_JS_HASH = 'app.794c89f5.js'; 8 | var EXPECTED_JS_MIN_HASH = 'app.794c89f5.min.js'; 9 | 10 | lab.experiment('js with default options', function () { 11 | lab.before(function (done) { 12 | var options = { 13 | main: __dirname + '/../fixtures/app/app.js', 14 | jsFileName: 'app' 15 | }; 16 | moonboots = new Moonboots(options); 17 | moonboots.on('ready', done); 18 | }); 19 | lab.test('filename', function (done) { 20 | Code.expect(moonboots.jsFileName(), 'js filename').to.equal(EXPECTED_JS_MIN_HASH); 21 | done(); 22 | }); 23 | /* 24 | lab.test('content', function (done) { 25 | Code.expect(moonboots.jsSource(), 'js source').to.equal('how do we even test this?'); 26 | done(); 27 | }); 28 | */ 29 | }); 30 | 31 | lab.experiment('js with uglify options', function () { 32 | lab.before(function (done) { 33 | var options = { 34 | main: __dirname + '/../fixtures/app/app.js', 35 | jsFileName: 'app', 36 | uglify: { 37 | mangle: false 38 | } 39 | }; 40 | 41 | moonboots = new Moonboots(options); 42 | moonboots.on('ready', done); 43 | }); 44 | lab.test('filename', function (done) { 45 | Code.expect(moonboots.jsFileName(), 'js filename').to.equal(EXPECTED_JS_MIN_HASH); 46 | done(); 47 | }); 48 | }); 49 | 50 | lab.experiment('js with no minify', function () { 51 | lab.before(function (done) { 52 | var options = { 53 | main: __dirname + '/../fixtures/app/app.js', 54 | jsFileName: 'app', 55 | minify: false 56 | }; 57 | moonboots = new Moonboots(options); 58 | moonboots.on('ready', done); 59 | }); 60 | lab.test('filename', function (done) { 61 | Code.expect(moonboots.jsFileName(), 'js filename').to.equal(EXPECTED_JS_HASH); 62 | done(); 63 | }); 64 | /* 65 | lab.test('content', function (done) { 66 | Code.expect(moonboots.jsSource(), 'js source').to.equal('how do we even test this?'); 67 | done(); 68 | }); 69 | */ 70 | }); 71 | 72 | lab.experiment('js with .js already added', function () { 73 | lab.before(function (done) { 74 | var options = { 75 | main: __dirname + '/../fixtures/app/app.js', 76 | jsFileName: 'app.js' 77 | }; 78 | moonboots = new Moonboots(options); 79 | moonboots.on('ready', done); 80 | }); 81 | lab.test('filename', function (done) { 82 | Code.expect(moonboots.jsFileName(), 'js filename').to.equal(EXPECTED_JS_MIN_HASH); 83 | done(); 84 | }); 85 | }); 86 | 87 | lab.experiment('modulesDir', function () { 88 | lab.before(function (done) { 89 | var options = { 90 | main: __dirname + '/../fixtures/app/app.js', 91 | jsFileName: 'app', 92 | modulesDir: __dirname + '/../fixtures/modules' 93 | }; 94 | moonboots = new Moonboots(options); 95 | moonboots.on('ready', done); 96 | }); 97 | lab.test('module foo is in source', function (done) { 98 | moonboots.jsSource(function (err, js) { 99 | Code.expect(js, 'js source').to.contain('"foo"'); 100 | done(); 101 | }); 102 | }); 103 | }); 104 | 105 | lab.experiment('transforms', function () { 106 | var transformRan = 0; 107 | lab.before(function (done) { 108 | var options = { 109 | main: __dirname + '/../fixtures/app/app.js', 110 | jsFileName: 'app', 111 | browserify: { 112 | transforms: [ 113 | function () { 114 | var through = require('through'); 115 | transformRan++; 116 | return through( 117 | function write() {}, 118 | function _end() { 119 | this.queue(null); 120 | } 121 | ); 122 | } 123 | ] 124 | } 125 | }; 126 | moonboots = new Moonboots(options); 127 | moonboots.on('ready', done); 128 | }); 129 | lab.test('ran', function (done) { 130 | Code.expect(transformRan).to.equal(1); 131 | done(); 132 | }); 133 | }); 134 | 135 | 136 | lab.experiment('transforms with transform option', function () { 137 | var transformRan = 0; 138 | lab.before(function (done) { 139 | var options = { 140 | main: __dirname + '/../fixtures/app/app.js', 141 | jsFileName: 'app', 142 | browserify: { 143 | transform: [ 144 | function () { 145 | var through = require('through'); 146 | transformRan++; 147 | return through( 148 | function write() {}, 149 | function _end() { 150 | this.queue(null); 151 | } 152 | ); 153 | } 154 | ] 155 | } 156 | }; 157 | moonboots = new Moonboots(options); 158 | moonboots.on('ready', done); 159 | }); 160 | lab.test('ran', function (done) { 161 | Code.expect(transformRan).to.equal(1); 162 | done(); 163 | }); 164 | }); 165 | 166 | lab.experiment('sync beforeBuildJS', function () { 167 | var beforeRan = false; 168 | lab.before(function (done) { 169 | var options = { 170 | main: __dirname + '/../fixtures/app/app.js', 171 | jsFileName: 'app', 172 | minify: false, 173 | beforeBuildJS: function () { 174 | beforeRan = true; 175 | } 176 | }; 177 | moonboots = new Moonboots(options); 178 | moonboots.on('ready', done); 179 | }); 180 | lab.test('ran', function (done) { 181 | Code.expect(beforeRan).to.equal(true); 182 | done(); 183 | }); 184 | }); 185 | -------------------------------------------------------------------------------- /test/sourceMaps.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var Code = require('code'); 3 | var lab = exports.lab = Lab.script(); 4 | var Moonboots = require('..'); 5 | var moonboots; 6 | 7 | lab.experiment('sourceMaps option sets browserify.debug', function () { 8 | lab.before(function (done) { 9 | var options = { 10 | main: __dirname + '/../fixtures/app/app.js', 11 | jsFileName: 'app', 12 | sourceMaps: true 13 | }; 14 | moonboots = new Moonboots(options); 15 | moonboots.on('ready', done); 16 | }); 17 | 18 | lab.test('filename', function (done) { 19 | Code.expect(moonboots.config.browserify.debug).to.equal(true); 20 | done(); 21 | }); 22 | }); 23 | 24 | lab.experiment('default is false', function () { 25 | lab.before(function (done) { 26 | var options = { 27 | main: __dirname + '/../fixtures/app/app.js', 28 | jsFileName: 'app' 29 | }; 30 | moonboots = new Moonboots(options); 31 | moonboots.on('ready', done); 32 | }); 33 | 34 | lab.test('filename', function (done) { 35 | Code.expect(moonboots.config.browserify.debug).to.equal(false); 36 | done(); 37 | }); 38 | }); 39 | 40 | lab.experiment('sourceMaps option can be overwritten by browserify.debug', function () { 41 | lab.before(function (done) { 42 | var options = { 43 | main: __dirname + '/../fixtures/app/app.js', 44 | jsFileName: 'app', 45 | sourceMaps: true, 46 | browserify: { 47 | debug: false 48 | } 49 | }; 50 | moonboots = new Moonboots(options); 51 | moonboots.on('ready', done); 52 | }); 53 | 54 | lab.test('filename', function (done) { 55 | Code.expect(moonboots.config.browserify.debug).to.equal(false); 56 | done(); 57 | }); 58 | }); -------------------------------------------------------------------------------- /test/timing.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var Code = require('code'); 3 | var lab = exports.lab = Lab.script(); 4 | var Moonboots = require('..'); 5 | var moonboots; 6 | var timingEvents = 0; 7 | 8 | lab.experiment('timingMode', function () { 9 | lab.before(function (done) { 10 | var options = { 11 | main: __dirname + '/../fixtures/app/app.js', 12 | timingMode: true 13 | }; 14 | moonboots = new Moonboots(options); 15 | moonboots.on('log', function (levels) { 16 | if (levels.indexOf('timing') > -1) { 17 | timingEvents = timingEvents + 1; 18 | } 19 | }); 20 | moonboots.on('ready', done); 21 | }); 22 | lab.test('emits timing events', function (done) { 23 | Code.expect(timingEvents).to.be.above(0); 24 | done(); 25 | }); 26 | }); 27 | 28 | --------------------------------------------------------------------------------