[webpack3.8.1]Guides-6-Hot Module Replacement(模塊熱重置)

Hot Module Replacement

This guide extends on code examples found in the Development guide.css

       舒適提示:這個指南中的例子是基於上一個指南的。(╯°Д°)╯html

Hot Module Replacement (or HMR) is one of the most useful features offered by webpack. It allows all kinds of modules to be updated at runtime without the need for a full refresh. This page focuses on implementation while the concepts page gives more details on how it works and why it's useful.vue

       Hot Module Replacement,或稱之爲HMR,是webpack提供的很是有用的特性之一。它容許你各類各樣的模塊在運行時自動更新,而無需總體更新。在這一趴,咱們主要關注這一切是如何實現的,不像概念部分那樣,咱們會告訴你它是怎麼工做的,爲何這樣是實用的。react

HMR is not intended for use in production, meaning it should only be used in development. See the building for production guide for more information.webpack

       咱們不建議在產品中使用HMR,這意味着它應當在開發過程當中使用。戳這裏,查看更多信息。git

Enabling HMR

This feature is great for productivity. All we need to do is update our webpack-dev-server configuration, and use webpack's built in HMR plugin. We'll also remove the entry point for print.js as it will now be consumed by the index.js module.github

       這個特性對於生產效率很重要。咱們所須要作的所有的事情只是更新咱們服務器的配置,只要使用HMR插件就好了。咱們也將會移除print.js的入口點,因爲它如今正在被index.js模塊使用。web

If you took the route of using webpack-dev-middleware instead of webpack-dev-server, please use the webpack-hot-middleware package to enable HMR on your custom server or application.npm

       若是你的技術路線是使用webpack-dev-middleware而不是webpack-dev-server,請使用webpack-hot-middleware來使得HMR在你的服務器或者程序中生效。json

webpack.config.js

const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CleanWebpackPlugin = require('clean-webpack-plugin');
+ const webpack = require('webpack');

  module.exports = {
    entry: {
-      app: './src/index.js',
-      print: './src/print.js'
+      app: './src/index.js'
    },
    devtool: 'inline-source-map',
    devServer: {
      contentBase: './dist',
+     hot: true
    },
    plugins: [
      new CleanWebpackPlugin(['dist']),
      new HtmlWebpackPlugin({
        title: 'Hot Module Replacement'
      }),
+     new webpack.NamedModulesPlugin(),
+     new webpack.HotModuleReplacementPlugin()
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };

You can use the CLI to modify the webpack-dev-server configuration with the following command: webpack-dev-server --hotOnly.

       你可使用命令行來修改webpack-dev-server的配置,使用以下的命令:

webpack-dev-server --hotOnly

Note that we've also added the NamedModulesPlugin to make it easier to see which dependencies are being patched. To start, we'll get the dev server up and running by executing an npm start from the command line.

       請注意,咱們還添加了這個功能NamedModulesPlugin,以便更輕鬆地查看哪些依賴關係正在進行修補。首先,咱們將經過npm start從命令行執行一個啓動並運行開發服務器。

Now let's update the index.js file so that when a change inside print.js is detected we tell webpack to accept the updated module.

       如今,讓咱們更新index.js,以便當print.js檢測到內部更改時,咱們告訴webpack接受更新的模塊。

index.js

import _ from 'lodash';
  import printMe from './print.js';

  function component() {
    var element = document.createElement('div');
    var btn = document.createElement('button');

    element.innerHTML = _.join(['Hello', 'webpack'], ' ');

    btn.innerHTML = 'Click me and check the console!';
    btn.onclick = printMe;

    element.appendChild(btn);

    return element;
  }

  document.body.appendChild(component());
+
+ if (module.hot) {
+   module.hot.accept('./print.js', function() {
+     console.log('Accepting the updated printMe module!');
+     printMe();
+   })
+ }

Start changing the console.log statement in print.js, and you should see the following output in the browser console.

       讓咱們開始改變print.js中的console.log語句,你應當能看到以下的在瀏覽器控制檯的輸出:

print.js

export default function printMe() {
-   console.log('I get called from print.js!');
+   console.log('Updating print.js...')
  }

console

[HMR] Waiting for update signal from WDS...
main.js:4395 [WDS] Hot Module Replacement enabled.
+ 2main.js:4395 [WDS] App updated. Recompiling...
+ main.js:4395 [WDS] App hot update...
+ main.js:4330 [HMR] Checking for updates on the server...
+ main.js:10024 Accepting the updated printMe module!
+ 0.4b8ee77….hot-update.js:10 Updating print.js...
+ main.js:4330 [HMR] Updated modules:
+ main.js:4330 [HMR]  - 20
+ main.js:4330 [HMR] Consider using the NamedModulesPlugin for module names.

Via the Node.js API

When using Webpack Dev Server with the Node.js API, don't put the dev server options on the webpack config object. Instead, pass them as a second parameter upon creation. For example:

       當咱們經過Node.js的API來使用Webpack Dev Server時,不要將dev server的選項配置在webpack的對象中。而是應該將這些配置信息做爲構造函數的第二個參數傳進去。舉個例子哈:✧(≖ ◡ ≖✿

new WebpackDevServer(compiler, options)

To enable HMR, you also need to modify your webpack configuration object to include the HMR entry points. The webpack-dev-server package includes a method called addDevServerEntrypoints which you can use to do this. Here's a small example of how that might look:

       要啓用HMR,還須要修改webpack配置對象以包含HMR入口點。該webpack-dev-server軟件包包含一個addDevServerEntrypoints,您能夠用來執行此操做的方法。下面是一個小例子,它多是這樣的:

dev-server.js

const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');

const config = require('./webpack.config.js');
const options = {
  contentBase: './dist',
  hot: true,
  host: 'localhost'
};

webpackDevServer.addDevServerEntrypoints(config, options);
const compiler = webpack(config);
const server = new webpackDevServer(compiler, options);

server.listen(5000, 'localhost', () => {
  console.log('dev server listening on port 5000');
});

If you're using webpack-dev-middleware, check out the webpack-hot-middleware package to enable HMR on your custom dev server.

       若是你正在使用webpack-dev-middleware,檢查webpack-hot-middleware包,使得HMR能夠應用在你的定製化的dev server中。

Gotchas

Hot Module Replacement can be tricky. To show this, let's go back to our working example. If you go ahead and click the button on the example page, you will realize the console is printing the old printMe function.

       模塊熱重置多是棘手的。爲了展示這個,讓咱們回到咱們工做的例子。若是你單擊咱們例子的頁面上的按鈕,你將會意識到控制檯正在打印舊的printMe函數的信息。

This is happening because the button's onclick event handler is still bound to the original printMe function.

       這是由於按鈕的點擊事件的解析器依舊綁定在原始的printMe的函數上。

To make this work with HMR we need to update that binding to the new printMe function using module.hot.accept:

       爲了使得HMR起做用,咱們須要使用module.hot.accept更新綁定,讓它綁定到新的printMe函數:

index.js

import _ from 'lodash';
  import printMe from './print.js';

  function component() {
    var element = document.createElement('div');
    var btn = document.createElement('button');

    element.innerHTML = _.join(['Hello', 'webpack'], ' ');

    btn.innerHTML = 'Click me and check the console!';
    btn.onclick = printMe;  // onclick event is bind to the original printMe function

    element.appendChild(btn);

    return element;
  }

- document.body.appendChild(component());
+ let element = component(); // Store the element to re-render on print.js changes
+ document.body.appendChild(element);

  if (module.hot) {
    module.hot.accept('./print.js', function() {
      console.log('Accepting the updated printMe module!');
-     printMe();
+     document.body.removeChild(element);
+     element = component(); // Re-render the "component" to update the click handler
+     document.body.appendChild(element);
    })
  }

This is just one example, but there are many others that can easily trip people up. Luckily, there are a lot of loaders out there (some of which are mentioned below) that will make hot module replacement much easier.

       這只是一個例子,可是這裏有不少其餘的狀況會輕易地使得人們感到難纏。幸運的是,在這裏有不少加載器(下面咱們列舉一些)可使得模塊熱重置變得更加簡易。( ゚∀゚)

HMR with Stylesheets (HMR和樣式表)

Hot Module Replacement with CSS is actually fairly straightforward with the help of the style-loader. This loader uses module.hot.accept behind the scenes to patch <style> tags when CSS dependencies are updated.

       實際上,使用style-loader了以後,模塊熱重置來更新CSS就會至關簡單。當CSS依賴發生更新時,該加載器使用module.hot.accept在後臺修補<style>標記。

First let's install both loaders with the following command:

       首先,讓咱們用下面的命令安裝這兩個加載器:

npm install --save-dev style-loader css-loader

Now let's update the configuration file to make use of the loader.

       如今,讓咱們更新配置文件以使用加載器。

webpack.config.js

const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const webpack = require('webpack');

  module.exports = {
    entry: {
      app: './src/index.js'
    },
    devtool: 'inline-source-map',
    devServer: {
      contentBase: './dist',
      hot: true
    },
+   module: {
+     rules: [
+       {
+         test: /\.css$/,
+         use: ['style-loader', 'css-loader']
+       }
+     ]
+   },
    plugins: [
      new CleanWebpackPlugin(['dist'])
      new HtmlWebpackPlugin({
        title: 'Hot Module Replacement'
      }),
      new webpack.HotModuleReplacementPlugin()
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };

Hot loading stylesheets is as easy as importing them into a module:

       咱們只須要導入它們進模塊之中,樣式表就能夠熱加載了。

project

webpack-demo
  | - package.json
  | - webpack.config.js
  | - /dist
    | - bundle.js
  | - /src
    | - index.js
    | - print.js
+   | - styles.css

styles.css

body {
  background: blue;
}

index.js

import _ from 'lodash';
  import printMe from './print.js';
+ import './styles.css';

  function component() {
    var element = document.createElement('div');
    var btn = document.createElement('button');

    element.innerHTML = _.join(['Hello', 'webpack'], ' ');

    btn.innerHTML = 'Click me and check the console!';
    btn.onclick = printMe;  // onclick event is bind to the original printMe function

    element.appendChild(btn);

    return element;
  }

  let element = component();
  document.body.appendChild(element);

  if (module.hot) {
    module.hot.accept('./print.js', function() {
      console.log('Accepting the updated printMe module!');
      document.body.removeChild(element);
      element = component(); // Re-render the "component" to update the click handler
      document.body.appendChild(element);
    })
  }

Change the style on body to background: red; and you should immediately see the page's background color change without a full refresh.

       如今,改變body的樣式爲background: red;,而後你應當當即就能看到頁面背景顏色的改變,並且不用總體刷新。

styles.css

body {
-   background: blue;
+   background: red;
  }

Other Code and Frameworks

There are many other loaders and examples out in the community to make HMR interact smoothly with a variety of frameworks and libraries...

       在社區中還有不少其餘的加載器和例子可使HMR與各類框架和庫進行順暢的交互。

  • React Hot Loader: Tweak react components in real time.
  • Vue Loader: This loader supports HMR for vue components out of the box.
  • Elm Hot Loader: Supports HMR for the Elm programming language.
  • Redux HMR: No loader or plugin necessary! A simple change to your main store file is all that's required.
  • Angular HMR: No loader necessary! A simple change to your main NgModule file is all that's required to have full control over the HMR APIs.

P.S.:好了,7之後的部分就比較難懂了,我會在能力提升了再譯,前六個指南以及基礎概念學會,使用webpack就基本不會遇到什麼難題了。

相關文章
相關標籤/搜索