神奇的HMR

模块热替换(Hot Module Replacement 简称HMR),就是当对代码做了修改并保存后,修改结果会直接反应在应用中而不用刷新浏览器。这个过程包括了两个步骤,一是保存后webpack重新打包;二是浏览器进行新老模块的替换,将新的结果反应在浏览器上。

两个过程对应着两个webpack插件的使用:webpack-dev-middleware和 webpack-hot-middleware,我们就来看一下如何利用这两个插件实现HMR。

假设已经创建了webpack.dev.conf.js配置文件.
build/setup-dev-server.js:

const path = require('path');
const webpack = require('webpack');
const webpackConfig = require('./webpack.dev.conf');
const DevMiddleware = require('webpack-dev-middleware');
const hotMiddleware = require('webpack-hot-middleware');

module.exports = function setupDevServer (app, opts) {
  webpackConfig.entry.app = ['webpack-hot-middleware/client', webpackConfig.entry.app]; // 入口文件添加'webpack-hot-middleware/client',服务端能够和客户端通信的关键
  webpackConfig.output.filename = '[name].js';
  webpackConfig.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  );

  const compiler = webpack(webpackConfig); // 以webpack.dev.conf.js文件为基础,创建一个用来传给webpack-dev-middleware的对象
  const devMiddleware = DevMiddleware(compiler, {
    publicPath: webpackConfig.output.publicPath, // 必传参数,和webpack.dev.conf.js文件里面的publicPath一致
    stats: { colors: true, chunks: false }
  });
  app.use(devMiddleware); // 添加中间件,告诉express使用webpack-dev-middleware插件

  compiler.plugin('done', () => { // 钩子函数被调用时客户端检查模块更新
    const fs = devMiddleware.fileSystem;
    const filePath = path.join(webpackConfig.output.path, 'index.html');
    if (fs.existsSync(filePath)) {
      const template = fs.readFileSync(filePath, 'utf-8');
      opts.templateUpdated(template);
    }
  });
  app.use(hotMiddleware(compiler));
}

server.js:

const express = require('express');
const app = express();

const noDevelop = process.env.NODE_ENV !== 'develop';
const resolve = file => path.resolve(__dirname, file);
let tempHTML;

//...其他代码

if (!noDevelop) {
  const setupDevServer = require('./build/setup-dev-server');
  setupDevServer(app, {
    templateUpdated: (template) => {
      tempHTML = template;
    }
  });
} else {
  tempHTML = fs.readFileSync(resolve('./dist/index.html'));
}

app.get('*', (req, res, next) => {
  res.end(tempHTML);
  next();
})

app.listen('7777', function () {
  
});

然后在package.json的scripts添加一条命令:

"dev": "cross-env NODE_ENV=develop node server.js"

执行npm run dev就可以运行了。

你可能感兴趣的:(神奇的HMR)