Skip to content
This repository has been archived by the owner on Apr 8, 2019. It is now read-only.

Commit

Permalink
Lots of misc (#47)
Browse files Browse the repository at this point in the history
* improving event bus tests, throwing on invalid options

* fix: configs with partial defaults should be valid

* add host option to getPort call to ensure correct results

* remove webpack 3 test

* update package lock

* add docs for on and add options

* improve object detection and bus test
  • Loading branch information
shellscape committed Mar 6, 2018
1 parent c492f55 commit 3bd62dc
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 47 deletions.
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ Type: `Object`

Options for initializing and controlling the server provided.

##### add

Please see [Add-On Features](#add-on-features).

##### compiler

Type: `webpack`
Expand Down Expand Up @@ -269,6 +273,22 @@ Default: `false`
Instruct `webpack-serve` to prepend each line of log output with a `[HH:mm:ss]`
timestamp.

##### on

Type: `Object`
Default: `null`

While running `webpack-serve` from the command line, it can sometimes be useful
to subscribe to events from the module's event bus _within your config_. This
option can be used for that purpose. The option's value must be an `Object`
matching a `key:handler`, `String: Function` pattern. eg:

```js
on: {
'listening': () => { console.log('listening'); }
}
```

##### open

Type: `Boolean|Object`
Expand Down Expand Up @@ -318,7 +338,42 @@ features that those familiar with `webpack-dev-server` have come to rely on. Thi
makes the module far easier to maintain, which ultimately benefits the user.

Luckily, flexibility baked into `webpack-serve` makes it a snap to add-on features.
Listed below are some of the add-on patterns that can be found in
You can leverage this by using the `add` option. The value of the option should
be a `Function` matching the following signature:

```js
add: (app, middleware, options) => {
// ...
}
```

### `add` Function Parameters

- `app` The underlying Koa app
- `middleware` An object containing accessor functions to call both
`webpack-dev-middleware` and the `koa-static` middleware.
- `options` - The internal options object used by `webpack-serve`

Some add-on patterns may require changing the order of middleware used in the
`app`. For instance, if adding routes or using a separate router with the `app`
where routes must be added last, you'll need to call the `middleware` functions
early on. `webpack-serve` recognizes these calls and will not execute them again.
If these calls were omitted, `webpack-serve` would execute both in the default,
last in line, order.

```js
add: (app, middleware, options) => {
// since we're manipulating the order of middleware added, we need to handle
// adding these two internal middleware functions.
middleware.webpack();
middleware.content();

// router *must* be the last middleware added
app.use(router.routes());
}
```

Listed below are some of the add-on patterns and recipes that can be found in
[docs/addons](docs/addons):

- [bonjour](docs/addons/bonjour.config.js)
Expand Down
8 changes: 7 additions & 1 deletion lib/bus.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
'use strict';

const isPlainObject = require('lodash/isPlainObject');
const nanobus = require('nanobus');
const weblog = require('webpack-log');
const WebpackServeError = require('./WebpackServeError');

module.exports = (options) => {
const log = weblog({ name: 'serve', id: 'webpack-serve' });
const bus = nanobus();

if (typeof options.on === 'object') {
if (isPlainObject(options.on)) {
for (const event of Object.keys(options.on)) {
const fn = options.on[event];

if (typeof fn === 'function') {
log.info(`Subscribed to '${event}' event`);
bus.on(event, fn);
} else {
throw new WebpackServeError(`The value for an \`on\` event handler must be a Function. event: ${event}`);
}
}
} else if (options.on) {
throw new WebpackServeError('The value for the `on` option must be an Object. Please see the README.');
}

return bus;
Expand Down
4 changes: 4 additions & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ module.exports = {
toArray(config) {
if (typeof config.entry === 'string') {
config.entry = [config.entry];
} else if (typeof config.entry === 'undefined') {
// webpack v4 defaults an empty config to { entry: './src' }. but since we
// need an array, we'll mimic that default config.
config.entry = ['./src'];
} else if (isPlainObject(config.entry)) {
for (const key of Object.keys(config.entry)) {
const entry = config.entry[key];
Expand Down
5 changes: 1 addition & 4 deletions lib/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ const path = require('path');
const merge = require('lodash/merge');
const weblog = require('webpack-log');
const MultiCompiler = require('webpack/lib/MultiCompiler');
const webpackPackage = require('webpack/package.json');
const { fromFunction } = require('./config');

const webpackVersion = parseInt(webpackPackage.version, 10);

const defaults = {
clipboard: true,
compiler: null,
Expand Down Expand Up @@ -51,7 +48,7 @@ function resolve(options) {

// webpack v4 defaults an empty config to { entry: './src' }. but since we
// need an array, we'll mimic that default config.
if (webpackVersion > 3 && !options.config && (!options.flags || !options.flags.config)) {
if (!options.config && (!options.flags || !options.flags.config)) {
options.config = { entry: ['./src'] };
}

Expand Down
7 changes: 4 additions & 3 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ module.exports = (options) => {
const app = new Koa();
const { bus } = options;
const log = weblog({ name: 'serve', id: 'webpack-serve' });
const uri = `${options.protocol}://${options.host}:${options.port}`;
let http2;
let server;
let koaMiddleware;
Expand Down Expand Up @@ -90,6 +89,8 @@ module.exports = (options) => {
}

server.once('listening', () => {
const uri = `${options.protocol}://${options.host}:${options.port}`;

log.info(chalk`Project is running at {blue ${uri}}`);

if (options.clipboard) {
Expand All @@ -112,8 +113,8 @@ module.exports = (options) => {
});

return Promise.all([
getPort({ port: options.port }),
getPort({ port: options.hot.port || 8081 })
getPort({ port: options.port, host: options.host }),
getPort({ port: options.hot.port || 8081, host: options.host })
])
.then(([port, hotPort]) => {
options.port = port;
Expand Down
49 changes: 24 additions & 25 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/fixtures/basic/webpack.function.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const webpack = require('webpack');
// eslint-disable-next-line no-unused-vars
module.exports = function config(env, argv) {
return {
mode: 'development',
context: __dirname,
devtool: 'source-map',
entry: ['./app.js'],
Expand Down
17 changes: 17 additions & 0 deletions test/fixtures/webpack-4-defaults/webpack.no-entry.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

const path = require('path');
const webpack = require('webpack');

module.exports = {
mode: 'development',
context: __dirname,
output: {
filename: './output.js',
path: path.resolve(__dirname)
},
plugins: [
new webpack.NamedModulesPlugin()
],
serve: {}
};
Loading

0 comments on commit 3bd62dc

Please sign in to comment.