diff --git a/docs/api/README.md b/docs/api/README.md index 730b18e..df68898 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -38,10 +38,10 @@ path is specified, it will be resolved relative to `process.cwd()`; absolute pat ```js new Neutrino({ // if not specified, defaults to process.cwd() - + // relative, resolves to process.cwd() + ./website root: './website', - + // absolute root: '/code/website' }) @@ -55,10 +55,10 @@ If a relative path is specified, it will be resolved relative to `options.root`; ```js new Neutrino({ // if not specified, defaults to options.root + src - + // relative, resolves to options.root + ./lib source: './lib', - + // absolute source: '/code/website/lib' }) @@ -72,10 +72,10 @@ If a relative path is specified, it will be resolved relative to `options.root`; ```js new Neutrino({ // if not specified, defaults to options.root + build - + // relative, resolves to options.root + ./dist output: './dist', - + // absolute output: '/code/website/dist' }) @@ -89,10 +89,10 @@ If a relative path is specified, it will be resolved relative to `options.root`; ```js new Neutrino({ // if not specified, defaults to options.root + test - + // relative, resolves to options.root + ./testing tests: './testing', - + // absolute tests: '/code/website/testing' }) @@ -106,10 +106,10 @@ If a relative path is specified, it will be resolved relative to `options.source ```js new Neutrino({ // if not specified, defaults to options.source + index.js - + // relative, resolves to options.source + ./entry.js entry: './entry.js', - + // absolute entry: '/code/website/lib/entry.js' }) @@ -124,10 +124,10 @@ used as-is. ```js new Neutrino({ // if not specified, defaults to options.root + node_modules - + // relative, resolves to options.root + ./modules node_modules: './modules', - + // absolute node_modules: '/code/website/modules' }) @@ -325,53 +325,3 @@ neutrino.on('custom-event', (args, payload) => { }); ``` - -### `handleErrors(err, stats)` - -This method is used internally to create a consistent console output when errors occur in the build. It will -log the `err` property and any errors from `stats` if applicable, and return `true` or `false` depending on if there -_were_ errors. - -This method returns a Boolean. - -```js -const failed = api.handleErrors(err, stats); - -if (failed) { - console.log('The build failed!'); -} -``` - -### `devServer()` - -This method is used internally to generate an instance of webpack-dev-server when using `start()`. It returns a promise -that resolves when the process receives a `SIGINT` event to stop. - -```js -api - .devServer() - .then(() => console.log('Exiting process...')); -``` - -### `builder()` - -This method is used internally to generate an instance of a Webpack compiler when using `build()`. It returns a promise -that resolves when the Webpack build has completed, or rejects if the build fails. - -```js -api - .builder() - .then(() => console.log('Exiting process...')) - .catch(() => console.error('Build failed!')); -``` - -### `watcher()` - -This method is used internally to generate an instance of a Webpack source watcher when using `start()`. It returns a promise -that resolves when the process receives a `SIGINT` event to stop and the watcher has closed. - -```js -api - .watcher() - .then(() => console.log('Exiting process, done watching...')); -``` diff --git a/packages/neutrino/src/neutrino.js b/packages/neutrino/src/neutrino.js index 9f1d40e..a3c9ba8 100644 --- a/packages/neutrino/src/neutrino.js +++ b/packages/neutrino/src/neutrino.js @@ -1,16 +1,16 @@ const { join, isAbsolute } = require('path'); const { EventEmitter } = require('events'); -const DevServer = require('webpack-dev-server'); -const webpack = require('webpack'); const Config = require('webpack-chain'); -const ora = require('ora'); const merge = require('deepmerge'); -const { defaultTo } = require('ramda'); +const { defaultTo, identity } = require('ramda'); const requireMiddleware = require('./requireMiddleware'); +const build = require('./webpack/build'); +const develop = require('./webpack/develop'); +const watch = require('./webpack/watch'); const normalizePath = (path, root) => (isAbsolute(path) ? path : join(root, path)); -class Neutrino extends EventEmitter { +module.exports = class Neutrino extends EventEmitter { constructor(options = {}) { super(); @@ -37,27 +37,6 @@ class Neutrino extends EventEmitter { return requireMiddleware(middleware, this.options); } - handleErrors(err, stats) { - if (err) { - console.error(err.stack || err); - - if (err.details) { - console.error(err.details); - } - - return true; - } - - const jsonStats = stats.toJson(); - - if (jsonStats.errors.length) { - jsonStats.errors.map(err => console.error(err)); - return true; - } - - return false; - } - getWebpackConfig() { return this.config.toConfig(); } @@ -67,18 +46,18 @@ class Neutrino extends EventEmitter { } build(args) { - return this.runCommand('build', args, () => this.builder()); + return this.runCommand('build', args, build); } start(args) { - return this.runCommand('start', args, () => (this.getWebpackOptions().devServer ? this.devServer() : this.watcher())); + return this.runCommand('start', args, this.getWebpackConfig().devServer ? develop : watch); } test(args) { return this.runCommand('test', args); } - runCommand(command, args = {}, fn) { + runCommand(command, args = {}, fn = identity) { process.env.NODE_ENV = defaultTo({ build: 'production', start: 'development', @@ -87,74 +66,7 @@ class Neutrino extends EventEmitter { return this .emitForAll(`pre${command}`, args) - .then(fn) + .then(() => fn(this.getWebpackConfig())) .then(() => this.emitForAll(command, args)); } - - devServer() { - return new Promise((resolve) => { - const starting = ora('Starting development server').start(); - const config = this.getWebpackOptions(); - const protocol = config.devServer.https ? 'https' : 'http'; - const host = config.devServer.host || 'localhost'; - const port = config.devServer.port || 5000; - - config.devServer.noInfo = true; - - const compiler = webpack(config); - const server = new DevServer(compiler, config.devServer); - const building = ora('Waiting for initial build to finish').start(); - - process.on('SIGINT', resolve); - server.listen(port, host, () => { - starting.succeed(`Development server running on: ${protocol}://${host}:${port}`); - compiler.plugin('compile', () => { - building.text = 'Source changed, re-compiling'; - building.start(); - }); - compiler.plugin('done', () => building.succeed('Build completed')); - }); - }); - } - - watcher() { - return new Promise((resolve) => { - const building = ora('Waiting for initial build to finish').start(); - const config = this.getWebpackOptions(); - const compiler = webpack(config); - const watcher = compiler.watch(config.watchOptions || {}, (err, stats) => { - building.succeed('Build completed'); - this.handleErrors(err, stats); - }); - - process.on('SIGINT', () => watcher.close(resolve)); - }); - } - - builder() { - return new Promise((resolve, reject) => { - const config = this.getWebpackOptions(); - const compiler = webpack(config); - - // eslint-disable-next-line consistent-return - compiler.run((err, stats) => { - const failed = this.handleErrors(err, stats); - - if (failed) { - return reject(); - } - - // eslint-disable-next-line no-console - console.log(stats.toString({ - colors: true, - chunks: false, - children: false - })); - - resolve(); - }); - }); - } } - -module.exports = Neutrino; diff --git a/packages/neutrino/src/webpack/build.js b/packages/neutrino/src/webpack/build.js new file mode 100644 index 0000000..cbf3f27 --- /dev/null +++ b/packages/neutrino/src/webpack/build.js @@ -0,0 +1,10 @@ +const webpack = require('webpack'); +const { handle, logErrors, logStats } = require('./utils'); + +module.exports = config => new Promise((resolve, reject) => { + const compiler = webpack(config); + + compiler.run(handle((errors, stats) => ( + errors.length ? reject(logErrors(errors)) : resolve(logStats(stats)) + ))); +}); diff --git a/packages/neutrino/src/webpack/develop.js b/packages/neutrino/src/webpack/develop.js new file mode 100644 index 0000000..d2627f3 --- /dev/null +++ b/packages/neutrino/src/webpack/develop.js @@ -0,0 +1,28 @@ +const ora = require('ora'); +const merge = require('deepmerge'); +const webpack = require('webpack'); +const DevServer = require('webpack-dev-server'); + +module.exports = _config => new Promise((resolve) => { + const defaultDevServer = { host: 'localhost', port: 5000, noInfo: true }; + const config = merge({ deverServer: defaultDevServer }, _config); + const protocol = config.devServer.https ? 'https' : 'http'; + const { host, port } = config.devServer; + + const starting = ora('Starting development server').start(); + const compiler = webpack(config); + const server = new DevServer(compiler, config.devServer); + const building = ora('Waiting for initial build to finish').start(); + + server.listen(port, host, () => { + starting.succeed(`Development server running on: ${protocol}://${host}:${port}`); + + compiler.plugin('done', () => building.succeed('Build completed')); + compiler.plugin('compile', () => { + building.text = 'Source changed, re-compiling'; + building.start(); + }); + }); + + process.on('SIGINT', resolve); +}); diff --git a/packages/neutrino/src/webpack/utils.js b/packages/neutrino/src/webpack/utils.js new file mode 100644 index 0000000..780b2ec --- /dev/null +++ b/packages/neutrino/src/webpack/utils.js @@ -0,0 +1,22 @@ +module.exports.handle = fn => (err, stats) => fn(err ? [err] : stats.toJson().errors, stats); + +module.exports.logStats = (stats) => { + console.log(stats.toString({ + colors: true, + chunks: false, + children: false + })); + + return stats; +}; + +module.exports.logErrors = (errors) => { + errors.forEach((err) => { + console.error(err.stack || err); + if (err.details) { + console.error(err.details); + } + }); + + return errors; +}; diff --git a/packages/neutrino/src/webpack/watch.js b/packages/neutrino/src/webpack/watch.js new file mode 100644 index 0000000..a65606e --- /dev/null +++ b/packages/neutrino/src/webpack/watch.js @@ -0,0 +1,15 @@ +const webpack = require('webpack'); +const ora = require('ora'); +const { handle, logErrors } = require('./utils'); + +module.exports = config => new Promise((resolve) => { + const compiler = webpack(config); + const building = ora('Waiting for initial build to finish').start(); + + const watcher = compiler.watch(config.watchOptions || {}, handle((errors) => { + building.succeed('Build completed'); + logErrors(errors); + })); + + process.on('SIGINT', () => watcher.close(resolve)); +});