@viewdo/dxp-story-cli
Version:
README.md
275 lines (214 loc) • 8.22 kB
JavaScript
// NPM Module Dependencies
const webpack = require('webpack');
const deepmerge = require('deepmerge');
const jsonConfig = require('./config/json');
const { argv } = require('yargs');
const fs = require('fs');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { legacy = false, serve = false } = argv;
const mkdirp = require('mkdirp');
const server = require('./server');
// Change when we move this over to the CLI
const defaultEpisodeKey = process.env.DEFAULT_EPISODE_KEY || "default";
// Webpack Dependencies
const defaultConfig = require('./config/default');
const es2015Config = require('./config/es2018');
const hasFile = (filePath) => {
try {
fs.accessSync(filePath, fs.constants.F_OK);
return true;
} catch (err) {
return false;
}
}
// Private Methods
/**
* If the source's css file is not a css type, this will use the extension
* and add a rule to create the CSS using the transpiler.
* @param {String} buildCSSFile - Style file that will create the
* css
* @param {Object} cssExtractor - Instance of the Webpack's Text Extractor
* to pull the CSS File using this style compiler
*/
const _getStyleConfig = (source, episodeKey, cssExtractor) => {
const hasLess = hasFile(`${source}/${episodeKey}.less`);
if (hasLess) {
return require(`./config/less`)(cssExtractor);
}
return {};
}
/**
* Creates a custom webpack config file to run webpack over based on what the settings
* are found in the "source" object for this story.
*
* @param {Object} storyInfo - Information for this story to create the
* webpack config file
* @param {String} buildPath - Path to where the webpack files will be push to.
*/
const _createWebpackConfig = (sourcePath, buildPath, episodeKey, dev) => {
let cssFileName = "story.css";
if (legacy) {
cssFileName = "text-templates/compiled.css";
}
const cssExtractor = new ExtractTextPlugin(cssFileName);
const defaultWebpackConfig = defaultConfig(sourcePath, buildPath, episodeKey, cssExtractor, dev);
const styleConfig = _getStyleConfig(sourcePath, episodeKey, cssExtractor);
let modifiedConfig = deepmerge(defaultWebpackConfig, styleConfig);
// PROPOSAL: Add to the console different JS packages maybe like vue, es2018, jsx, etc.
modifiedConfig = deepmerge(modifiedConfig, es2015Config());
modifiedConfig.plugins = [...modifiedConfig.plugins, cssExtractor];
return modifiedConfig;
}
const _getWebpackConfigs = (story_keys, config, dev) => {
const {
stories,
output: outputPath,
source: sourcePath } = config
let buildPath = outputPath;
if (story_keys.length >= 1) {
return story_keys.reduce((configs, storyKey) => {
const { episodes = {} } = stories[storyKey];
const storyBuildPath = `${buildPath}/${storyKey}`;
const storySourcePath = `${sourcePath}/${storyKey}`;
mkdirp.sync(storyBuildPath);
const defaultEpisodeConfigs = [
_createWebpackConfig(storySourcePath, storyBuildPath, defaultEpisodeKey, dev),
jsonConfig(storySourcePath, storyBuildPath, defaultEpisodeKey, dev)
];
const episodeKeys = Object.keys(episodes);
const episodeConfigs = episodeKeys.reduce((currentEpisodeConfigs, episodeKey) => {
const episodeBuildPath = `${storyBuildPath}/episodes/${episodeKey}`;
mkdirp.sync(episodeBuildPath);
const episodeConfigs = [
_createWebpackConfig(storySourcePath, episodeBuildPath, episodeKey, dev),
jsonConfig(storySourcePath, episodeBuildPath, episodeKey, dev)
];
return [
...currentEpisodeConfigs,
...episodeConfigs
];
}, []);
return [
...configs,
...defaultEpisodeConfigs,
...episodeConfigs
];
}, []);
}
}
const _postBuild = (story_keys, config) => {
const {
output: outputPath,
stories,
source: sourcePath } = config;
story_keys.forEach((storyKey) => {
const { episodes = {} } = stories[storyKey];
const srcDirectory = `${sourcePath}/${storyKey}`;
const introStoryHtmlPath = `${srcDirectory}/story-intro.html`;
const storyBuildPath = `${outputPath}/${storyKey}`;
const cssFile = `${outputPath}/${storyKey}/story.css`;
const evaluatorPath = `${storyBuildPath}/_json-evaluator.js`;
// Clean up episode files.
const episodeKeys = Object.keys(episodes);
episodeKeys.forEach((episodeKey) => {
const episodeBuildPath = `${storyBuildPath}/episodes/${episodeKey}`;
const episodeEvaluatorPath = `${episodeBuildPath}/_json-evaluator.js`;
const episodeStoryCss = `${episodeBuildPath}/story.css`;
if (hasFile(episodeEvaluatorPath)) {
fs.unlinkSync(episodeEvaluatorPath);
}
if (!hasFile(cssFile)) {
fs.writeFileSync(episodeStoryCss, '');
}
});
if (hasFile(introStoryHtmlPath)) {
const introHtmlFile = fs.readFileSync(introStoryHtmlPath, 'utf-8');
fs.writeFileSync(`${storyBuildPath}/story-intro.html`, introHtmlFile);
}
if (!hasFile(cssFile)) {
fs.writeFileSync(cssFile, '');
}
if (hasFile(evaluatorPath)) {
fs.unlinkSync(evaluatorPath);
}
});
}
/**
* Creates a config and then runs webpack on the various config files for
* various stories.
* @param {Object} config - Settings defined in the dxp-config
*/
module.exports = {
build(story_keys, config) {
process.noDeprecation = true;
return new Promise((res, rej) => {
const webpackConfigs = _getWebpackConfigs(story_keys, config);
webpack(webpackConfigs).run((err, stats) => {
_postBuild(story_keys, config);
console.log(stats.toString({
colors: true
}));
if (stats.hasErrors()) {
rej(err);
return;
}
if (legacy) {
_runLegacyCompiling(console, webpackConfigs).then(() => {
res();
});
return;
}
res();
});
});
},
serve(config, dev) {
let {stories} = config
let story_keys = Object.keys(stories)
const webpackConfigs = _getWebpackConfigs(story_keys, config, dev);
currentServer = server(webpackConfigs, config);
},
watch(config, dev) {
let currentServer = {};
let init = true;
let {stories} = config
let story_keys = Object.keys(stories)
const webpackConfigs = _getWebpackConfigs(story_keys, config, dev);
if (serve) {
currentServer = server(webpackConfigs, config);
}
webpack(webpackConfigs).watch({}, (err, stats) => {
if (stats.hasErrors()) {
console.log(stats.toString({
colors: true
}));
return;
}
_postBuild(story_keys, _console);
if (currentServer.reload) {
currentServer.reload();
}
if (currentServer.openWindow && init) {
currentServer.openWindow();
init = false;
}
if (legacy) {
_runLegacyCompiling(console, webpackConfigs).then(() => {
console.log(stats.toString({
colors: true
}));
})
.catch((err) => {
console.log(err);
});
return;
}
console.log(stats.toString({
colors: true
}));
});
},
postBuild: (story_keys, config) => {
_postBuild(story_keys, config);
}
}