普通视图

发现新文章,点击刷新页面。
昨天 — 2025年5月19日首页

一文读懂 webpack 配置选项 output.publicPath

2025年5月18日 00:43

引出问题

入口文件为:

// src/index.js
import path from './assets/webpack.png';
console.log(path);
const img = document.createElement('img');
img.src = path;
document.body.appendChild(img);

配置文件为:

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  output: {
    filename: 'scripts/[name].[chunkhash:3].js',
    clean: true
  },
  devServer: {
    open: 'html/index.html',
    static: './dist'
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'html/index.html'
    })
  ],
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        use: {
          loader: 'file-loader',
          options: {
            name: 'img/[name].[hash:3].[ext]'
          }
        }
      }
    ]
  }
}

打包后 dist 目录的结构为:

dist
  |—— img
    |—— webpack.xxx.png
  |—— scripts
    |—— main.yyy.js
  |—— html
    |—— index.html

打包生成的 dist/html/index.html 文件:

该文件由 html-webpack-plugin 生成,作为一个插件,它知道最终输出的文件在 dist 目录中的位置,因此能够正确引入

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Webpack App</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script defer src="../scripts/main.yyy.js"></script>
  </head>
  <body>
  </body>
</html>

运行 dist/html/index.html 文件(请求 http://localhost:8080/html/index.html 页面),浏览器控制台输出:img/webpack.xxx.png,该相对路径最终转换成的绝对路径为 http://localhost:8080/html/img/webpack.xxx.png,图片找不到

问题出现的原因

src/assets/webpack.png 图片会交给 file-loader 处理,作为一个 loader,它在运行时,webpack 还未输出文件到 dist 目录,因此,它只知道最终生成到 dist 目录中的图片路径为 img/webpack.xxx.png(配置该 loader 时指定的),并不知道该图片将来会被哪个文件使用

解决方法

// webpack.config.js
module.exports = {
    // ...
    output: {
        // ...
        publicPath: '/'
    }
}

output.publicPath 本质就是一个字符串,并不会影响 webpack 的打包构建过程,只不过该字段的值会被某些 plugin 和 loader 读取使用,例如 html-webpack-plugin、file-loader 等等。

配置 output.publicPath 后:

  • html-webpack-plugin 生成的 html 页面中,会将该值作为 script 标签和 link 标签引入的资源路径的前缀
  • file-loader 在处理文件时,会将该值作为输出路径的前缀
  • ...etc

所以配置了 output.publicPath="/" 后,file-loader 处理 webpack.png 图片时,输出的路径为:/img/webpack.xxx.png,转换为绝对路径后为:http://localhost:8080/img/webpack.xxx.png,路径正确,能够正常找到图片

扩展

若某些 plugin 和 loader 需要使用不同的资源路径前缀,那么可以为这些 plugin 和 loader 分别配置 publicPath,以 file-loaderhtml-webpack-plugin 为例:

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // ...
  plugins: [
    new HtmlWebpackPlugin({
      // ...
      publicPath: "abc"
    })
  ],
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        use: {
          loader: 'file-loader',
          options: {
            // ...
            publicPath: "bcd"
          }
        }
      }
    ]
  }
}

tip:并不是所有的 plugin 和 loader 都可以配置自己的 publicPath,具体可以参考其 npm 文档

❌
❌