资讯专栏INFORMATION COLUMN

【翻译向】webpack2 指南(中)

阿罗 / 1894人阅读

摘要:我们先假设设置为从安装然后就可以执行的命令了上面的命令会自动打开你的浏览器并指定到修改一下你的文件并保存。比如,类似与解析等都是共通的功能,需要放在基础配置文件里面然后使用来合并特定环境变量下指定的配置文件。

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

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

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

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

项目配置

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

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

npm install --save-dev babel@6.5.2 babel-core@6.13.2 babel-loader@6.2.4 babel-preset-es2015@6.13.2 babel-preset-react@6.11.1 babel-preset-stage-2@6.13.0 css-loader@0.23.1 postcss-loader@0.9.1 react-hot-loader@3.0.0-beta.6 style-loader@0.13.1 webpack@2.1.0-beta.25 webpack-dev-server@2.1.0-beta.0

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

npm install --save react@15.3.0 react-dom@15.3.0
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 的引用:

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

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

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

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

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

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

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

一个放在 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:

                
阅读需要支付1元查看
<