1 | #!/usr/bin/env node
|
2 | 'use strict';
|
3 |
|
4 | const meow = require('meow');
|
5 | const chalk = require('chalk');
|
6 | const path = require('path');
|
7 | const fs = require('fs');
|
8 | const batfishLog = require('../dist/node/batfish-log');
|
9 | const start = require('../dist/node/start');
|
10 | const build = require('../dist/node/build');
|
11 | const serveStatic = require('../dist/node/serve-static');
|
12 | const writeBabelrc = require('../dist/node/write-babelrc');
|
13 | const getLoggableErrorMessage = require('../dist/node/get-loggable-error-message');
|
14 | const renderPrettyErrorStack = require('../dist/node/render-pretty-error-stack');
|
15 | const constants = require('../dist/node/constants');
|
16 |
|
17 | const commands = {
|
18 | start,
|
19 | build,
|
20 | 'serve-static': serveStatic,
|
21 | 'write-babelrc': writeBabelrc
|
22 | };
|
23 |
|
24 | const description = `Build websites with batfish.`;
|
25 | const 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 |
|
86 | const 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 |
|
127 | const logCliError = (message) => {
|
128 | batfishLog.error(`${chalk.red.bold('CLI error:')} ${message}`);
|
129 | };
|
130 |
|
131 | const command = cli.input[0];
|
132 | if (command === undefined || commands[command] === undefined) {
|
133 | logCliError('You must specify a valid command.');
|
134 | cli.showHelp();
|
135 | }
|
136 |
|
137 | const isDefaultConfigPath = cli.flags.config === undefined;
|
138 | let configPath;
|
139 | if (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 |
|
147 | let config = {};
|
148 | if (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 |
|
172 | if (cli.flags.production) {
|
173 | config.production = cli.flags.production;
|
174 | } else if (command === 'build') {
|
175 | config.production = true;
|
176 | }
|
177 | if (cli.flags.debug) {
|
178 | config.production = !cli.flags.debug;
|
179 | }
|
180 | if (cli.flags.port) {
|
181 | config.port = cli.flags.port;
|
182 | }
|
183 | if (cli.flags.verbose) {
|
184 | config.verbose = cli.flags.verbose;
|
185 | }
|
186 | if (cli.flags.stats) {
|
187 | config.webpackStats = true;
|
188 | }
|
189 | if (command === 'start' && cli.flags.include) {
|
190 | config.includePages = [].concat(cli.flags.include);
|
191 | }
|
192 | if (cli.flags.clear === false) {
|
193 | config.clearOutputDirectory = false;
|
194 | }
|
195 | if (command === 'start' && cli.flags.browsers) {
|
196 | config.devBrowserslist =
|
197 | cli.flags.browsers === 'false' ? false : cli.flags.browsers;
|
198 | }
|
199 |
|
200 | const 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 | })();
|