cogear
Version:
Cogear.JS – modern static websites generator (Node.JS/Webpack)
193 lines (190 loc) • 6.72 kB
JavaScript
const webpack = require('webpack');
const express = require('express');
const http = require('http');
// const { throttle, debounce } = require("throttle-debounce");
const path = require('path');
const fs = require('fs');
const chalk = require('chalk');
const date = ()=>{
return new Date().toISOString().replace(/.+T(.+?)\..+/,'$1');
};
module.exports = {
apply() {
cogear.on('webpack', async ({ mode }) => {
if (mode == 'development') {
await this.webpackDev();
}
});
cogear.on('build.done',()=>{
if('development' !== cogear.mode) return;
cogear.loader.succeed(
`Your site is running at ${chalk.bold.whiteBright(
'http://' + cogear.config.host + ':' + cogear.http.address().port
)} (${chalk.bold('development mode')})`
);
console.log('Press Ctrl+C to exit…');
this.watch();
});
cogear.on('preload.done', async() => {
if (cogear.mode == 'development') {
if(cogear.compiler) return;
try {
cogear.compiler = webpack(cogear.webpackConfig);
} catch (e){
cogear.loader.fail(chalk.red(e));
process.exit();
}
cogear.compiler.hooks.afterEmit.tap('Build pages', async compilation => {
cogear.compilation = compilation;
await cogear.emit('webpack.afterEmit', compilation);
});
cogear.compiler.hooks.done.tap('Webpack done', async stats => {
cogear.compilation = stats.compilation;
await cogear.emit('webpack.done', stats.compilation);
cogear.flags.webpackFirstDone = true; // Important. DO NOT DELETE
});
await this.runServer();
}
});
},
/**
* Webpack development mode
*/
async webpackDev() {
cogear.webpackConfig = require(path.join(cogear.baseDir, 'webpack.dev.js'));
await cogear.emit('webpack.config', cogear.webpackConfig);
await cogear.emit('preload');
},
async runServer() {
cogear.server = express();
cogear.devMiddleware = require('webpack-dev-middleware')(cogear.compiler, {
watchOptions: {
aggregateTimeout: 300,
poll: true
},
noInfo: !cogear.options.verbose,
logLevel: cogear.options.verbose ? 'debug' : 'silent',
stats: {
hash: !!cogear.options.verbose,
version: !!cogear.options.verbose,
timings: false,
assets: false,
chunks: false,
modules: false,
colors: true
},
overlay: true,
inline: true,
hot: true,
publicPath: cogear.webpackConfig.output.publicPath,
reload: true,
compress: true,
watchContentBase: false,
contentBase: cogear.themeDir
? [cogear.options.src, cogear.themeDir]
: [cogear.options.src]
});
cogear.hotMiddleware = require('webpack-hot-middleware')(cogear.compiler, {
overlay: true,
log: console.info,
heartbeat: 10 * 1000,
path: '/__webpack_hmr',
reload: true,
// log: () => {}
});
cogear.server.use(cogear.devMiddleware);
cogear.server.use(cogear.hotMiddleware);
cogear.server.use(express.static(cogear.options.output));
await cogear.emit('server.init');
cogear.server.on('error',(e)=>{
console.error(e.message);
console.info(e.stack);
});
cogear.http = http.createServer(cogear.server).listen(cogear.config.port, cogear.config.host, async err => {
if (err) {
cogear.loader.fail(err);
process.exit();
}
await cogear.emit('server.listen');
});
},
watch() {
let watchDirs = [
cogear.options.srcPages,
path.join(cogear.options.src, 'layouts'),
];
if (cogear.themeDir) watchDirs.push(path.join(cogear.themeDir, 'layouts'));
cogear.watcher = require('chokidar').watch(watchDirs.filter(dir=>fs.existsSync(dir)), {
ignorePermissionErrors: true,
ignored: /(^|[\/\\])\../,
// awaitWriteFinish: true,
ignoreInitial: true
});
let watcherLoaded = false;
cogear.watcher.on('ready', () => {
if (watcherLoaded) return; // Mac bug – double init
watcherLoaded = true;
// cogear.loader.info("Watching for changes…")
// If file is changed or added
process.on('SIGINT',()=>cogear.watcher.close());
cogear.watcher.on('change', async file => {
cogear.loader.info(
chalk.yellow(`[${date()}] Changed: ${this.clearFilename(file)}`)
);
await cogear.emit('watcher.change',file);
if (file.indexOf(cogear.options.srcPages) !== -1) {
let filePath = file.replace(path.join(cogear.options.srcPages,''), '');
await cogear.emit('build.page', filePath);
await cogear.emit('watcher.change.page',filePath);
cogear.hotMiddleware.publish({ action: 'reload' });
} else {
await this.rebuildAllPages();
}
});
// File is added
cogear.watcher.on('add', async file => {
cogear.loader.info(
chalk.yellow(`[${date()}] Added: ${this.clearFilename(file)}`)
);
await cogear.emit('watcher.change',file);
if (file.indexOf(cogear.options.srcPages) !== -1) {
let filePath = file.replace(path.join(cogear.options.srcPages,''), '');
await cogear.emit('build.page', filePath);
await cogear.emit('watcher.add.page',filePath);
cogear.hotMiddleware.publish({ action: 'reload' });
} else {
await this.rebuildAllPages();
}
});
// If file is deleted
cogear.watcher.on('unlink', async file => {
cogear.loader.info(
chalk.yellow(`[${date()}] Deleted: ${this.clearFilename(file)}`)
);
await cogear.emit('watcher.unlink',file);
if (file.indexOf(cogear.options.srcPages) !== -1) {
// let pageName = file.replace(cogear.options.srcPages + "/", "");
let result = Object.entries(cogear.pages).filter(([uri,page])=> page.filePath == file );
if(!result.length) return;
let [uri,page] = result.shift();
delete cogear.pages[uri];
fs.unlinkSync(path.join(cogear.options.output, page.path));
await cogear.emit('watcher.unlink.page',[file,page]);
cogear.hotMiddleware.publish({ action: 'reload' });
}
});
});
},
// Remote absolute paths from filename
clearFilename(file) {
return file
.replace(cogear.options.srcPages, '')
.replace(cogear.options.src, '')
.replace(cogear.themeDir, '');
},
// Rebuild all pages
async rebuildAllPages() {
await cogear.emit('rebuild');
cogear.hotMiddleware.publish({ action: 'reload' });
}
};