资讯专栏INFORMATION COLUMN

Webpack 2: 生产力工具, 模块热替换(HMR)的几种方式

changfeng1050 / 2395人阅读

摘要:更新已经到了这里添加更新说明并说明结合使用的简要步骤参考资料环境在中添加中的设置的要设置为要在你的应用程序入口之前添加如下在有完整的配置入口文件要这样导

2018-01-10 更新

Webpacket 已经到3了, 这里添加更新说明,并说明结合babel-loader使用的简要步骤

参考资料

https://doc.webpack-china.org...

https://github.com/gaearon/re...

https://segmentfault.com/p/12...

#0. 环境

node: v9.0.0
webpack: ^3.10.0 
webpack-dev-server: ^2.10.1
react-hot-loader": ^3.1.3
babel-core: ^6.26.0
babel-loader: ^7.1.2
babel-plugin-import: ^1.6.3
babel-preset-env: ^1.6.1
babel-preset-react: ^6.24.1

#1..babelrc中添加 react-hot-loader

// .babelrc
{
  "plugins": [
    "react-hot-loader/babel"
  ]
}

#2. webpacket.confg.js 中的设置

const path = require("path");
const webpack = require("webpack");
const moment = require("moment")

const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const WriteFilePlugin = require("write-file-webpack-plugin");

const publish_date = moment().format("YYYYMMDD")

let config = {
  devtool: "eval-source-map",
  resolve: {
    extensions: [".js", ".jsx", ".json"]
  },
  entry: {
    app: [
      "react-hot-loader/patch",
      "./src/index"
    ]
  },
  module: {
    rules: [
      {
        test: /.jsx$/,
        exclude: /node_modules/,
        use: [{
          loader: "babel-loader"
        }]
      },
      {
        test: /.css$/,
        use: [
          { loader: "style-loader" },
          { loader: "css-loader" }
        ]
      },
      {
        test: /.less$/,
        use: [
          { loader: "style-loader" },
          { loader: "css-loader", },
          { loader: "less-loader" }
        ]
      },
    ]
  },
  output: {
    path: path.resolve(__dirname, "dist", publish_date),
    filename: "[name].[hash].js",
    sourceMapFilename: "[name].[hash].map",
    publicPath: "/" + publish_date
  },
  plugins: [
    new WriteFilePlugin(),
    new HtmlWebpackPlugin({
      title: "RBAC",
      inject: true,
      template: "./index.html",
      filename: "index.html",
      chunksSortMode: "auto",
      minify: false,
      hash: false,
      xhtml: true,
      chunks: ["app"],
      cache: true,
      showErrors: true,
    }),
    new CopyWebpackPlugin([
      { from: "src/assets", to: "assets" }
    ]),
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ],
  devServer: {
    contentBase: path.join(__dirname, "dist", publish_date),
    hot: true,
    host: "0.0.0.0",
    port: 8000,
    publicPath: "/" + publish_date,
  }
}

module.exports = config;

devServerhot要设置为true

#3. 要在你的应用程序入口之前添加 react-hot-loader/patch, 如下:

let config = {
  devtool: "eval-source-map",
  resolve: {
    extensions: [".js", ".jsx", ".json"]
  },
  entry: {
    app: [
      "react-hot-loader/patch",
      "./src/index"
    ]
  },
  ...
  ...
  ...
}

#2 有完整的配置

#4. 入口文件要这样

// index.js
import React from "react"
import ReactDOM from "react-dom"
// 导入HMR
import { AppContainer } from "react-hot-loader"
import App from "./containers/App"

// 定义一个热加载回调函数用于重新渲染入口组件
const render = Component => {
  ReactDOM.render(
    
      
    ,
    document.getElementById("root"),
  )
}

// 启动时调用
render(App)

// 当发送热加载时调用, Webpack打包的生产环境不会有 `module.hot`, 因此这块代码在开发环境
// 下面的if块里面的代码不会执行
if (module.hot) {
  module.hot.accept("./containers/App", () => {
    render(App)
  })
}

#5. .babelrc 中的 modules 属性

modules 属性必须要设置为 false, 否则HMR无效

{
  "presets": [
    ["env", { "modules": false }], 
    "react"
  ],
  "plugins": [
    ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }],
    "react-hot-loader/babel"
  ]
}

#6. 最新如果你不用babel, 直接在配置文件中设置 react-hot-loader/webpack 加载器

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /.jsx?$/,
        use: ["react-hot-loader/webpack"],
      },
    ],
  },
}
更新完毕 命令行

命令行方式是最简单的方式, 如果项目只是纯Web前端, 使用这种方式是最便捷的. 只需要在package.json文件中的scripts里面添加下面一行就可以了.

直接命令行:

webpack-dev-server --content-base=www --inline --watch --hot --progress --config webpack.config.js

通过 npm run devyarn run dev:

// package.json
"scripts": {
  "dev": "webpack-dev-server --content-base=www --inline --watch --hot --progress --config webpack.config.js",
  ...
},

参数说明:

--content-base: 静态资源的目录, 为 output.path 设置的目录.

output: {   
   path: path.resolve(__dirname, "dist"), 
}, 

--watch: 监视模式, Web执行完打包后不退出, 一直监听文件变化, Ctrl + S后自动构建变化的模块, 及其依赖模块.
--hot: 开启模块热替换.
--progress: 显示进度
--config: 指定配置文件 webpack.config.js 为默认文件名.

Webpack API

API的方式需要对webpack.config.js配置文件进行修改, 增加HotModuleReplacementPlugin插件.

Webpack 1.x

const path = require("path");
const webpack = require("webpack");

module.exports = {
  context: path.join(__dirname, "js"),
  entry: [
    "./index.js",
    "webpack/hot/dev-server",
    "webpack-dev-server/client?http://localhost:8080/",
  ],
  output: {
    path: path.join(__dirname, "www"),
    filename: "bundle.js",
    publicPath: "/",
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
  ],
};

Webpack 2.x

Webpack 2.x 需要一个额外配置 .babelrc, 增加 react-hot-loader/babel:

{
  "presets": [
    "es2015",
    "react",
    "stage-0"
  ],
  "plugins": [
    "react-hot-loader/babel"
  ]
}

webpack.config.js 模块加载器的配置, 和Webpack 1.x是不同的:

rules: [
  // Javascript模块加载器
  {
    test: /.js|jsx$/,
    exclude: /(node_modules|bower_components)/,
    use: {
      loader: "babel-loader",
      options: {
        cacheDirectory : true,
        presets: [
          ["es2015", {modules: false}]
        ],
        // ES7
        plugins: [
          // 模块动态导入
          "syntax-dynamic-import",
          "transform-async-to-generator",
          "transform-regenerator",
          // 运行时转换
          "transform-runtime"
        ]
      }
    }
  },
中间件

需要编写一个Express服务器, 并且把 webpack-dev-middleware 集成到自己的服务器中. 多用于需要高度定制的场景, 实际上之前的webpack-dev-server就是使用的 webpack-dev-middleware 来实现的, 这里可以证明.

const express = require("express");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");
const webpack = require("webpack");
const webpackConfig = require("./webpack.config.js");
const app = express();

const compiler = webpack(webpackConfig);

app.use(webpackDevMiddleware(compiler, {
  // 启用热更
  hot: true,
  filename: "bundle.js",
  publicPath: "/assets/",
  stats: {
    colors: true,
  },
  // 路由需要的
  historyApiFallback: true,
}));

app.use(webpackHotMiddleware(compiler, {
  log: console.log,
  
  path: "/__webpack_hmr",
  heartbeat: 10 * 1000,
}));

app.get("/", function(req, res) {
  res.send("Hello World");
});

const server = app.listen(3000, function() {
  const host = server.address().address;
  const port = server.address().port;

  console.log("Example app listening at http://%s:%s", host, port);
});

对于这种形式的热更, 需要配合使用 webpack-hot-middleware.

Javascript 模块的热替换

需要在入口文件里面添加 module.hot.accept 配置, 下面给出入口文件的完整代码:

import React from "react";
import ReactDOM from "react-dom";

import {
  BrowserRouter as Router
  Route,
  Link
} from "react-router-dom"; // React Router v4 版本.

import App from "./App";

import { AppContainer } from "react-hot-loader";
const render = (Component) => {
  ReactDOM.render(
    
      
    ,
    document.getElementById("App")
  );
}
render(App);
if (module.hot) {
  module.hot.accept("./App", () => { render(App) });
}

原先直接挂载App, 要使用HMR, 需要在外层包一个容器.

多端同步刷新
这个视频, 是Chrome, Safari, Firefox 三端同步操作的示例.

对于需要支持全平台(移动, 桌面, Web)的开发, 可以使用 BrowerSync 这个神器. 它通过 Websocket 同步事件.

首先, 把模块包含进来:

const BrowserSyncPlugin          = require("browser-sync-webpack-plugin");

其次, 配置插件:

new BrowserSyncPlugin({
  host: "localhost",
  port: 3000,
  // server: {            // 独立服务器模式, 这里我使用的代理模式, 注释掉了
  //   baseDir: ["dist"]  // 监视的目录, 其中如果文件发生变化, 刷新页面
  // },
  proxy: "http://localhost:8080/"
}, {
  name: "dev",
  reload: false // 不让 BrowerSync 刷新页面, 让 webpack-dev-server 管理页面是否需要刷新.
}),

这里我使用代理模式, 因为除了 BrowerSync 的功能外, 我还要使用 webpack-dev-server HMR功能. 具体配置参考: https://github.com/Va1/browse...

参考:

https://github.com/search?utf...
https://github.com/webpack/we...
https://github.com/glenjamin/...
http://acgtofe.com/posts/2016...
https://github.com/Va1/browse...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82771.html

相关文章

  • webpack工具替换 -- angularjs的粗放式实现

    摘要:参照组件单一职责,单个模块文件仅承担有限职责,。路由声明与组件声明在统一文件内部声明。组件替换约定服务在内部属于单例,实例声明通过的方式,声明服务。指令热替换同样采用较为粗放的容器定位策略,通过路由模板替换实现。 ng-hot-loader 前言 webpack-dev-server自带支持模块热替换特性(HMR),不刷新页面实现代码局部更新,使用HMR可以大幅提升开发效率。 实现目标...

    Eminjannn 评论0 收藏0
  • Node.js 更新(一)

    摘要:直到最近在使用微信机器人时,遇到了强烈的需求。增删文件后热更新上面的代码已经不小心实现了增加文件后热更新,因为表示检测的更新,如果增加一个,那么就变成,于是新模块不等于老模块不存在,从而使用注册事件监听器。 背景 刚思考这个话题的时候,首先想到的是 Vue 或 React 的组件热更新(基于 Webpack HMR),后来又想到了 Lua、Erlang 等语言的热更新,不过在实际开发 ...

    LancerComet 评论0 收藏0
  • 一份关于webpack2模块打包的新手指南

    摘要:使用让从打包文件中删除未使用的导出项以减少文件大小。最后,用以下内容替换的部分在命令行中运行将以监视模式启动,当目录中的文件更改时,它将重新编译。这种转换涉及三个单独的加载器和库在配置文件中为文件添加新规则。 webpack已成为现代Web开发中最重要的工具之一。它是一个用于JavaScript的模块打包工具,但是它也可以转换所有的前端资源,例如HTML和CSS,甚至是图片。它可以让你...

    tianren124 评论0 收藏0
  • 如何打造一个令人愉悦的前端开发环境(四)

    摘要:在前后端分离的前端项目开发中经常用到。是的一个中间件。即是一个重要的功能。配置先来在配置文件中引入添加一个和通信的客户端添加应用入口文件在插件中引入在我们的开发环境中是这样配置的。 原文链接此文是我同事写的,搭建Express结合Webpack。以下是正文,后面我会附上我的解读 Express 结合 Webpack 实现HMR 本篇文件主要讲结合 Webpack 和 Express 实...

    StonePanda 评论0 收藏0
  • 如何打造一个令人愉悦的前端开发环境(四)

    摘要:在前后端分离的前端项目开发中经常用到。是的一个中间件。即是一个重要的功能。配置先来在配置文件中引入添加一个和通信的客户端添加应用入口文件在插件中引入在我们的开发环境中是这样配置的。 原文链接此文是我同事写的,搭建Express结合Webpack。以下是正文,后面我会附上我的解读 Express 结合 Webpack 实现HMR 本篇文件主要讲结合 Webpack 和 Express 实...

    animabear 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<