@mapbox/batfish
Version:
The React-powered static-site generator you didn't know you wanted
131 lines (120 loc) • 4.44 kB
JavaScript
//
;
const _ = require('lodash');
const path = require('path');
const EventEmitter = require('events');
const createWebpackConfigClient = require('./create-webpack-config-client');
const createWebpackConfigStatic = require('./create-webpack-config-static');
const validateConfig = require('./validate-config');
const inlineCss = require('./inline-css');
const generateSitemap = require('./generate-sitemap');
const compileStylesheets = require('./compile-stylesheets');
const constants = require('./constants');
const maybeClearOutputDirectory = require('./maybe-clear-output-directory');
const copyNonPageFiles = require('./copy-non-page-files');
const writeWebpackStats = require('./write-webpack-stats');
const buildHtml = require('./build-html');
const webpackCompilePromise = require('./webpack-compile-promise');
function build(rawConfig , projectDirectory ) {
// Default production to true when building.
rawConfig = Object.assign({ production: true }, rawConfig);
const emitter = new EventEmitter();
const emitError = (error ) => {
emitter.emit(constants.EVENT_ERROR, error);
};
const emitNotification = (message ) => {
emitter.emit(constants.EVENT_NOTIFICATION, message);
};
let batfishConfig;
try {
batfishConfig = validateConfig(rawConfig, projectDirectory);
} catch (configValidationError) {
// setImmediate allows us to return the emitter before emitting the error.
setImmediate(() => {
emitError(configValidationError);
});
return emitter;
}
const stylesheetsIsEmpty = _.isEmpty(batfishConfig.stylesheets);
const outputDirectory = batfishConfig.outputDirectory;
const assetsDirectory = path.join(
outputDirectory,
batfishConfig.publicAssetsPath
);
// For the static build, put everything Webpack makes in an assets/ subdirectory.
const tailoredBatfishConfig = Object.assign({}, batfishConfig, {
outputDirectory: assetsDirectory
});
const buildClient = () => {
return createWebpackConfigClient(tailoredBatfishConfig)
.then(webpackCompilePromise)
.then(stats => {
return writeWebpackStats(outputDirectory, stats);
});
};
const buildStatic = () => {
return createWebpackConfigStatic(tailoredBatfishConfig).then(
webpackCompilePromise
);
};
// The compiled CSS filename will differ depending on whether this is a
// production build or not. So it needs to be a variable.
let cssFilename;
maybeClearOutputDirectory(batfishConfig)
.then(() => {
if (stylesheetsIsEmpty) return;
emitNotification('Compiling CSS.');
return compileStylesheets(batfishConfig, assetsDirectory).then(
filename => {
cssFilename = filename;
}
);
})
.then(() => {
emitNotification('Starting the Webpack bundling.');
emitNotification('Creating the client bundle.');
return buildClient();
})
.then(() => {
emitNotification('Creating the static-page-rendering Node bundle.');
return buildStatic();
})
.then(() => {
emitNotification('Copying unprocessed files.');
return copyNonPageFiles(batfishConfig);
})
.then(() => {
emitNotification('Building HTML.');
return buildHtml(batfishConfig, cssFilename);
})
.then(() => {
if (!batfishConfig.production) return;
return new Promise((resolve, reject) => {
// This line within the callback function scope to please Flow about
// the cssFilename variable.
if (stylesheetsIsEmpty || !cssFilename) return resolve();
const inlineCssEmitter = inlineCss(outputDirectory, cssFilename, {
verbose: batfishConfig.verbose
});
inlineCssEmitter.on(constants.EVENT_NOTIFICATION, emitNotification);
inlineCssEmitter.on(constants.EVENT_ERROR, reject);
inlineCssEmitter.on(constants.EVENT_DONE, resolve);
});
})
.then(() => {
if (batfishConfig.siteOrigin) {
emitNotification('Building the sitemap.');
return generateSitemap(batfishConfig);
} else {
emitNotification(
'siteOrigin is not specified; unable to generate sitemap.'
);
}
})
.then(() => {
emitter.emit(constants.EVENT_DONE);
})
.catch(emitError);
return emitter;
}
module.exports = build;