欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

webpack使用笔记(三)配置devServer

程序员文章站 2022-07-12 19:53:54
...

配置 devServer 之前需要先下载

yarn add webpack-dev-server -D

下载好之后,就可以在 webpack 配置项中去配置 webpack-dev-server 啦。

devServer 的配置项很多,这里只对使用比较多的配置项做一下介绍。devServer 的配置应该是在开发环境下进行。下面是一个简单的配置内容:

if(isDev){      // 如果是开发环境
    config.devServer = {
        // 设置 host(默认就是 localhost)
        // 如果你希望服务器外部可访问
        // 可以这样指定:127.0.0.1
        // 即:通过 IP 地址的形式
        host: "localhost",
        // 设置端口号
        port: "8888",
        // 告诉服务器从哪个目录中提供内容
        // 默认它会查找 index.html 文件作为页面根路径展示
        contentBase: path.join(__dirname,"../build"),
        // 这个publicPath代表静态资源的路径(打包后的静态资源路径)
        publicPath: '/build/',
        // 当设置成 true时,任意的 404 响应都可能需要被替代为 index.html
        historyApiFallback: true,
        // 是否开启 模块热替换功能
        hot: true,
        // 是否让浏览器自动打开(默认是 false)
        open: true,
        // 被作为索引文件的文件名。
        // 默认是 index.html,可以通过这个来做更改
        index: 'demo.html',

        // 使用代理服务器
        proxy: {
            '/api': {
                // 当请求 /api 的路径时,就是用 target 代理服务器
                target: "http://loaclhost:3000",
                // 重写路径
                pathRewrite: {
                    '/api': ''
                }
            }
        }
    }
}

有时候我们不想使用代理,只是想单纯的模拟数据。就可以使用 webpack 给我们提供的一个 before 函数:

{
    devServer: {
        // app 参数就是 express 框架的 express 实例
        before(app){
            app.get('/api',(req,res) => {
                // to do something...
            })
        }
    }
}

在服务器内部执行自定义中间件之前 before 方法会被执行。与 before 方法对应的还有一个 after 方法,它会在服务器内部执行所有其他中间件之后执行。

第三种方式,就是使用 webpack 的端口(服务端和 webpack(前端) 是一个端口)在服务端需要下载一个中间件:webpack-dev-middleware

yarn add webpack-dev-middleware -D 

然后服务端写入以下代码:

const express = require("express");
const webpack = require("webpack");
const webpackMiddleware = require("webpack-dev-middleware");

// 引入写好的 webpack 配置文件
let config = require("./webpack.config.js");
let compiler = webpack(config);

// 绑定中间件
app.use(webpackMiddleware(compiler));

配置命令

来到 package.json 文件中,再添加一条命令,叫做 start,写下下面的内容:

{
    "script": {
        "build": "cross-env NODE_ENV='development' webpack --config config/webpack.config.dev.js",
        "start": "cross-env NODE_ENV=development webpack-dev-server --config config/webpack.config.dev.js"
    }
}

然后运行 npm start 就会自动打开浏览器,跳转到我们指定的 localhost:8888 端口。

有一点需要注意,在开发环境不要设置 publicPath,因为开发环境下 devServer 执行打包的内容是在内存里的,如果设置了 publicPath 保存后页面反而不会有刷新。应在生产环境再用 publicPath。还有一点就是,每次修改配置项都要重新运行命令,这是很费时的一件事,如何在更新配置文件后不用再次重启服务呢?这在下面会说到。

historyApiFallback 更具体的配置

通过传入一个对象,比如使用 rewrites 这个选项,可进一步地控制。

{
    devServer: {
        historyApiFallback: {
            // 是个数组
            rewrites: [
                // 表示 以 “/” 开头请求的页面,会返回 to 对应路径下的 html 文件
                { from: /^\/$/, to: '/views/landing.html' },
                { from: /^\/subpage/, to: '/views/subpage.html' },
                // 别的则会返回 404 页面
                { from: /./, to: '/views/404.html' }
            ]
        }
    }
}

devServer 中 publicPath 的配置

devServer 中的 publicPath 与 output 中的并不同。devServer 中的 publicPath 指的是 webpack-dev-server 的静态资源服务路径。假如我们打包的内容在 build 文件夹下,则 publicPath 应是 /build/,这里有个技巧,output 中指定的打包路径,比如:path: path.join(__dirname,'../build') 那么 devServer 的 publicPath 一般就是 join方法中的那个 build。如果指定别的路径,很可能就会访问不到资源。

开启模块热替换功能

开启这个功能可以让我们修改文件并保持后,页面不会出现刷新的情况,页面中的内容是被动态更替了!这样减少了页面重新绘制的时间。在 devServer 中单纯的让 hot: true 是没有作用的,还需要一个 webpack 插件。这个插件是 webpack 内置的插件,不需要下载。具体配置步骤如下:

/**
 * 来到 webpack 配置文件
 * 引入 热更替插件
*/
const webpack = require('webpack');
// 来到 devServer 选项
{  
    devServer: {
        hot: true
    },
    // 添加 plugin
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
    ]
}

配置好 webpack 之后,还需要在入口程序处检测 module.hot 是否存在(这个对象是在 webpack 打包后自动加入的)。
假如我们的程序入口文件是 index.js,可以这么来写:

// index.js
if(module.hot){
    // 调用 accept 方法开启热更替
    module.hot.accept();
}

上面步骤做完后,就可以使用热更替了。如果有多个页面,则应为每个页面的入口作检验。

accept 还可以传入一个参数,如:

// index.js
import util from './utils';
// ...
if(module.hot){
    // module.hot.decline();
    module.hot.accept(['./utils.js'], () => {
        console.log('utils.js hot module replace!!!');
    });
}

当 utils.js 内部发生变更时可以告诉 webpack 接受更新的模块,回调函数会在热模块更替后触发。decline 方法与 accept 方法作用相反,它接受一个字符串数组或者字符串(模块的路径),它会拒绝给定依赖模块的更新。

React 中使用热模块更替

在 React 中,index.js 常常做程序的入口,而 App.js 往往需要 index.js 的导入。在 index.js 中可以这么来写:

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

import App from './App.jsx';

function render(){
    ReactDOM.render(
        <App />,
        document.getElementById('root')
    )
}

render();

if (module.hot) {
    // 当第一个参数是数组时
    // 表示 有多个路径需要热模块更替
    // 回调用于在模块更新后触发的函数
    module.hot.accept('./App.jsx',() => {
        render();
    });
}

React 官方提供了一个热更替模块 —— react-hot-loader。使用它时需要下载,然后需要配置。

  • 首先需要配置 webpack 文件:
// 更改 entry:
{
    entry: ['react-hot-loader/patch', '../src/index.js'],
}
  • 然后来到 .babelrc 文件,添加一个 plugin:
{
    "plugins": ["react-hot-loader/babel"]
}
  • 来到 index.js 文件处,你就可以直接把原来判断 module.hot 的内容给删掉了。而且 webpack 配置文件也不需要再引入热更新插件(恢复没有热更新配置时的样子,但是 hot 项不要变成 false)。
  • 来到 App.js 文件,更改内容:
import { hot } from 'react-hot-loader';
function App(){
    // ....
}

// 最后这样导出:
export default hot(module)(App);

还没完,还应该重新下载一个包:yarn add @hot-loader/react-dom 这个包和 react-dom 一样,只是它有热替换功能。下载之后,在 webpack resolve 配置项中写入:

alias: {
    // 这样,你在引入 react-dom 时,就会引入这个包
    'react-dom': '@hot-loader/react-dom'
}

最后,重启服务,热更替模块就可以用了。使用 react-hot-loader 的好处就是,可以避免 React 组件的不必要渲染。