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 |
|
59 | ${chalk.bold(`${chalk.magenta('serve-static')} options`)}
|
60 | -p, --port Server port. Default: 8080.
|
61 |
|
62 | ${chalk.bold(`${chalk.magenta('write-babelrc')} options`)}
|
63 | --target "node" or "browser". Default: "node".
|
64 | --dir Directory where .babelrc should be written.
|
65 | Default: same directory as Batfish config.
|
66 |
|
67 | ${chalk.bold('Examples')}
|
68 | No options are required for any command.
|
69 | ${chalk.cyan('batfish start')}
|
70 | ${chalk.cyan('batfish build')}
|
71 | ${chalk.cyan('batfish serve-static')}
|
72 | ${chalk.cyan('batfish write-babelrc')}
|
73 | Build with your Batfish config in a special place.
|
74 | ${chalk.cyan('batfish build -c conf/bf.js')}
|
75 | Start with an alternate port.
|
76 | ${chalk.cyan('batfish start -p 9966')}
|
77 | Start but only build the /about pages.
|
78 | ${chalk.cyan('batfish start -i about/**')}
|
79 | Start but only build the /about/history page.
|
80 | ${chalk.cyan('batfish start --include about/history')}
|
81 | Start and build only for Chrome 60+.
|
82 | ${chalk.cyan('batfish start --browsers "Chrome >= 60"')}
|
83 | `;
|
84 |
|
85 | const cli = meow({
|
86 | description,
|
87 | help,
|
88 | flags: {
|
89 | config: {
|
90 | type: 'string',
|
91 | alias: 'c'
|
92 | },
|
93 | verbose: {
|
94 | type: 'boolean',
|
95 | alias: 'V'
|
96 | },
|
97 | port: {
|
98 | type: 'number',
|
99 | alias: 'p'
|
100 | },
|
101 | debug: {
|
102 | type: 'boolean',
|
103 | alias: 'd'
|
104 | },
|
105 | target: {
|
106 | type: 'string'
|
107 | },
|
108 | dir: {
|
109 | type: 'string'
|
110 | },
|
111 | include: {
|
112 | type: 'string',
|
113 | alias: 'i'
|
114 | },
|
115 | browsers: {
|
116 | type: 'string',
|
117 | alias: 'b'
|
118 | }
|
119 | }
|
120 | });
|
121 |
|
122 | const logCliError = (message) => {
|
123 | batfishLog.error(`${chalk.red.bold('CLI error:')} ${message}`);
|
124 | };
|
125 |
|
126 | const command = cli.input[0];
|
127 | if (command === undefined || commands[command] === undefined) {
|
128 | logCliError('You must specify a valid command.');
|
129 | cli.showHelp();
|
130 | }
|
131 |
|
132 | const isDefaultConfigPath = cli.flags.config === undefined;
|
133 | let configPath;
|
134 | if (cli.flags.config) {
|
135 | configPath = path.isAbsolute(cli.flags.config)
|
136 | ? cli.flags.config
|
137 | : path.join(process.cwd(), cli.flags.config);
|
138 | } else {
|
139 | configPath = path.join(process.cwd(), 'batfish.config.js');
|
140 | }
|
141 |
|
142 | let config = {};
|
143 | if (configPath) {
|
144 | try {
|
145 | if (fs.existsSync(configPath)) {
|
146 | const configModule = require(configPath);
|
147 | if (typeof configModule !== 'function') {
|
148 | logCliError(
|
149 | 'Your configuration module must export a function that returns an object.'
|
150 | );
|
151 | process.exit(2);
|
152 | }
|
153 | config = configModule();
|
154 | }
|
155 | } catch (error) {
|
156 | if (!isDefaultConfigPath) {
|
157 | logCliError(
|
158 | `Failed to load configuration module from ${chalk.underline(
|
159 | configPath
|
160 | )}`
|
161 | );
|
162 | }
|
163 | throw error;
|
164 | }
|
165 | }
|
166 |
|
167 | if (cli.flags.production) {
|
168 | config.production = cli.flags.production;
|
169 | } else if (command === 'build') {
|
170 | config.production = true;
|
171 | }
|
172 | if (cli.flags.debug) {
|
173 | config.production = !cli.flags.debug;
|
174 | }
|
175 | if (cli.flags.port) {
|
176 | config.port = cli.flags.port;
|
177 | }
|
178 | if (cli.flags.verbose) {
|
179 | config.verbose = cli.flags.verbose;
|
180 | }
|
181 | if (command === 'start' && cli.flags.include) {
|
182 | config.includePages = [].concat(cli.flags.include);
|
183 | }
|
184 | if (cli.flags.clear === false) {
|
185 | config.clearOutputDirectory = false;
|
186 | }
|
187 | if (command === 'start' && cli.flags.browsers) {
|
188 | config.devBrowserslist =
|
189 | cli.flags.browsers === 'false' ? false : cli.flags.browsers;
|
190 | }
|
191 |
|
192 | const projectDirectory = path.dirname(configPath);
|
193 |
|
194 | (() => {
|
195 | if (command === 'write-babelrc') {
|
196 | writeBabelrc(config, {
|
197 | projectDirectory,
|
198 | outputDirectory: cli.flags.dir,
|
199 | target: cli.flags.target
|
200 | });
|
201 | return;
|
202 | }
|
203 |
|
204 | const executeCommand = commands[command];
|
205 | const emitter = executeCommand(config, projectDirectory);
|
206 | emitter.on(constants.EVENT_NOTIFICATION, (message) => {
|
207 | batfishLog.log(message);
|
208 | });
|
209 | emitter.on(constants.EVENT_ERROR, (error) => {
|
210 | const niceMessage = getLoggableErrorMessage(error);
|
211 | if (niceMessage) {
|
212 | batfishLog.error(niceMessage);
|
213 | } else {
|
214 | batfishLog.error(renderPrettyErrorStack(error));
|
215 | }
|
216 | if (command !== 'start') {
|
217 | process.exit(1);
|
218 | }
|
219 | });
|
220 | })();
|