Vue 项目之 Webpack 打包图片资源——设置文件的存放路径和名称

2,466 阅读3分钟

「这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战

1. 设置文件的存放路径和名称

你可能会发现,前面我们将两张图片打包到输出的文件夹中去时,最终的效果有点丑:

  1. 打包后的图片文件直接和 js 文件放在了同一个文件夹(./build)下,那如果有 100 张图片或者到时打包出来多个 js 文件,看起来就有点乱了;
  2. 打包后的图片名称不容易直接与打包前的名称对应起来(当然,webpack 都帮我们处理好了,我们一般也不需要关心),如果我们想要将打包前后的图片对照起来看,只能一个个的点开来确认。所以当前打包后的文件名也不好看。

那么,如何设置打包后的文件所在的文件夹以及文件名呢?在讲设置方法之前,我们先来看下关于文件的命名规则:

  • 有时候我们需要处理后的文件名称按照一定的规则进行显示:
    • 比如保留原来的文件名、扩展名,同时为了防止重复,还会包含一个 hash 值(比如有两个不同的文件夹下存在两张同名但内容不同的图片,我们引用它们时的路径是不一样的,而它们虽然名字一样,但由于内容是不一样的,所以打包出来的 hash 值也是不一样的,所以到时候还是可以做一个区分的)等等;
  • 这个时候我们可以使用 PlaceHolders 来完成,webpack 给我们提供了大量的 PlaceHolders 来显示不同的内容:
  • 我们这里介绍几个最常用的 placeholder
    • [ext]:获取文件的扩展名,extextension 的缩写;
    • [name]:获取文件的名称(不包括扩展名);
    • [hash]:文件的内容,使用 MD4 的散列函数处理,生成的一个 128 位的 hash 值(32 个十六进制数);
    • [contentHash]:在 file-loader 中和 [hash] 的值是一致的(在 webpack 的一些其它地方不一样,后面会讲到);
    • [hash:<length>]:截取 hash 的长度,因为默认的 32 个字符太长了,我们可以截取其中的几位进行显示;
    • [path]:文件相对于 webpack 配置文件的路径,用得比较少;

下面,我们可以先删除项目中的 ./build 文件夹,然后来到 webpack.config.js 文件中进行配置:

...

module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        use: {
          loader: 'file-loader',
          options: {
            outputPath: 'img' // 指定目标文件到时候存放的路径
          }
        }
      }
    ]
  }
}

上面的配置中,我们将原先的 use: 'file-loader' 改成了对象形式(我们前面讲过,每个 loader 都是可以传入对应的参数的,如果想要给这个 loader 传入参数,就可以在 use 属性后面跟上一个对象,而如果是多个 loader,则需要在 use 属性后面跟上一个数组)。然后我们运行 npm run build 命令打包看下效果:

image-20211110232330225

可以看到,输出目录下生成了一个 img 文件夹,里面存放的就是打包后的那两张图片。这就意味着,通过设置 file-loaderoutputPath 选项,就能把它匹配到的文件资源最终打包到对应的路径下了。

file-loader 除了 outputPath 选项,还有一个 name 选项,用来为目标文件指定一个自定义的文件名模板,比如如果我们设置 name: '123.png',就意味着所有的图片到时打包后都会叫做 123.png,所以我们肯定不能把它写死,这时我们就可以使用前面介绍的占位符(Placeholders)来自定义文件名模板:

...

module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        use: {
          loader: 'file-loader',
          options: {
            outputPath: 'img', // 指定目标文件到时候存放的路径
            name: '[name].png' // 指定目标文件打包后使用的名称
          }
        }
      }
    ]
  }
}

然后我们先删除项目中的 ./build 文件夹,再来打包看下效果:

image-20211110234151656

这次,两张图片就都保留了原来的名称。当然,有时候图片名称可能是相同的,这时为了区分,一般会使用 hash 值:

...

module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        use: {
          loader: 'file-loader',
          options: {
            outputPath: 'img', // 指定目标文件到时候存放的路径
            name: '[name]_[hash:6].png' // 指定目标文件打包后使用的名称
          }
        }
      }
    ]
  }
}

这次修改,我们添加了 hash 值,并只截取了 6 位,同时在 namehash 之间用 _ 做了隔断,这只是为了方便区分,你也可以使用别的符号,比如 -,甚至不使用也可以。然后我们先删除项目中的 ./build 文件夹,再来打包看下效果:

image-20211110234821301

前面我们打包后的图片文件后缀名是写死的,其实我们也可以使用图片原来的后缀名:

...

module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        use: {
          loader: 'file-loader',
          options: {
            outputPath: 'img', // 指定目标文件到时候存放的路径
            name: '[name]_[hash:6].[ext]' // 指定目标文件打包后使用的名称
          }
        }
      }
    ]
  }
}

然后我们先删除项目中的 ./build 文件夹,再来打包看下效果:

image-20211110235138437

当然,我们还可以直接在 name 选项中完成 outputPath 选项的设置,这样来写看起来更简洁一些:

...

module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        use: {
          loader: 'file-loader',
          options: {
            name: 'img/[name]_[hash:6].[ext]'
          }
        }
      }
    ]
  }
}

以上,就是 file-loader 中对图片进行命名以及存放到对应的文件夹中的一些写法。