Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,12 @@ When the minimize button (yellow dot) is clicked, the overlay will shrink to a s
<img src="assets/status-beacons.gif" alt="status beacons"><br/><br/>
</div>

### `waitForBuild`
Type: `boolean`<br>
Default: `false`

If `true`, instructs the server to halt middleware processing until the current build is done.

## Proxying

Proxying with `webpack-plugin-serve` is supported via the [`middleware`](#middleware) option. But while this plugin module doesn't contain any fancy options processing for proxying, it does include access to the [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) module by default, and the rest should look familiar to users of `http-proxy-middleware`.
Expand Down
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ declare module 'webpack-plugin-serve' {
progress?: boolean | 'minimal';
static?: string | Array<string>;
status?: boolean;
waitForBuild?: boolean;
}

export class WebpackPluginServe {
Expand Down
23 changes: 19 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class WebpackPluginServe extends EventEmitter {
this.log = getLogger(options.log || {});
this.options = options;
this.compilers = [];
this.state = {};
}

apply(compiler) {
Expand Down Expand Up @@ -154,6 +155,20 @@ class WebpackPluginServe extends EventEmitter {
invalid.tap(key, (filePath) => this.emit('invalid', filePath, compiler));
watchClose.tap(key, () => this.emit('close', compiler));

if (this.options.waitForBuild) {
// track the first build of the bundle
this.state.compiling = new Promise((resolve) => {
this.once('done', () => resolve());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be shortened to this.once('done', resolve);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could :) in certain situations I like to be a bit more verbose.

});

// track subsequent builds from watching
this.on('invalid', () => {
this.state.compiling = new Promise((resolve) => {
this.once('done', () => resolve());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

});
});
}

compiler.hooks.compilation.tap(key, (compilation) => {
compilation.hooks.afterHash.tap(key, () => {
// webpack still has a 4 year old bug whereby in watch mode, file timestamps aren't properly
Expand All @@ -168,14 +183,14 @@ class WebpackPluginServe extends EventEmitter {
});

watchRun.tapPromise(key, async () => {
if (!this.startPromise) {
if (!this.state.starting) {
// ensure we're only trying to start the server once
this.startPromise = start.bind(this)();
this.startPromise.then(() => newline());
this.state.starting = start.bind(this)();
this.state.starting.then(() => newline());
}

// wait for the server to startup so we can get our client connection info from it
await this.startPromise;
await this.state.starting;
Comment thread
matheus1lva marked this conversation as resolved.

const compilerData = {
// only set the compiler name if we're dealing with more than one compiler. otherwise, the
Expand Down
9 changes: 8 additions & 1 deletion lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,19 @@ const start = async function start() {
}

const { app } = this;
const { host, middleware, port } = this.options;
const { host, middleware, port, waitForBuild } = this.options;
const builtins = getBuiltins(app, this.options);

this.options.host = await host;
this.options.port = await port;

if (waitForBuild) {
app.use(async (ctx, next) => {
await this.state.compiling;
await next();
});
}

// allow users to add and manipulate middleware in the config
await middleware(app, builtins);

Expand Down
3 changes: 2 additions & 1 deletion lib/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ module.exports = {
secure: any().forbidden(),
// prettier-ignore
static: [string().allow(null), array().items(string())],
status: boolean()
status: boolean(),
waitForBuild: boolean()
};
const schema = object().keys(keys);
const results = validate(options, schema);
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/wait-for-build/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 'hello';
46 changes: 46 additions & 0 deletions test/fixtures/wait-for-build/make-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* eslint-disable no-param-reassign */
const { resolve } = require('path');

const { WebpackPluginServe: Serve } = require('../../../lib/');

const make = (port) => {
const outputPath = resolve(__dirname, './output/output.js');
const serve = new Serve({
host: 'localhost',
port,
waitForBuild: true,
middleware: (app) => {
app.use(async (ctx, next) => {
if (ctx.url === '/test') {
try {
// eslint-disable-next-line import/no-dynamic-require, global-require
require(outputPath);
ctx.body = 'success';
} catch (e) {
ctx.body = 'error';
}
}
await next();
});
}
});

const config = {
context: __dirname,
entry: ['./app.js'],
mode: 'development',
output: {
filename: './output.js',
path: resolve(__dirname, './output'),
publicPath: 'output/',
libraryTarget: 'commonjs2'
},
plugins: [serve],
target: 'node',
watch: true
};

return { serve, config };
};

module.exports = { make };
32 changes: 32 additions & 0 deletions test/wait-for-build.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const getPort = require('get-port');
const del = require('del');
const webpack = require('webpack');
const test = require('ava');
const fetch = require('node-fetch');
const defer = require('p-defer');

const { make } = require('./fixtures/wait-for-build/make-config');

let watcher;
let port;

test.before('Starting server', async () => {
const deferred = defer();
port = await getPort();
const { serve, config } = make(port);
const compiler = webpack(config);
watcher = compiler.watch({}, () => {});
serve.on('listening', deferred.resolve);
await deferred.promise;
});

test.after.always('Closing server', async () => {
watcher.close();
await del('./test/fixtures/waitForBuild/output');
});

test('should wait until bundle is compiled', async (t) => {
const response = await fetch(`http://localhost:${port}/test`);
const text = await response.text();
t.is(text, 'success');
});