【翻译向】webpack2 指南(中)

原文发布与抹桥的博客-【翻译向】webpack2 指南(中)

动态模块替换(Hot Module Repalcement -React)

就像之前 理念页面 中解析的细节那样,动态模块替换(HMR)会在应用运行时动态的替换、添加或者删除模块而不用重新刷新页面。 HMR 非常有用,当应用只有一个状态树(single state tree)时。

下面介绍的方法描述中使用了 Babel 和 React ,但这并不是使用 HRM 所必须的工具。

项目配置

这里会指导你如何用 Babel, React 和 PostCss 一起使用 HMR 去演示一个项目。为了能够跟着下面走下去,需要把这些依赖添加到 package.json 中去。

为了使用 HMR,你需要如下这些依赖:

npm install --save-dev [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]

同时,为了达到我们演示的目的,还需要:

npm install --save [email protected] [email protected]

Babel Config

.babelrc 文件应该如下:

{
  "presets": [
    ["es2015", {"modules": false}],
    // webpack understands the native import syntax, and uses it for tree shaking

    "stage-2",
    // Specifies what level of language features to activate.
    // Stage 2 is "draft", 4 is finished, 0 is strawman.
    // See https://tc39.github.io/process-document/

    "react"
    // Transpile React components to JavaScript
  ],
  "plugins": [
    "react-hot-loader/babel"
    // Enables React code to work with HMR.
  ]
}

Webpack Config

const { resolve } = require('path');
const webpack = require('webpack');

module.exports = {
  entry: [
    'react-hot-loader/patch',
    // activate HMR for React

    'webpack-dev-server/client?http://localhost:8080',
    // bundle the client for webpack-dev-server
    // and connect to the provided endpoint

    'webpack/hot/only-dev-server',
    // bundle the client for hot reloading
    // only- means to only hot reload for successful updates


    './index.js'
    // the entry point of our app
  ],
  output: {
    filename: 'bundle.js',
    // the output bundle

    path: resolve(__dirname, 'dist'),

    publicPath: '/'
    // necessary for HMR to know where to load the hot update chunks
  },

  context: resolve(__dirname, 'src'),

  devtool: 'inline-source-map',

  devServer: {
    hot: true,
    // enable HMR on the server

    contentBase: resolve(__dirname, 'dist'),
    // match the output path

    publicPath: '/'
    // match the output `publicPath`
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          'babel-loader',
        ],
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader?modules',
          'postcss-loader',
        ],
      },
    ],
  },

  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    // enable HMR globally

    new webpack.NamedModulesPlugin(),
    // prints more readable module names in the browser console on HMR updates
  ],
};

上面有很多配置,但不是所有都和 HMR 有关。可以通过查阅 webpack-dev-server options 和concept pages 来加深理解。

我们基础设想是这样的,你的 JavaScript 入口文件在 ./src/index.js 且你使用 CSS Module 来编写样式文件。

配置文件中需要重点关注的是 devServerentry key. HotModueReplacementPlugin 同样需要被包含在 plugins key 中。

为了达到目的,我们引入了两个模块:

  • react-hot-loader 添加到了入口中, 是为了能够使 React 支持 HMR

  • 为了更好的理解 HMR 每次更新的时候做了哪些事情,我们添加了 NamedModulePlugin

Code

// ./src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

import { AppContainer } from 'react-hot-loader';
// AppContainer is a necessary wrapper component for HMR

import App from './components/App';

const render = (Component) => {
  ReactDOM.render(
  
  
  ,
    document.getElementById('root')
  );
};

render(App);

// Hot Module Replacement API
if (module.hot) {
  module.hot.accept('./components/App', () => {
    const NewApp = require('./components/App').default
    render(NewApp)
  });
}
// ./src/components/App.js
import React from 'react';
import styles from './App.css';

const App = () => (
  

Hello,

); export default App;
.app {
    text-size-adjust: none;
    font-family: helvetica, arial, sans-serif;
    line-height: 200%;
    padding: 6px 20px 30px;
}

一个需要特别注意的是 module 的引用:

  1. Webpack 会暴露出 module.hot 给我们的代码,当我们设置 devServer: { hot: true } 时;

  2. 这样我们可以使用 module.hot 来给特定的资源弃用 HMR (这里是 App.js). 这里有一个非常重要的 API module.hot.accept ,用来决定如何处理这些特定的依赖。

  3. 需要注意的是,webpack2 内建支持 ES2015 模块语法,你不需要在 module.hot.accept 中重新引用跟组件。为了达到这个目的,需要在 .babelrc 配置 Babel ES2015 的预先设置:

    ["es2015", {"modules": false}]

    就像我们在之前 Babel Config 中配置的那样。需要注意,禁用 Babel 的模块功能 不仅仅是为了启用 HMR。如果你不关掉这个配置,那么你会碰到需要问题。

  4. 如果你在 webpack2 的配置文件中使用 ES6 模块,并且你按照 #3 修改了 .babelrc,那么你需要使用 require 语法来创建两个 .babelrc 文件:

    1. 一个放在根目录下面并配置为 "presets: ["es2015"]"

    2. 一个放在 webpack 要编译的文件夹下,比如在这个例子中,就是 src/
      所以在这个案例中,module.hot.accept 会执行 render 方法无论 src/compoents/App.js 或者其它的依赖文件变化的时候 ——这意味着当 App.css 被引入到 App.js 中以后,即使是 App.css 被修改,

    render 方法同样会被执行。

Index.html

入口页面需要被放在页面 dist 下面,webpack-dev-server 的运行需要这个文件。




    
    Example Index


Package.json

最后,我们需要启动 webpack-dev-server 来打包我们的代码并且看看 HMR 是如何工作的。我们可以使用如下的 package.json 入口:

{
  "scripts" : {
    "start" : "webpack-dev-server"
  }
}

执行 npm start, 打开浏览器输入 http://localhost:8080, 应该可以看到下面这些项展示在 console.log中:

dev-server.js:49[HMR] Waiting for update signal from WDS…
only-dev-server.js:74[HMR] Waiting for update signal from WDS…
client?c7c8:24 [WDS] Hot Module Replacement enabled.

然后编辑并且修改 App.js 文件,你会在 console.log 中看到类似如下的日志:

[WDS] App updated. Recompiling…
client?c7c8:91 [WDS] App hot update…
dev-server.js:45 [HMR] Checking for updates on the server…
log-apply-result.js:20 [HMR] Updated modules:
log-apply-result.js:22 [HMR]  - ./components/App.js
dev-server.js:27 [HMR] App is up to date.

注意 HMR 指出了更新模块的路径。这是因为我们使用了 NamedModulesPlugin.

开发环境(Development)

这个章节介绍在开发过程中可以使用的一些工具。

需要注意,不能在生产环境使用

Source Map

当 JS 发生异常的时候,我们需要指导是哪一个文件的哪一行出错了。但是当文件都被 webpack 打包以后,找问题会变得很麻烦。
Source Map 就是为了解决这个问题的。它有很多不同的选项,每一种都有的好处和不足。在一开始,我们使用:

devtool: "cheap-eval-source-map"

选择一个工具(Choosing a Tool)

Webpack 可被用于监视模式(watch mode)。这种模式下, webpack 会监视你的文件,当它们有变动的时候就会重编译。Webpack-dev-server 提供了一个很方便使用的开发环境的服务,并且支持自动刷新功能。如果你已经有了一个开发环境的服务,并且希望能够拥有更好的适应性,那么 webpack-dev-middleware 可以被用作一个中间件来达到这个目的。

Webpack-dev-server 和 webpack-dev-middleware 实在内存中进行编译的,这意味着打包后的代码包并不会保存到本地磁盘中。这回使打包变得很快,同时不会产生很多临时文件来污染你的本地文件系统。

大多数情况下,你都会想要去使用 webpack-dev-server, 因为它使用起来很方便,而且提供了许多开箱即用的功能。

Webpack 监视模式(wtach mode)

Webpack 的监视模式会检测文件的变动。只要变动被检测到,它就会重新进行一次编译。我们希望它的编译过程能有一个很好的进度展示。那么就执行以下命令:

webpack --progress --watch

随便修改一个文件然后保存,你就会看到重新编译的过程。

监视模式没有考虑任何和服务有关的问题,所以你需要自己提供一个服务。一个简单的服务就是 [server](https://github.com/tj/serve). 当安装好后(npm i server -g),在你打包后的文件目录下运行:

server

当每次重新编译后,你都需要手动的去刷新浏览器。

webpack-dev-server

webpack-dev-server 提供一个支持自动刷新的服务。

首先,确认你 index.html 页面里面已经引用了你的代码包。我们先假设 output.filename 设置为 bundle.js:


                    
                    

你可能感兴趣的:(webpack,webpack2,javascript)