UNPKG

5.43 kBJavaScriptView Raw
1#!/usr/bin/env node
2var _ = require('lodash');
3var fs = require('fs');
4var path = require('path');
5var Mocha = require('mocha');
6var colors = require('colors');
7var rimraf = require('rimraf');
8var mochaNotifier = require('mocha-notifier-reporter');
9
10var build = require('../lib/build');
11var makeBuild = require('../lib/makeBuild').makeBuild;
12var configs = require('../lib/configs');
13var getWebpackEntryForTest = require('../lib/getWebpackEntryForTest');
14
15var argv = require('yargs')
16 .alias('b', 'blueprintsPath')
17 .describe('b', 'path to a raw-config via a node file with moduel.exports = config')
18 .default('b', './blueprints.config.js')
19 .alias('p', 'production')
20 .describe('p', 'enable production settings for the default build cofings')
21 .default('p', false)
22 .alias('c', 'client')
23 .describe('c', 'use the default client build, assumes you have an entry point to a client at ~/lib/client.[some es6.js or .js or .jsx]')
24 .default('c', false)
25 .alias('s', 'server')
26 .describe('s', 'use the default server build, assumes you have an entry point to a server at ~/lib/server[some es6.js or .js or .jsx]')
27 .default('s', false)
28 .alias('a', 'clientAndServer')
29 .describe('a', '[DEFAULT=true] use both a client and a server build. checks if you have an extend build and applies it.')
30 .default('a', true)
31 .alias('w', 'watch')
32 .describe('w', '[DEFAULT=false] force watching of all builds')
33 .default('w', false)
34 .alias('i', 'ignoreBlueprints')
35 .describe('ignore the blueprints.config.js file in the current directory and use defaults')
36 .default('i', false)
37 .alias('t', 'runTest')
38 .describe('search for test files and run them')
39 .default('t', false)
40 .argv;
41
42function loadBlueprintsFromPath(filePath, isProduction) {
43 try {
44 console.log('...loading blueprints from', filePath)
45 var builds = require(path.resolve(filePath));
46
47 // build configuration files are written in js and can be:
48 // a) a function that takes isProduction (boolean) and returns an array of builds
49 // b) object with property named extensions, to extend / override default builds
50 // c) an array of builds
51 // The array is most straightforward and the function seems infinitely
52 // more useful than the extensions object, and easier to understand. I'd
53 // like to deprecate the extensions object if its not being used in many places.
54 if (typeof builds === 'function') {
55 builds = builds(isProduction);
56 } else if (!Array.isArray(builds)) {
57 if (builds.extensions === true) {
58 return { extensions: _.omit(builds, 'extensions') };
59 }
60 builds = [builds];
61 }
62
63 return { builds };
64 } catch (e) {
65 console.log(colors.red('Error in loading blueprints'), e);
66 process.exit(1);
67 }
68}
69
70function loadDefaultConfigs(options) {
71 console.log('...using default configs');
72 if (options.runTest) {
73 console.log('...Setting up tests:');
74 var config = _.merge(
75 {},
76 configs.DefaultTestingConfig,
77 { webpack: { entry: getWebpackEntryForTest('./') } }
78 );
79 return [ config ];
80
81 } else if (options.client) {
82 console.log('...client');
83 return [ configs.getClientConfig(options.production) ];
84
85 } else if (options.server) {
86 console.log('...server');
87 return [ configs.getServerConfig(options.production) ];
88
89 } else if (options.clientAndServer) {
90 console.log('...both');
91 return [
92 configs.getClientConfig(options.production),
93 configs.getServerConfig(options.production),
94 ];
95 }
96}
97
98function makeConfig(options) {
99 var builds;
100 var extensions = {};
101
102 if (options.blueprintsPath && !options.ignoreBlueprints && !options.runTest) {
103 var blueprints = loadBlueprintsFromPath(options.blueprintsPath, options.production);
104
105 if (blueprints.extensions) {
106 extensions = blueprints.extensions;
107
108 } else if (blueprints.builds && blueprints.builds.length) {
109 builds = blueprints.builds;
110 }
111 }
112
113 if (!builds) {
114 builds = loadDefaultConfigs(options);
115 }
116
117 if (options.watch) {
118 extensions.watch = true;
119 }
120
121 return {
122 builds: builds.map(function(build) {
123 return makeBuild(_.merge(build, extensions));
124 }),
125 };
126};
127
128
129console.log('...Reading Blueprints', argv.blueprintsPath);
130console.log('...cwd', process.cwd());
131
132var config = makeConfig(argv);
133
134build(config, function(stats) {
135 if (stats.errors && stats.errors.length > 0 && !argv.watch) {
136 console.log(colors.red('ERROR IN BUILD. Aborting.'));
137 process.exit(1);
138 }
139
140 if (argv.runTest) {
141 console.log(colors.magenta(
142 '\n ******************************' +
143 '\n * RUNNING TESTS *' +
144 '\n ******************************'
145 ));
146
147 m = new Mocha({ reporter: mochaNotifier.decorate('spec') });
148 stats.assets.forEach(function(asset) {
149 m.addFile('./.test/' + asset.name);
150 });
151 m.run();
152
153 // we want to remove these from the require cache while we have path
154 // references to them to ensure they get tested on the next rebuild
155 m.files.forEach(function(filePath) {
156 delete require.cache[require.resolve(path.resolve(filePath))];
157 });
158 }
159});
160
161// Hacky way to handle webpacks file output
162process.on('SIGINT', function() {
163 if (argv.runTest) {
164 var testDirectory = configs.DefaultTestingConfig.webpack.output.path;
165 rimraf(path.resolve(testDirectory), {}, process.exit);
166 } else {
167 process.exit();
168 }
169});