@mapbox/batfish
Version:
The React-powered static-site generator you didn't know you wanted
229 lines (208 loc) • 6.43 kB
JavaScript
#!/usr/bin/env node
'use strict';
const meow = require('meow');
const chalk = require('chalk');
const path = require('path');
const fs = require('fs');
const batfishLog = require('../dist/node/batfish-log');
const start = require('../dist/node/start');
const build = require('../dist/node/build');
const serveStatic = require('../dist/node/serve-static');
const writeBabelrc = require('../dist/node/write-babelrc');
const getLoggableErrorMessage = require('../dist/node/get-loggable-error-message');
const renderPrettyErrorStack = require('../dist/node/render-pretty-error-stack');
const constants = require('../dist/node/constants');
const commands = {
start,
build,
'serve-static': serveStatic,
'write-babelrc': writeBabelrc
};
const description = `Build websites with batfish.`;
const help = `
${chalk.bold('Usage')}
batfish <command> [options]
You must provide a batfish configuration module, either with
batish.config.js in process.cwd() or with the --config option.
${chalk.bold('Commands')}
start Start a development server.
build Build the static site.
serve-static Serve the static site.
write-babelrc Write a .babelrc file that other processes,
like your test runner, can use.
${chalk.bold('Shared options')}
-c, --config Path to your configuration module.
Default: batfish.config.js
-V, --verbose Log extra stats.
${chalk.bold(`${chalk.magenta('start')} options`)}
-p, --port Server port. Default: 8080.
-i, --include Build only the specified page(s). Value
is a glob relative to the root of your site.
--production Build as though for production.
--no-clear Do not clear the destination directory.
-b, --browsers A comma-separated browserslist string
specifying the browsers you want to support
during this dev build. Or "false" if you
want to support all your production browsers.
${chalk.bold(`${chalk.magenta('build')} options`)}
-d, --debug Build for debugging, not for production.
--no-clear Do not clear the destination directory.
-s, --stats Generate Webpack statistics.
${chalk.bold(`${chalk.magenta('serve-static')} options`)}
-p, --port Server port. Default: 8080.
${chalk.bold(`${chalk.magenta('write-babelrc')} options`)}
--target "node" or "browser". Default: "node".
--dir Directory where .babelrc should be written.
Default: same directory as Batfish config.
${chalk.bold('Examples')}
No options are required for any command.
${chalk.cyan('batfish start')}
${chalk.cyan('batfish build')}
${chalk.cyan('batfish serve-static')}
${chalk.cyan('batfish write-babelrc')}
Build with your Batfish config in a special place.
${chalk.cyan('batfish build -c conf/bf.js')}
Start with an alternate port.
${chalk.cyan('batfish start -p 9966')}
Start but only build the /about pages.
${chalk.cyan('batfish start -i about/**')}
Start but only build the /about/history page.
${chalk.cyan('batfish start --include about/history')}
Start and build only for Chrome 60+.
${chalk.cyan('batfish start --browsers "Chrome >= 60"')}
`;
const cli = meow({
description,
help,
flags: {
config: {
type: 'string',
alias: 'c'
},
verbose: {
type: 'boolean',
alias: 'V'
},
stats: {
type: 'boolean',
alias: 's'
},
port: {
type: 'number',
alias: 'p'
},
debug: {
type: 'boolean',
alias: 'd'
},
target: {
type: 'string'
},
dir: {
type: 'string'
},
include: {
type: 'string',
alias: 'i'
},
browsers: {
type: 'string',
alias: 'b'
}
}
});
const logCliError = (message) => {
batfishLog.error(`${chalk.red.bold('CLI error:')} ${message}`);
};
const command = cli.input[0];
if (command === undefined || commands[command] === undefined) {
logCliError('You must specify a valid command.');
cli.showHelp();
}
const isDefaultConfigPath = cli.flags.config === undefined;
let configPath;
if (cli.flags.config) {
configPath = path.isAbsolute(cli.flags.config)
? cli.flags.config
: path.join(process.cwd(), cli.flags.config);
} else {
configPath = path.join(process.cwd(), 'batfish.config.js');
}
let config = {};
if (configPath) {
try {
if (fs.existsSync(configPath)) {
const configModule = require(configPath);
if (typeof configModule !== 'function') {
logCliError(
'Your configuration module must export a function that returns an object.'
);
process.exit(2);
}
config = configModule();
}
} catch (error) {
if (!isDefaultConfigPath) {
logCliError(
`Failed to load configuration module from ${chalk.underline(
configPath
)}`
);
}
throw error;
}
}
if (cli.flags.production) {
config.production = cli.flags.production;
} else if (command === 'build') {
config.production = true;
}
if (cli.flags.debug) {
config.production = !cli.flags.debug;
}
if (cli.flags.port) {
config.port = cli.flags.port;
}
if (cli.flags.verbose) {
config.verbose = cli.flags.verbose;
}
if (cli.flags.stats) {
config.webpackStats = true;
}
if (command === 'start' && cli.flags.include) {
config.includePages = [].concat(cli.flags.include);
}
if (cli.flags.clear === false) {
config.clearOutputDirectory = false;
}
if (command === 'start' && cli.flags.browsers) {
config.devBrowserslist =
cli.flags.browsers === 'false' ? false : cli.flags.browsers;
}
const projectDirectory = path.dirname(configPath);
(() => {
if (command === 'write-babelrc') {
writeBabelrc(config, {
projectDirectory,
outputDirectory: cli.flags.dir,
target: cli.flags.target
});
return;
}
const executeCommand = commands[command];
const emitter = executeCommand(config, projectDirectory);
emitter.on(constants.EVENT_NOTIFICATION, (message) => {
batfishLog.log(message);
});
emitter.on(constants.EVENT_ERROR, (error) => {
const niceMessage = getLoggableErrorMessage(error);
if (niceMessage) {
batfishLog.error(niceMessage);
} else {
batfishLog.error(renderPrettyErrorStack(error));
}
if (command !== 'start') {
process.exit(1);
}
});
})();