#!/usr/bin/env node
const path = require('path');
const chalk = require('chalk');
const browserSync = require('browser-sync').create();
const bsConfig = require('./bs-config');
// ********************************** JAVASCRIPT **********************************
// webpack watch task always performs an intial bundle, and we don't want browsersync
// listening at the point. so we use this flag to know whether any change webpack reports
// is the initial bundle, or subsequent file changes
let INITIAL_BUNDLE = true;
// just a bit of visual feedback while webpack creates its initial bundles.
// fakes a listr step
const ora = require('ora');
const wpNotification = ora({
text: 'Create initial webpack bundles',
color: 'yellow',
});
wpNotification.start();
const webpack = require('webpack');
const webpackBundler = webpack(require('../webpack.config.dev.js'));
webpackBundler.watch(
{
ignored: /node_modules/,
},
(err, stats) => {
if (err) {
// log any unexpected error
console.log(chalk.red(err));
}
if (INITIAL_BUNDLE) {
INITIAL_BUNDLE = false;
wpNotification.succeed();
// now have the initial bundles, we can start browsersync
return browserSync.init(bsConfig);
}
const info = stats.toJson();
// send editing errors to console and browser
if (stats.hasErrors()) {
console.log(chalk.red(info.errors));
return browserSync.sockets.emit('fullscreen:message', {
title: 'Webpack Error:',
body: info.errors,
timeout: 100000,
});
}
if (stats.hasWarnings()) {
console.warn(chalk.yellow(info.warnings));
}
// announce the changes
return browserSync.reload();
}
);
// ********************************** Sass **********************************
const chokidar = require('chokidar');
const sassDir = path.resolve(__dirname, '../', 'static', 'src', 'stylesheets');
const sassGraph = require('sass-graph').parseDir(sassDir, {
loadPaths: [sassDir],
});
const compileSass = require('../tools/compile-css');
// when we detect a change in a sass file, we look up the tree of imports
// and only compile what we need to. anything matching this regex, we can just ignore in dev.
const ignoredSassRegEx = /^(_|ie9|old-ie)/;
chokidar.watch(`${sassDir}/**/*.scss`).on('change', changedFile => {
// see what top-level files need to be recompiled
const filesToCompile = [];
const changedFileBasename = path.basename(changedFile);
sassGraph.visitAncestors(changedFile, ancestorPath => {
const ancestorFileName = path.basename(ancestorPath);
if (!ignoredSassRegEx.test(ancestorFileName)) {
filesToCompile.push(ancestorFileName);
}
});
if (!/^_/.test(changedFileBasename)) {
filesToCompile.push(changedFileBasename);
}
// now recompile all files that matter
Promise.all(filesToCompile.map(compileSass))
.then(() => {
// clear any previous error messages
browserSync.sockets.emit('fullscreen:message:clear');
// announce the changes
browserSync.reload(
filesToCompile.map(file => file.replace('scss', 'css'))
);
})
.catch(e => {
// send editing errors to console and browser
console.log(chalk.red(`\n${e.formatted}`));
browserSync.sockets.emit('fullscreen:message', {
title: 'CSS Error:',
body: e.formatted,
timeout: 100000,
});
});
});