当前位置:首页 >> 网络编程

Webpack 实现 Node.js 代码热替换

这两天为了这个问题, Gitter 上问, Twitter 上问, GitHub 上问, 两天没反应
原来写博客的 jlongster 不理我, 我也不知道 Webpack 作者的联系方式
最后在 Gitter 上发的消息他似乎看到了, 就粗略地解释了一遍, 醍醐灌顶啊...
https://github.com/webpack/docs/issues/45#issuecomment-149793458

Here is the process in short:

Compile the server code with webpack
Use target: "node" or target: "async-node"
Enabled HMR via --hot or HotModuleReplacementPlugin
Use webpack/hot/poll or webpack/hot/signal
The first polls the fs for updates (easy to use)
The second listens for a process event to check for updates (you need a way to send the signal)
Run the bundle with node.
You can't use existing HMR loaders like react-hot-loader or style-loader because they make no sense in a server environment. Just add manuall replacement code at the correct location (i. e. accept request handler like in the example)

You can't use the webpack-dev-server. It's a server which serves assets not a runner. Just run webpack --watch and node bundle.js. I would go the webpack/hot/poll"https://github.com/jiyinyiyong/webpack-backend-HMR-demo">https://github.com/jiyinyiyong/webpack-backend-HMR-demo
其中代码可以从 jlongster 的配置教程里抄:
http://jlongster.com/Backend-Apps-with-Webpack--Part-II

webpack = require 'webpack'

module.exports =
 entry: [
  'webpack/hot/poll"htmlcode">
npm i
webpack --watch & # <-- watch 模式
node build/bundle.js # <-- 运行的是打包结果的代码

我写了两个测试文件, 一个是会修改的代码 src/lib.coffee:

exports.data = 'code 5'

exports.printSelf = ->
 console.log 'doing 3'

另一个入口文件 src/main.coffee 包含了处理模块替换的代码:

lib = require './lib'

console.log lib.data
lib.printSelf()

counter = 0
setInterval ->
 counter += 1
 console.log counter
, 2000

if module.hot
 module.hot.accept './lib', ->
  lib = require './lib'

  console.log lib.data
  lib.printSelf()

跑一跑 Demo, 就知道效果怎么样了, setInterval 不受替换的干扰
而在 build/ 目录, 每次修改都会生成一个 JSON 文件记录修改的内容:

复制代码 代码如下:"htmlcode">

"https://www.jb51.net/article/73739.htm">https://www.jb51.net/article/73739.htm

另一个似乎是对 require.extensions 做了 hack, 增加了操作和事件,当模块文件更新时, 对应模块自动更新, 并且 emit 一个事件,通过这样的效果, 模块引用的位置可以做一些处理, 使用新的代码,这个应该说还是比较粗暴的, 毕竟不是所有的代码都容易替换
https://github.com/rlidwka/node-hotswap

感想

考虑到我已经在 Webpack 这棵树上吊死, 也就不打算深入研究了,也许 Node.js 官方对 lib/module.js 做下优化能搞出不错的功能来,然而, JavaScript 毕竟不是不可变数据使用成风的社区, 比不了 Erlang,因为代码替换就涉及到状态更新的问题, 不好搞, 不如重启来得省事,而重启现在有 node-dev supervisor nodemon 三套方案任你选

对我来说, 主要是 Cumulo 方案对 WebSocket 存在巨大的依赖,现在前端开发已经能做到服务器上更新代码, 客户端自动更新了,
通过 Webpack 和 React 的机制, 局部更新 DOM 和纯函数模块,如果说能够做到开发环境也能热替换, 这对于开发效率的提升就太大了,本来觉得热替换遥不可及的, 然而很可能是触手可及的效率提升!

后面大概还有坑, 毕竟黑科技... 遇到再说了

有兴趣可以细看下 jlongster 写的相关的几篇神作, 非常有帮助:
http://jlongster.com/archive