这是我参与更文挑战的第5天,活动详情查看: 更文挑战
前言
目前项目已经可以加载了 css 文件了,这篇文章将会介绍如何加载资源文件(如:图片)。
旧版本与 webpack5+ 加载资源的区别
在 webpack5 之前,可能需要使用 raw-loader、file-loader、url-loader 来加载资源。
- raw-loader:将文件作为字符串导入
- file-loader:处理文件的路径并输出文件到输出目录
- url-loader:有条件将文件转化为 base64 URL,如果文件大于 limit 值,通常交给 file-loader 处理。
在 webpack5+,以上方法已经过时了,webpack5 使用了“资源模块”来代替以上 loader。
官方是这样解释“资源模块”的。
资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。
复制代码而“资源模块”类型有四种。
- asset/resource: 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
- asset/inline: 导出一个资源的 data URI。之前通过使用 url-loader 实现。
- asset/source: 导出资源的源代码。之前通过使用 raw-loader 实现。
- asset: 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现。
asset/resource
asset/resource 起到两个作用,一个是用来解析文件的 URL,另外一个是将目标文件输出到打包目录。
我们先在 src 目录里创建一个 assets 目录,里面新建一个 img 目录,再把一张测试图片复制进来。

在 webpack.config.js 进行配置。
module: {
    rules: [
      ...
      {
        test: /\.(jpe?g|png|svg|gif)/i,
        type: 'asset/resource'
      }
    ]
}
复制代码在 index.js 引入图片
import '../assets/img/simao.jpg'
复制代码运行 npm run build。

图片打包到了 dist 目录了,main.js 也引入了图片,并且图片名默认是以哈希字符串命名(命名规则:[hash][ext][query])。
不过图片是打包到 dist 根目录上,我们再配置一下,让图片放到 dist/img 目录下
webpack.config.js
output: {
    ...
    assetModuleFilename: 'img/[hash][ext][query]'
}
复制代码我们打包后就发现图片放到指定目录下了。

这种方法看起来不错,但是资源文件不单止是图片,可能还会是字体、下载文件,这些文件的类型应该也是 asset/resource,难道我们都统一放到 img 目录下吗?
显然不合理,我们可以改用第二种方案,局部去指定目录。
module.exports = {
    ...
    output: {
        ...
        // assetModuleFilename: 'img/[hash][ext][query]' // 全局指定资源文件输出位置
    }
    ...
    module: {
        rules: [
            ...
            {
                test: /\.(jpe?g|png|svg|gif)/i,
                type: 'asset/resource',
                generator: {
                  filename: 'img/[hash][ext][query]' // 局部指定输出位置
                }
            },
        ]
    }
}
复制代码asset/inline
浏览器请求一个带有图片的网页,会发出 http 请求下载相应的图片,有多少张图片,就有多少个 http 请求,这样是很耗费图片服务器资源以及损耗速度的,想象一下需要加载的图片可能就几kb,却要发出一个 http 请求。
因此将小图片转化为 base64 字符串是一个不错的选择(雪碧图的技术也是为了解决上述问题,有兴趣的可以深究一下)。asset/inline 就是起到这个作用。
记得把上面写的 asset/resource 规则注释掉,防止冲突。
webpack.config.js
module: {
     rules: [
          ...
          // {
          //   test: /\.(jpe?g|png|svg|gif)/i,
          //   type: 'asset/resource',
          //   generator: {
          //     filename: 'img/[hash][ext][query]' // 局部指定输出位置
          //   }
          // },
          {
            test: /\.(jpe?g|png|svg|gif)/i,
            type: 'asset/inline',
          },
     ]
}
复制代码index.js
import img from '../assets/img/simao.jpg'
document.body.style.background = `url(${img})`
复制代码build 一下。

可以发现,图片没有打包出来了,如果你在这个时候打开 main.js,会发现里面有一串很长的字符串,那个字符串就是 base64 字符串。
在浏览器打开 dist/index.html,或运行 npm run dev,网页的背景图将会预期展现出来。

注意了,asset/inline 会将所有符合规则的资源都变为 base64 字符串,也即是比较大的图片也会转化为 base64,base64 占用的空间会很大(可以动手试试)。在 webpack5 里,asset 资源类型可以解决这个问题。
asset
asset 资源类型可以根据指定的图片大小来判断是否需要将图片转化为 base64,如果图片大于或等于限制,则使用 asset/resource 处理,如果图片小于限制 asset/inline 处理。asset 相当于一个判断工具。
项目里的图片(simao.jpg)大小为10kb,现在,我将一张 3kb 图片(名为:webpack.svg)放进 src/asset/img 里做测试。
同样地,注释之前设置的规则,然后新增新的规则。
webpack.config.js
module: {
     rules: [
          ...
          // {
          //   test: /\.(jpe?g|png|svg|gif)/i,
          //   type: 'asset/resource',
          //   generator: {
          //     filename: 'img/[hash][ext][query]' // 局部指定输出位置
          //   }
          // },
          // {
          //  test: /\.(jpe?g|png|svg|gif)/i,
          //  type: 'asset/inline',
          //},
          {
            test: /\.(jpe?g|png|svg|gif)/i,
            type: 'asset',
            generator: {
              filename: 'img/[hash][ext][query]' // 局部指定输出位置
            },
            parser: {
              dataUrlCondition: {
                maxSize: 8 * 1024 // 限制于 8kb
              }
            }
          }
     ]
}
复制代码index.js 引入 webpack.svg,并设置 body 的背景图为 webpack.svg。
index.js
import img from '../assets/img/simao.jpg'
import img2 from '../assets/img/webpack.svg'
// 更换为 img2 背景图
document.body.style.background = `url(${img2})`
复制代码npm run build,发现 dist/img 有图片文件(原 simao.jpg),simao.jpg 并没有并转化为 base64。

我们再在浏览器浏览 index.html 页面,发现 webpack.svg 被转化为 base64 并写入到 body 的背景图里。

由于 simao.jpg 大于 8kb,asset 选择用 asset/resource 处理它。
由于 webpack.svg 小于 8kb,asset 选择用 asset/inline 处理它。
asset/source
这个在实际开发中用得比较少,所以就简单说一下。
asset/source 的作用可以理解为“把目标文件的内容输出到 js 变量中”。
写一个处理 txt 文件的规则,资源类型为 asset/source。
webpack.config.js
module: {
     rules: [
          ...
          {
            test: /\.txt/,
            type: 'asset/source'
          }
     ]
}
复制代码在 src/assets 创建一个 txt 目录,里面新建一个 test.txt,test.txt 内容如下:
Hello World
复制代码index.js
import txt from '../assets/txt/test.txt'
console.log(txt)
复制代码npm run dev,可以发现 “Hello World” 打印出来了

补充:webpack 别名设置
从“webpack5 的使用(一):起步”到这篇文章,有没有发现一个问题。
好像每次 import 一个资源都要写上相对路径,如果文件换目录,那不是每个 import 都要改一遍,别担心,webpack 有一个别名设置,可以设定路径别名。
设置 @ 为 src 的别名。
webpack.config.js
module.exports = {
    resolve: {
        alias: {
          '@': path.resolve(__dirname, '../src'),
          // 下面可以继续新增别名
        }
    }
}
复制代码index.js 里这样导入
import '@/css/index.css'
import '@/scss/index.scss'
import img from '@/assets/img/simao.jpg'
import img2 from '@/assets/img/webpack.svg'
import txt from '@/assets/txt/test.txt'
复制代码完整代码
目录

webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
console.log('环境变量:', process.env.NODE_ENV)
module.exports = {
  // entry: path.resolve(__dirname, '../src/js/index.js'),
  entry: {
    main: path.resolve(__dirname, '../src/js/index.js'),
    header: path.resolve(__dirname, '../src/js/header.js'),
    footer: path.resolve(__dirname, '../src/js/footer.js'),
  },
  output: {
    // filename: 'main.js',
    filename: 'js/[name].[fullhash].js',
    path: path.resolve(__dirname, '../dist'),
    // assetModuleFilename: 'img/[hash][ext][query]' // 全局指定资源文件输出位置和文件名
  },
  // devServer: {
  //   port: 3000,
  //   hot: true,
  //   contentBase: '../dist'
  // },
  plugins: [
    // new HtmlWebpackPlugin({
    //   title: '首页'
    // }),
    // 配置多个 HtmlWebpackPlugin,有多少个页面就配置多少个
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/index.html'),
      filename: 'index.html',
      chunks: ['main'] // 与入口文件对应的模块名(entry 配置),这里可以理解为引入 main.js
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/header.html'),
      filename: 'header.html',
      chunks: ['header']
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/footer.html'),
      filename: 'footer.html',
      chunks: ['footer']
    }),
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[fullhash].css'
    })
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          //'style-loader', 'css-loader'
          MiniCssExtractPlugin.loader, 'css-loader'
        ]
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'
        ]
      },
      // {
      //   test: /\.(jpe?g|png|svg|gif)/i,
      //   type: 'asset/resource',
      //   generator: {
      //     filename: 'img/[hash][ext][query]' // 局部指定输出位置
      //   }
      // },
      // {
      //   test: /\.(jpe?g|png|svg|gif)/i,
      //   type: 'asset/inline',
      // },
      {
        test: /\.(jpe?g|png|svg|gif)/i,
        type: 'asset',
        generator: {
          filename: 'img/[hash][ext][query]' // 局部指定输出位置
        },
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024 // 限制于 8kb
          }
        }
      },
      {
        test: /\.txt/,
        type: 'asset/source'
      }
    ]
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, '../src'),
      // 下面可以继续新增别名
    }
  }
}
复制代码index.js
import '@/css/index.css'
import '@/scss/index.scss'
import img from '@/assets/img/simao.jpg'
import img2 from '@/assets/img/webpack.svg'
import txt from '@/assets/txt/test.txt'
document.body.style.background = `url(${img2})`
console.log('这是一个入口文件')
console.log('环境变量:', process.env.NODE_ENV)
console.log(txt)
复制代码






















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)
