likes
comments
collection
share

Webpack热更新之DevServer

作者站长头像
站长
· 阅读数 21

我们在平时的实际开发当中,都会起一个服务来实时查看改动后的效果。我们很多时候都是直接npm run xxx来把这个服务起起来,但具体是怎么配置的呢?

这其实都依赖于webpack-dev-server

webpack-dev-server简称DevServer,是一个官方提供的开发者工具,使用后它会启动一个 HTTP 服务器用于服务网页请求,同时会帮助启动 Webpack ,并接收 Webpack 发出的文件更变信号,通过 WebSocket 协议自动刷新网页做到实时预览。

磨刀不误砍柴工

在了解更多之前,让我们来先看看我们这次的测试例子,目录结构如下

.
|-- package-lock.json
|-- package.json
|-- src
|   |-- index.css
|   |-- index.html
|   |-- index.js
|   `-- show.js
`-- webpack.config.js

我们在package.json中写入"dev": "webpack"脚本,使得我们可以直接通过运行npm run dev来编译项目。

然后初始化index.html,写一个id="app"的块级元素,但里面什么内容都没有。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app"></div>
</body>
</html>

再然后在index.css中为这个块级元素上色,就红色好了:#app { color: red; }

紧接着,我们通过show.js为块级元素插入内容,随便什么都行,但别忘了导出,因为我们待会要在index.js中导入。

function show (name) {
    const app = document.querySelector('#app')
    app.innerHTML = '你好,' + name
}

module.exports = show

最后,我们在index.js中导入刚刚写的 css 与 show 模块。

require('./index.css')
const show = require('./show')

show('Webpack')

最最后,我们来初始化一下我们的 webpack.config.js

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist')
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html'
        })
    ]
}

我们告诉 webpack 以src目录下的index.js为入口,并帮我们把编译后的文件放到当前目录下的dist目录下。并且,我们使用MiniCssExtractPlugin这个插件来帮我们把css单独抽离出来;使用HtmlWebpackPlugin这个插件来使 webpack 打包后自动创建一个 html 文件,并把打包后的静态资源自动插入到这个 html 文件中,比如被抽离出来的 css 和 编译出来的 bundle.js,这样我们就不用频繁的手动添加修改 index.html 的静态资源了。

我们运行完 npm run dev,能看到dist目录顺利生成,且css也被剥离了出来,使用live server打开dist目录下的index.html也能看到出现了红色的【你好,webpack】了。

我们每次修改文件,都要再手动执行一遍npm run dev,然后才能查看修改的结果,效率实在太低了!因此,DevServer是时候登场了!

使用 DevServer

首先安装 DevServer:npm i -D webpack-dev-server

然后修改package.json中的dev脚本,修改如下:

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

发现了吗?我们只是把其中的webpack替换成了webpack-dev-server,就是如此简单!

我们重新运行npm run dev,这时控制台输出了一串日志

Webpack热更新之DevServer

这意味着 DevServer 启动的 HTTP 服务器监听在 http://localhost:8080/ ,DevServer 启动后会一直驻留在后台保持运行,我们这个时候再把index.js中的传参修改成DevServer,你会发现网页中的Webpack实时的改变成了DevServer

Webpack热更新之DevServer

我们会发现DevServer并没有为我们生成所谓的dist目录,那是因为这个东西其实被放到了内存当中而非磁盘当中,使得httpServer能够更快更高效的读取这些文件,还能避免读盘造成的磁盘碎片,保障我们硬盘的使用寿命。

服务虽然已经启动了,但我们仍想做更多事情。比如我想在8081端口打开而非8080,我想跨过浏览器同源策略与后端进行联调等等,这要如何配置呢?

其实这也很简单,我们只需要在 webpack 的配置文件中添加一个 devServer 属性即可。

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist')
    },
    mode: 'development',
    module: {
        // ...
    },
    plugins: [
        // ...
    ],
    devServer: {
        port: 8081, // 更改端口号
        proxy: { // 反向代理服务
            '/api': 'http://localhost:3000'
        }
    }
}

现在,我们的网页将会在8081端口打开,并且对/api/user的请求将会被代理到http://localhost:3000/api/user,如果不希望传递/api,则需要重写路径:

module.exports = {
    // ...
    devServer: {
        port: 8081, // 更改端口号
        proxy: { // 反向代理服务
            '/api': {
                target: 'http://localhost:3000',
                pathRewrite: { '^/api': '' },
            }
        }
    }
}

除了通过重新刷新整个网页来实现实时预览,DevServer 还有一种被称作模块热替换的刷新技术。模块热替换能做到在不重新加载整个网页的情况下,通过将被更新过的模块替换老的模块,再重新执行一次来实现实时预览。模块热替换相对于默认的刷新机制能提供更快的响应和更好的开发体验,它能保留在完全重新加载页面期间丢失的应用程序状态。模块热替换默认是关闭的,要开启模块热替换,有两种方式

  1. 通过命令行使用,即在我们的package.json脚本中添加--hot字段,比如当前我们的例子项目中为"dev": "webpack-dev-server --hot"
  2. 通过配置文件的devServer添加hot: true开启,即:
module.exports = {
    // ...
    devServer: {
        port: 8081, // 更改端口号
        proxy: { // 反向代理服务
            '/api': {
                target: 'http://localhost:3000',
                pathRewrite: { '^/api': '' },
            }
        },
        hot: true // 开启热模块更新
    }
}

总结

DevServer 还有许多配置项,比如告诉 dev-server 在服务器已经启动后打开浏览器,设置 devServer.opentrue,设置 devServer.compress 来开启或关闭 gzip 压缩,设置 host0.0.0.0 来让外部访问我们的服务。

上面介绍的配置已经能满足我们绝大部分的实际开发,但我们有时候也会需要 DevServe 的其他功能,我们可以通过查阅Devserver官方文档来了解最新的配置选项,然后根据我们所需要的功能,来选择合适的配置项。