UNPKG

6.43 kBJavaScriptView Raw
1#!/usr/bin/env node
2'use strict';
3
4const meow = require('meow');
5const chalk = require('chalk');
6const path = require('path');
7const fs = require('fs');
8const batfishLog = require('../dist/node/batfish-log');
9const start = require('../dist/node/start');
10const build = require('../dist/node/build');
11const serveStatic = require('../dist/node/serve-static');
12const writeBabelrc = require('../dist/node/write-babelrc');
13const getLoggableErrorMessage = require('../dist/node/get-loggable-error-message');
14const renderPrettyErrorStack = require('../dist/node/render-pretty-error-stack');
15const constants = require('../dist/node/constants');
16
17const commands = {
18 start,
19 build,
20 'serve-static': serveStatic,
21 'write-babelrc': writeBabelrc
22};
23
24const description = `Build websites with batfish.`;
25const help = `
26${chalk.bold('Usage')}
27 batfish <command> [options]
28
29 You must provide a batfish configuration module, either with
30 batish.config.js in process.cwd() or with the --config option.
31
32${chalk.bold('Commands')}
33 start Start a development server.
34 build Build the static site.
35 serve-static Serve the static site.
36 write-babelrc Write a .babelrc file that other processes,
37 like your test runner, can use.
38
39${chalk.bold('Shared options')}
40 -c, --config Path to your configuration module.
41 Default: batfish.config.js
42 -V, --verbose Log extra stats.
43
44${chalk.bold(`${chalk.magenta('start')} options`)}
45 -p, --port Server port. Default: 8080.
46 -i, --include Build only the specified page(s). Value
47 is a glob relative to the root of your site.
48 --production Build as though for production.
49 --no-clear Do not clear the destination directory.
50 -b, --browsers A comma-separated browserslist string
51 specifying the browsers you want to support
52 during this dev build. Or "false" if you
53 want to support all your production browsers.
54
55${chalk.bold(`${chalk.magenta('build')} options`)}
56 -d, --debug Build for debugging, not for production.
57 --no-clear Do not clear the destination directory.
58 -s, --stats Generate Webpack statistics.
59
60${chalk.bold(`${chalk.magenta('serve-static')} options`)}
61 -p, --port Server port. Default: 8080.
62
63${chalk.bold(`${chalk.magenta('write-babelrc')} options`)}
64 --target "node" or "browser". Default: "node".
65 --dir Directory where .babelrc should be written.
66 Default: same directory as Batfish config.
67
68${chalk.bold('Examples')}
69 No options are required for any command.
70 ${chalk.cyan('batfish start')}
71 ${chalk.cyan('batfish build')}
72 ${chalk.cyan('batfish serve-static')}
73 ${chalk.cyan('batfish write-babelrc')}
74 Build with your Batfish config in a special place.
75 ${chalk.cyan('batfish build -c conf/bf.js')}
76 Start with an alternate port.
77 ${chalk.cyan('batfish start -p 9966')}
78 Start but only build the /about pages.
79 ${chalk.cyan('batfish start -i about/**')}
80 Start but only build the /about/history page.
81 ${chalk.cyan('batfish start --include about/history')}
82 Start and build only for Chrome 60+.
83 ${chalk.cyan('batfish start --browsers "Chrome >= 60"')}
84`;
85
86const cli = meow({
87 description,
88 help,
89 flags: {
90 config: {
91 type: 'string',
92 alias: 'c'
93 },
94 verbose: {
95 type: 'boolean',
96 alias: 'V'
97 },
98 stats: {
99 type: 'boolean',
100 alias: 's'
101 },
102 port: {
103 type: 'number',
104 alias: 'p'
105 },
106 debug: {
107 type: 'boolean',
108 alias: 'd'
109 },
110 target: {
111 type: 'string'
112 },
113 dir: {
114 type: 'string'
115 },
116 include: {
117 type: 'string',
118 alias: 'i'
119 },
120 browsers: {
121 type: 'string',
122 alias: 'b'
123 }
124 }
125});
126
127const logCliError = (message) => {
128 batfishLog.error(`${chalk.red.bold('CLI error:')} ${message}`);
129};
130
131const command = cli.input[0];
132if (command === undefined || commands[command] === undefined) {
133 logCliError('You must specify a valid command.');
134 cli.showHelp();
135}
136
137const isDefaultConfigPath = cli.flags.config === undefined;
138let configPath;
139if (cli.flags.config) {
140 configPath = path.isAbsolute(cli.flags.config)
141 ? cli.flags.config
142 : path.join(process.cwd(), cli.flags.config);
143} else {
144 configPath = path.join(process.cwd(), 'batfish.config.js');
145}
146
147let config = {};
148if (configPath) {
149 try {
150 if (fs.existsSync(configPath)) {
151 const configModule = require(configPath);
152 if (typeof configModule !== 'function') {
153 logCliError(
154 'Your configuration module must export a function that returns an object.'
155 );
156 process.exit(2);
157 }
158 config = configModule();
159 }
160 } catch (error) {
161 if (!isDefaultConfigPath) {
162 logCliError(
163 `Failed to load configuration module from ${chalk.underline(
164 configPath
165 )}`
166 );
167 }
168 throw error;
169 }
170}
171
172if (cli.flags.production) {
173 config.production = cli.flags.production;
174} else if (command === 'build') {
175 config.production = true;
176}
177if (cli.flags.debug) {
178 config.production = !cli.flags.debug;
179}
180if (cli.flags.port) {
181 config.port = cli.flags.port;
182}
183if (cli.flags.verbose) {
184 config.verbose = cli.flags.verbose;
185}
186if (cli.flags.stats) {
187 config.webpackStats = true;
188}
189if (command === 'start' && cli.flags.include) {
190 config.includePages = [].concat(cli.flags.include);
191}
192if (cli.flags.clear === false) {
193 config.clearOutputDirectory = false;
194}
195if (command === 'start' && cli.flags.browsers) {
196 config.devBrowserslist =
197 cli.flags.browsers === 'false' ? false : cli.flags.browsers;
198}
199
200const projectDirectory = path.dirname(configPath);
201
202(() => {
203 if (command === 'write-babelrc') {
204 writeBabelrc(config, {
205 projectDirectory,
206 outputDirectory: cli.flags.dir,
207 target: cli.flags.target
208 });
209 return;
210 }
211
212 const executeCommand = commands[command];
213 const emitter = executeCommand(config, projectDirectory);
214 emitter.on(constants.EVENT_NOTIFICATION, (message) => {
215 batfishLog.log(message);
216 });
217 emitter.on(constants.EVENT_ERROR, (error) => {
218 const niceMessage = getLoggableErrorMessage(error);
219 if (niceMessage) {
220 batfishLog.error(niceMessage);
221 } else {
222 batfishLog.error(renderPrettyErrorStack(error));
223 }
224 if (command !== 'start') {
225 process.exit(1);
226 }
227 });
228})();