前端webpack构建react系列二:开发阶段,热模块替换(HMR,热更新)

热更新

在前端开发中,我们做的最频繁的是刷新浏览器,清楚缓存。如果以webpack打包方式开发,修改代码的时候我们还需要重新构建,再重新刷新浏览器,效率肯定很低。

采用热更新技术可以提高效率,通俗就是说,我一修改js文件且保存,webpack自动构建,浏览器自动刷新。

感觉很黑科技,其实就是用webpack把js打包到内存里面,为了达到此效果,我们需要配置一个本地服务器,主页面请求此服务器的js,css等资源,前台和后台通过websocket协议传输, 所以就能实时更新。服务器模块可以选择express也可以使用webpack推荐的webpack-dev-server,这里我选择的是webpack-dev-server

搭建热更新服务器

依赖包
[email protected]

通过webpack-dev-server配置热更新,有两种方式,一种是用nodejs方式启动,另外一种是通过webpack-dev-server命令,第二种需要全局安装webpack-dev-server,这里我选择nodejs配置,不需要全局安装,本地安装即可

第一篇文章已经在项目目录下载好了基本依赖包。我们就从第一篇文章介绍的项目入手,使其支持热更新。

注意,我的webpack版本是3.10.0,webpack-dev-server就必须选用2.x.x。这是个坑,之前我下载的webpack-dev-server是3.X.X,导致一直报错comp.hooks.compile.tap(‘webpack-dev-server’, invalidPlugin);。最后看到某篇帖子,这位仁兄说他也是在google里面才找到答案,如果webpack是4.x.x,那么webpack-dev-server就是3.x.x,如果webpack是3.x.x,webpack就选2.x.x。

1、首先我们在根目录下创建一个webpack.config.dev.js文件,代码如下

var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: {
        bundle:['webpack-dev-server/client?http://127.0.0.1:9090','webpack/hot/dev-server','./index.js'] (1)
    },

    output: {
        path: __dirname + '/build/',
        filename:'bundle.js',
        publicPath: './'
    },
    module:{
        loaders:[
            {
                test: /\.js$/,         
                loader:'babel-loader',
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract("css-loader","style-loader")
            },
            {
                test: /\.(png|jpg)$/,
                loader: 'url-loader?limit=8192&name=distImg/[name].[ext]'
            }
        ]
    },
    plugins:[
        new ExtractTextPlugin('prefixer_main.css', {
            disable: false,
            allowChunks: true
        }),
        new webpack.HotModuleReplacementPlugin()    (2)
    ]
}

(1):入口文件写成数组形式,一旦webpack开始工作,所有的模块都会被加载进来,最后一个会被输出(看文档自己翻译,不是很懂,这里数组的前2个就得这么写,具体原因我也不是很清楚,’webpack-dev-server/client?http://127.0.0.1:9090‘这个是用于配置webpack-dev-server的inline模式(nodejs方式启动webpack-dev-server)。
(2): 插件项,打包构建过程中的动作,生成内存中的热替换块(看文档自己翻译,我想就是打包后放到内存中的动作吧)

2、我们在根目录下创建一个server.js文件

var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config.dev')    (1)

new WebpackDevServer(webpack(config),{
    publicPath:'http://127.0.0.1:9090/storage', (2) 
    hot: true,  (3)
    inline : true,  (4)
    historyApiFallback: true,  (5)
}).listen(9090,'127.0.0.1',function(err, result){   (6)
    if(err){
        console.log(err)
    }else{
        console.log('Listening at 127.0.0.1:9090'); 
    }
})

(1):将webpack.config.dev的配置引入。
(2):在index.html里面的script src=”http://127.0.0.1:9090/storage/bundle.js”的依据就是它(这里我也是只知其然,不知所以然,通过测试试出来的)。
(3):开启热更新
(4):webpack-dev-server的inline模式,基本常用这个模式,它还有一个iframe模式, iframe mode实际上是在网页中嵌入了一个iframe,然后将我们自己的应用注入到这个iframe 当中去, 当每次文件被修改后,这个iframe会进行了reload,当我们用iframe模式的时候,需要浏览器中输入http://127.0.0.1:9090/webpack-dev-server/index.html(inline mode下直接输入http://127.0.0.1:9090)同时,webpack.config.dev中入口文件项entry中配置的’webpack-dev-server/client?http://127.0.0.1:9090‘就不需要了。两者在实际效果没区别,一般我们都用的是inline模式。
(5):在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,不存在的页面会被替换成index.html,比如你访问http://127.0.0.1:9090/q2e/dfef 和 http://127.0.0.1:9090一样会返回http://127.0.0.1:9090/index.html资源
(6):通过webpack(config)将配置配到WebpackDevServer上,然后监听127.0.0.1的9090端口。这样webpack-dev-server配置热更新完毕。

3、新建一个index.html文件。


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>INDEXtitle>
    <link rel="stylesheet" href="http://127.0.0.1:9090/storage/prefixer_main.css" type="text/css" />
head>
<body>
    <div id='main'>div>
    <script src="http://127.0.0.1:9090/storage/bundle.js">script>
body>
html>

现在项目的结构如下
前端webpack构建react系列二:开发阶段,热模块替换(HMR,热更新)_第1张图片

4、打开cmd定位到根目录运行 node server.js,然后访问127.0.0.1::9090,最后更改index.js,此时不用手动构建和刷新浏览器,页面自动刷新。

此时,项目目录并未生成build目录。我们用dom探测器查看页面。
前端webpack构建react系列二:开发阶段,热模块替换(HMR,热更新)_第2张图片

前端webpack构建react系列二:开发阶段,热模块替换(HMR,热更新)_第3张图片
前端webpack构建react系列二:开发阶段,热模块替换(HMR,热更新)_第4张图片
可以看到,index.html的结构和main.html(第一篇文章创建)引用资源的形式很相似。因此我猜想,webpack-dev-server将资源打包到内存,server.js的publicPath指定访问内存资源的地址(可能在我们看不见的地方生成了bundle.js,prefixer_main.css,distImg/test.png吧)。

5、修改index.js或者main.css,页面自动刷新。

再说一句

为什么要建立index.html,之前的main.html(第一篇文章创建)不行吗。其实是可以的,index.html是默认项而已,下面是如何指定为main.html

依赖包
[email protected]

修改webpack.config.dev.js

var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin'); (1module.exports = {
    entry: {
        bundle:['webpack-dev-server/client?http://127.0.0.1:9090','webpack/hot/dev-server','./index.js']
    },

    output: {
        path: __dirname + '/build/',
        filename:'bundle.js',
        publicPath: './'
    },
    module:{
        loaders:[
            {
                test: /\.js$/,         
                loader:'babel-loader',
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract("css-loader","style-loader")
            },
            {
                test: /\.(png|jpg)$/,
                loader: 'url-loader?limit=8192&name=distImg/[name].[ext]'
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template: './main.html'
        }), (2new ExtractTextPlugin('prefixer_main.css', {
            disable: false,
            allowChunks: true
        }),
        new webpack.HotModuleReplacementPlugin()
    ]
}

(1):定义HtmlWebpackPlugin ; (2):在plugins添加HtmlWebpackPlugin,指定main.html

修改main.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>MAINtitle>
    <link rel="stylesheet" href="http://127.0.0.1:9090/storage/prefixer_main.css" type="text/css" />
head>
<body>
    <h3>I AM THE MAIN.HTMLh3>
    <div id='main'>div>
    <script src="http://127.0.0.1:9090/storage/bundle.js">script>
body>
html>

在项目目录输入 node server.js。访问http://127.0.0.1:9090/main.html(不能直接用http://127.0.0.1:9090)。在这里,如果页面不存在就不会重定向到index.html里面了。为了方便还是用默认的index.html吧。

小结

下一篇会介绍分模块打包,使部署更合理。

git地址:https://github.com/kiramario/hello-world.git

你可能感兴趣的:(环境配置)