七、webpack搭建本地服务

2021-05-01  本文已影响0人  AShuiCoder

为什么要搭建本地服务器?
目前我们开发的代码,为了运行需要有两个操作:

这个过程经常操作会影响我们的开发效率,我们希望可以做到,当文件发生变化时,可以自动的完成 编译 和 展示。
为了完成自动编译,webpack提供了几种可选的方式:

接下来,我们一个个来学习一下它们。

1. Webpack watch

webpack给我们提供了watch模式:

如何开启watch呢?两种方式:

这里我们选择方式二,在package.json的 scripts 中添加一个 watch 的脚本:

{
  "scripts": {
    "build": "webpack --watch"
  }
}

2. webpack-dev-server

上面的方式可以监听到文件的变化,但是事实上它本身是没有自动刷新浏览器的功能的, 当然,目前我们可以在VSCode中使用live-server来完成这样的功能,但是,我们希望在不适用live-server的情况下,可以具备live reloading(实时重新加载)的功能。
webpack-dev-server 在编译之后不会写入到任何输出文件。而是将 bundle 文件保留在内存中,
事实上webpack-dev-server使用了一个库叫memfs。
安装

yarn add  webpack-dev-server -S

使用
package.json

{
  "scripts": {
    "serve": "webpack serve"
  }
}

webpack serve是webpack5的写法

3. webpack-dev-middleware

webpack-dev-middleware 是一个封装器(wrapper),它可以把 webpack 处理过的文件发送到一个 server。webpack-dev-server 在内部使用了它,然而它也可以作为一个单独的 package 来使用,以便根据需求进行更多自定义设置。
我们可以搭配一个服务器来使用它,比如express。
安装

yarn add express webpack-dev-middleware

新建server.js

const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();

const config = require("./webpack.config");

// 传入配置信息, webpack根据配置信息进行编译
const compiler =  webpack(config);

const middleware = webpackDevMiddleware(compiler);
app.use(middleware);

app.listen(3000, () => {
  console.log("服务已经开启在3000端口上~");
});

运行命令node server.js,然后就能在http://loacalhost:3000看到效果啦。

4. 模块热替换(HMR)

什么是HMR呢?

如何使用HMR呢?

4.1 开启HMR

webpack.config.js

module.exports = {
  devServer: {
    hot: true
  },
}

目前devserver和brwserlist工具有冲突,在webpack.config.js加入target: "web"

module.exports = {
    target: 'web'
}

然后执行yarn serve就能看到热更新提示

image.png
但是你会发现,当我们修改了某一个模块的代码时,依然是刷新的整个页面,这是因为我们需要去指定哪些模块发生更新时,进行HMR。
入口文件:
if (module.hot) {
  module.hot.accept("./math.js", () => {
    console.log("math模块发生了更新~");
  });
}

4.2 框架的HMR

有一个问题:在开发其他项目时,我们是否需要经常手动去写入 module.hot.accpet相关的API呢?

接下来我们分别对React、Vue实现一下HMR功能。

4.2.1 React的HMR

在之前,React是借助于React Hot Loader来实现的HMR,目前已经改成使用react-refresh来实现了。
安装实现HMR相关的依赖

yarn add react-refresh-webpack-plugin react-refresh -D

webpack.config.js

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
module.exports = {
  plugins: [
    new ReactRefreshWebpackPlugin(),
  ]
};

babel.config.js

module.exports = {
  presets: [
    ["@babel/preset-env"],
    ["@babel/preset-react"],
  ],
  plugins: [
    ["react-refresh/babel"]
  ]
}

4.2.2 Vue的HMR

Vue的加载我们需要使用vue-loader,而vue-loader加载的组件默认会帮助我们进行HMR的处理。
第六节已经介绍过vue-loader。

4.3 HMR的原理

那么HMR的原理是什么呢?如何可以做到只更新一个模块中的内容呢?

HMR Socket Server,是一个socket的长连接:

HMR的原理图:


image.png

5. publicPath

5.1 output的publicPath

output中的path的作用是告知webpack之后的输出目录:

output中还有一个publicPath属性,该属性是指定index.html文件打包引用的一个基本路径:

module.exports = {
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './build'), // 出口文件必须要用相对路径
    publicPath: './'
  }
}

5.2 devServer的publicPath

devServer中也有一个publicPath的属性,该属性是指定本地服务所在的文件夹:

6. devServer的其他属性

6.1 contentBase

devServer中contentBase对于我们直接访问打包后的资源其实并没有太大的作用,它的主要作用是如果我们打包后的资源,又依赖于其他的一些资源,那么就需要指定从哪里来查找这个内容:

当然在devServer中还有一个可以监听contentBase发生变化后重新编译的一个属性:watchContentBase。
目录结构如下:


image.png

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
  <div id="root"></div>

  <script src="./abc.js"></script>
</body>
</html>

webpack.config.js

module.exports = {
  devServer: {
    contentBase: path.resolve(__dirname, "./why"),
    watchContentBase: true
}

6.2 hotOnly

hotOnly是当代码编译失败时,是否刷新整个页面:

6.3 host

host设置主机地址:

localhost 和 0.0.0.0 的区别:

6.4 port

port设置监听的端口,默认情况下是8080

6.5 open

open是否打开浏览器:

6.6 compress

compress是否为静态文件开启gzip compression,默认值是false,可以设置为true。

6.7 Proxy代理

proxy是我们开发中非常常用的一个配置选项,它的目的设置代理来解决跨域访问的问题:

我们可以进行如下的设置:

changeOrigin的解析
changeOrigin其实是要修改代理请求中的headers中的host属性:

webpack.config.js

  devServer: {
    proxy: {
      "/why": {
        target: "http://localhost:8888",
        pathRewrite: {
          "^/why": ""
        },
        secure: false,
        changeOrigin: true
      }
    }
  }

6.8 historyApiFallback

historyApiFallback是开发中一个非常常见的属性,它主要的作用是解决SPA页面在路由跳转之后,进行页面刷新
时,返回404的错误。

7. resolve模块解析

resolve用于设置模块如何被解析:

webpack能解析三种文件路径:

7.1 文件还是文件夹

如果是一个文件:

如果是一个文件夹:

7.2 extensions和alias配置

extensions是解析到文件时自动添加扩展名:

另一个非常好用的功能是配置别名alias:

webpack.config.js

resolve: {
    extensions: ['.wasm', '.mjs', '.js', '.json', '.jsx', '.ts', '.vue'],
    alias: {
      "@": path.resolve(__dirname, "./src"),
      "pages": path.resolve(__dirname, "./src/pages")
    }
}
上一篇 下一篇

猜你喜欢

热点阅读