等待Webpack Dev Server准备就绪

8

要求

我需要运行webpack-dev-server并等待服务器准备好为页面提供服务。

解决方案

// Start a webpack-dev-server
new WebpackDevServer(webpack(myConfig), {
    publicPath: myConfig.output.publicPath,
    hot: true,
    historyApiFallback: true,
    // It suppress error shown in console, so it has to be set to false.
    quiet: false,
    // It suppress everything except error, so it has to be set to false as well
    // to see success build.
    noInfo: false,
    stats: {
        // Config for minimal console.log mess.
        assets: false,
        colors: true,
        version: false,
        hash: false,
        timings: false,
        chunks: false,
        chunkModules: false
    }
}).listen(3000, '0.0.0.0', function(err) {
    if(err) throw new gutil.PluginError('webpack-dev-server', err);
    gutil.log('[webpack-dev-server]', 'http://0.0.0.0:3000/webpack-dev-server/index.html');
    //this is to ensure that end to end test wouldn't start running until the server is ready
    http.get({
        hostname: '0.0.0.0',
        port: 3000,
        path: '/',
        agent: false  // create a new agent just for this one request
    }, (/*res*/) => {
        // Do stuff with response
        done();
    });
});

问题

在Linux上,我可以等待服务器就绪。但在Windows上,由于没有等待,所以会出现异常,服务器也无法就绪。

C:\development\ucms-react>gulp webpack-dev-server [11:03:01] Requiring external module babel-register [11:03:07] Using gulpfile C:\development\ucms-react\gulpfile.babel.js [11:03:07] 启动 'webpack-dev-server'... [11:03:07] [webpack-dev-server] http://0.0.0.0:3000/webpack-dev-server/index.html error events.js:141 throw er; // Unhandled 'error' event ^

Error: connect EADDRNOTAVAIL 0.0.0.0:3000 at Object.exports._errnoException (util.js:907:11) at exports._exceptionWithHostPort (util.js:930:20) at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1077:14)

C:\development\ucms-react>

如何解决这个问题?

3个回答

8
这里Brett DeWoody的另一个回答部分正确。它确保等待服务器启动,但这并不等于等待捆绑完成。因此,如果您此时要求webpack获得页面,它将返回类似于“仍在编译”的内容。
为了在尝试访问页面之前等待捆绑完全编译(并且服务器正在侦听),您需要像这样的东西:
function makeServer(config) {
  return new Promise((resolve, reject) => {
    const compiler = webpack(config);

    let compiled = false;
    let listening = false;

    compiler.hooks.done.tap('IDoNotUnderstandWhatThisStringIsForButItCannotBeEmpty', () => {
      // console.log('compiled');

      if (listening) resolve(server);
      else compiled = true;
    });

    const server = new WebpackDevServer(compiler, config.devServer);

    server.listen(port, '0.0.0.0', err => {
      if (err) return reject(err);

      // console.log('listening');

      if (compiled) resolve(server);
      else listening = true;
    });
  });
}

然后,就像Brett的答案一样,await结果:

var server = await makeServer(config);

或者不使用 async/await

makeServer(config).then(server => {
  // Do something with server
});

6
这里有另一种解决方案(受 @CameronTacklind 答案的启发)。setImmediate 使得日志输出显示在初始编译器日志输出下方。
const PORT = process.env.PORT || 3000

const compiler = webpack(config)
new WebpackDevServer(compiler).listen(PORT, '0.0.0.0', err => {
    if (err) {
        console.log(err)
    }
})

compiler.hooks.done.tap('done', () => {
    setImmediate(() => {
        console.log()
        console.log(`Running at http://localhost:${PORT}`)
    })
})

更新

这里有一个替代版本,它不需要自定义服务器脚本,您只需将其添加到webpack配置选项中即可。它还保留了自动使用不同端口的内置功能,如果默认端口不可用...当然,如果您更愿意指定端口,则无需使用该部分。

const chalk = require('chalk')
...

module.exports = {
    ....
    devServer: {
        onListening: server => {
            const { port } = server.listeningApp.address()
            server.compiler.hooks.done.tap('done', () => {
                setImmediate(() => {
                    console.log()
                    console.log(
                        chalk.cyan.bold(`Running at http://localhost:${port}`)
                    )
                })
            })
        },
    }
}

这正是我在寻找的答案,谢谢。其他钩子的完整列表请参见:https://webpack.js.org/api/compiler-hooks/ - Patrick

4

处理这个问题的一种方法是将服务器设置封装在一个返回 Promise 的函数中。当服务器连接时,Promise 将被解决,如果出现错误,则被拒绝。

这里是一个简化的例子:

function startServer() {
  return new Promise((resolve, reject) => {
    new WebpackDevServer(webpack(myConfig), {
      // Do stuff
    }).listen(3000, '0.0.0.0', function(err) {
      resolve();
    }).on('error', (error) => {
      reject(error);
    });
  });
}

然后为服务器启动提供回调函数:

var server = startServer();

server.then(function() {
  // Run tests
});

1
Brett,你是一个传奇! - Marco C
@calmbird - 你在用哪个版本?我会更新新版本的解决方案。 - Brett DeWoody

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接