Webpack5学习 --- devServer和resolve

2,775 阅读8分钟

devServer

publicPath

output.publicPath

output中的path的作用是告知webpack之后的输出目录, 比如静态资源的js、css等输出到哪里,常见的会设置为dist、build文件夹等;

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

实际的资源路径为域名 拼接上 output.publicPath 拼接上 资源路径

publicPath的默认值是一个空字符串,所以我们打包后引入js文件时,路径是 bundle.js,实际路径就变为了域名+ ’‘+bundle.js,此时浏览器会自动在bundle.js前边加上/,变成例如http://www.example/bundle.js

在开发中,我们也将其设置为 / ,路径是 /bundle.js,这样可以放置某些浏览器可能没法为我们自动添加/

但是,如果设置了publicPath为/,那么在本地直接打开html文件来运行会存在问题,

因为本地访问的路径是file:///Users/example/xxxx/xxx/webpack-demo/dist/index.html, 此时bundle.js的路径为/bundle.js

进行路径拼接后就会变为file:///bundle.js,此时就会因为找不到bundle.js而报错

所以如果需要在本地打开进行调试的时候,可以会将publicPath设置为./,此时对应的路径会转换为./bundle.js,可以根据相对路径去查找资源。

devServer.devMiddleware.publicPath

devServer.devMiddleware.publicPath其实就是webpack-dev-server在V3版本中的devServer.publicPath, 详情见迁移说明

该属性设置的是搭建本地服务的时候,express中各个资源请求路由的公共路径,默认值是/

这个属性实际修改的是devServer本地开启的express的路由映射

例如:

devServer.devMiddleware.publicPath的值为/的时候

请求/bundle.js -> 匹配路由/bundle.js -> 返回资源

当设置值为/abc的时候,路由会全部添加前缀/abc

/bundle.js ->/abc/bundle.js->返回原来/bundle.js所对应的路由资源

注意: 默认情况下output.publicPath的值是空字符串,所以此时在页面中所有打包后资源请求的路径都是类似于bundle.js的路径

所以是无法准确匹配对应路由,所以资源都是404,为了让打包后的资源的请求路径和路由的路径一致,需要修改output.publicPath

的值和devServer.devMiddleware.publicPath的值保持一致

因此: 建议 devServer.devMiddleware.publicPath 与 output.publicPath所配置的路径应该时刻保持相同

contentBase

devServer中contentBase用来设置打包后的资源,又依赖于其他的一些资源的路径

此时contentBase就可以用来设置这些静态资源的基准路径

比如在index.html中,我们需要依赖一个 abc.js 文件,这个文件我们存放在 public文件 中

在index.html中,我们应该如何去引入这个文件呢?

  1. index.html引入代码是这样的: <script src="./abc.js"></script>

  2. 此时如果没有contentBase,是无法在webpack-dev-server提供的服务中找到对应资源

    因为默认情况下,如果它发现是相对路径的时候,是以项目根目录去进行查找

  3. 此时可以设置contentBasecontentBase: path.resolve(__dirname, './public')

    ps: contentBase的值虽然可以设置为相对路径,但是推荐设置为绝对路径

此时devServer就会以public为相对路径查找的基准路径

当然这么做是仅仅是针对于devServer,如果位于生产环境,依旧需要使用copyWebpackPluign将相关资源进行复制

watchContentBase

默认情况下,静态资源的修改,是不会触发devServer的HMR,因为静态资源并不是一个模块

所以可以设置watchContentBase的值为true,此时当静态资源发生更新的时候,

devServer会自动刷新对应的页面,从而更新界面

proxy

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

比如我们的一个api请求是 http://localhost:8888 但是本地启动服务器的域名是 http://localhost:8000 这个时候发送网络请求就会出现跨域的问题

那么我们可以将请求先发送到一个代理服务器,代理服务器帮助我们进行请求的转发,因为跨域是浏览器端限制,所以代理服务器和API服务器没有跨域的问题,就可以解决我们的 跨域问题了

devServer: {
    proxy: { 
      "/api": { // 请求路径前缀
        // /api/moment会被代理到 https://www.example.com/api/moment;
        target: 'https://www.example.com', // 表示的是代理到的目标地址
        changeOrigin: true, // 默认情况下,代理时会保留主机头的来源,可以将 changeOrigin 设置为 true 以覆盖此行为
        secure: false, // 默认情况下,将不接受在 HTTPS 上运行且证书无效的后端服务器。 如果需要可以关闭校验
        pathRewrite: { // 重写路由
         // /api/moment ====> https://www.example.com/api/moment
         // 但是实际接口为 https://www.example.com/moment
          "^/api": ''
        }
      }
    }
}

如果没有任何的设置,可以简写为

module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': 'https://www.example.com',
    },
  },
};

如果想将某个特定路径代理到同一目标,则可以使用一个或多个context属性的对象的数组

module.exports = {
  //...
  devServer: {
    proxy: [
      {
        context: ['/auth', '/api'],
        target: 'https://www.example.com',
      },
    ],
  },
};

historyApiFallback

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

因为在SPA中的路由是前端路由,直接刷新的时候,后台是不存在对应路由的,因此会报404错误

当使用HTML5历史API时,所有的404请求都响应index.html的内容。 将devServer.historyApiFallback设为true开启

module.exports = {
  //...
  devServer: {
    historyApiFallback: true,
  },
};

通过传递对象,可以使用配置选项rewrites,设置不同路由的默认跳转路径

module.exports = {
  //...
  devServer: {
    historyApiFallback: {
      rewrites: [
        { from: /^\/$/, to: '/views/landing.html' },
        { from: /^\/subpage/, to: '/views/subpage.html' },
        { from: /./, to: '/views/404.html' },
      ],
    },
  },
};
historyApiFallback: {
  index: '/', // 默认返回的资源是index.html, 可以使用index属性修改默认返回的资源
  disableDotRule: true
  
  // disableDotRule 选项可以在路径匹配的时候忽略路径中的点
  
  // 有路由 /:param

  // disableDotRule为 false
  // https://www.example.com/foo.html ===> 404

  // disableDotRule为 true
  // https://www.example.com/foo.html ===> 匹配成功 param的值为 foo.html
}

其它配置选项

选项功能
hot实时监听文件的修改,在文件内容发生改变的时候,自动去刷新界面以显示最新的内容
默认值是true
可以设置的值有true和'only'
设置为’only‘的时候,会关闭自动检测文件内容的改变
host设置主机地址
默认值是localhost,如果希望其他地方也可以访问,可以设置为 0.0.0.0
port设置监听的端口,默认情况下是8080
open是否打开浏览器
默认值是false,设置为true会打开浏览器
compress是否为静态文件开启gzip compression
会在响应头中添加content-encoding: gzip
浏览器接收到gzip格式文件后会自动对gzip文件进行解压缩操作
默认值是false,可以设置为true

localhost 和 0.0.0.0 的区别:

  1. localhost:本质上是一个域名,通常情况下会被解析成127.0.0.1

  2. 127.0.0.1:回环地址(Loop Back Address),表达的意思其实是我们主机自己发出去的包,直接被自己接收

    • 正常的数据库包经常 应用层 - 传输层 - 网络层 - 数据链路层 - 物理层
    • 而回环地址,是在网络层直接就被获取到了,是不会经常数据链路层和物理层的
    • 比如我们监听 127.0.0.1时,在同一个网段下的主机中,通过ip地址是不能访问的;
  3. 0.0.0.0:监听IPV4上所有的地址,再根据端口找到不同的应用程序;

    • 比如我们监听 0.0.0.0时,在同一个网段下的主机中,通过ip地址是可以访问的

resolve

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

在开发中我们会有各种各样的模块依赖,这些模块可能来自于自己编写的代码,也可能来自第三方库,resolve可以帮助webpack从每个 require/import 语句中,找到需要引入到合适的模块代码

webpack能解析三种文件路径:

路径解析
绝对路径由于已经获得文件的绝对路径,因此不需要再做进一步解析
相对路径在这种情况下,使用 import 或 require 的资源文件所处的目录,被认为是上下文目录
在 import/require 中给定的相对路径,会拼接此上下文路径,来生成模块的绝对路径
模块路径在 resolve.modules中指定的所有目录检索模块
(默认值是 ['node_modules'],所以默认会从node_modules中查找文件)
也可以通过设置别名的方式来替换模块的查找路径规则

webpack查找模块的规则:

如果是一个文件:

  1. 如果文件具有扩展名,则直接打包文件
  2. 否则,将使用 resolve.extensions选项作为文件扩展名解析

如果是一个文件夹:

会在文件夹中根据 resolve.mainFiles配置选项中指定的文件顺序查

  • resolve.mainFiles的默认值是 ['index']
resolve: {
  // 配置后缀名的时候,新的配置会覆盖默认的配置,所以需要加上默认的配置
  // 每一个文件的后缀名应该以点来开头
  extensions: ['.js', '.json', '.ts'],

  alias: {
    // alias的值推荐设置为绝对路径,因为我们无法确定实际是在那个目录层级来使用别名
    '@': path.resolve(__dirname, './src'),
    'utils': path.resolve(__dirname, './src/utils')
  }
}