1 概述

引入图片有三种方式。

  1. js中创建图片引入
  2. css中引入图片
  3. <img>标签引入图片

引入图片的语法很简单,关键是图片路径问题。

如何能正确找到图片资源,这是我们关心的。

2 js中创建图片引入

示例代码:

import logo from "./logo.png"
let img = new Image();
console.log(logo)
img.src = logo;
document.body.appendChild(img)

然而,运行时报错:

ERROR in ./src/logo.png 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
 @ ./src/bbb.js 9:0-30 11:12-16 12:10-14
 @ ./src/aaa.js 7:0-18

webpack 5.21.2 compiled with 1 error in 2960 ms

报错说:需要合适的loader去加载图片。

需引入file-loaderimg-loader,并增加webpack配置。

1. file-loader 实现图片加载

file-loader默认会在内部生成一张图片到build目录下,返回生成的图片的路径。

安装:

npm install file-loader -D

webpack配置:

module.exports = {
  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.(png|jpg|gif)$/,
        use: "file-loader"
      }
    ]
  }
}

运行查看结果。

2. url-loader 实现小图片base64化

安装:

npm install url-loader -D

webpack配置:


module.exports = {
  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.(png|jpg|gif)$/,
        use: "file-loader"
      },
      {
        test: /\.(png|jpg|gif)$/,
        //可以做限制,如:图片小于200k,用base64转化,否则用url-loader产生真实图片
        use: {
          loader: "url-loader",
          options: {
            limit: 200 * 1024,
          }
        }
      },
    ]
  }
}

运行,可以看到小于200k的图片是base64的内容。

使用base64的用处:可以不用走网络请求加载,但是base的内容会比原图片大三分之一。

3 css中加载图片

使用CSS语法:background: url('')

示例代码:

div {
  width: 400px;
  height: 400px;
  background: url('./logo.png');
}

然而,运行时报错:
Error: Automatic publicPath is not supported in this browser

ERROR in ./src/index.styl
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
Error: Automatic publicPath is not supported in this browser

报错说:此浏览器不支持自动publicPath。

说明需要手动配置一个publicPath

publicPath就是我们网站的域名。

修改webpack配置:

module.exports = {
  output: {
    filename: "bundle.[hash:8].js",//打包后的文件名
    path: path.resolve(__dirname, "dist"),//打包后的路径(文件夹路径),必须是绝对路径,"__dirname"指当前路径
    publicPath: "http://localhost:3000/"
  },
}

主要是在output中添加publicPath:

publicPath: "http://localhost:3000/"

本地调试就用本机域名地址。

4 <img>标签引入图片

使用标签:<img src=""></img>

示例代码:

  <img src="./logo.png"></img>

运行之后,浏览器报错:

GET http://localhost:3000/logo.png 404 (Not Found)

因为我们的图片并不在打包目录下,自然是找不到的。

此时我们需要用html-withimg-loader来解析html中的图片路径。

安装:

npm install html-withimg-loader -D

配置webpack:

module.exports = {
  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.html$/,
        use: "html-withimg-loader"
      }
    ]
  }
}

运行发现img标签下的图片加载失败,

报错内容:

GET http://localhost:3000/%7B%22default%22:%22http://localhost:3000/e702de51403af91429843c1df58d3d49.png%22%7D 404 (Not Found)

查看资源文件发现img加载的路径变得奇奇怪怪:

<img src="{&quot;default&quot;:&quot;http://localhost:3000/e702de51403af91429843c1df58d3d49.png&quot;}"></img>

问题原因是:

那是和html-webpack-plugin 发生了冲突 同时也因为 file-loader版本冲突了

首先你需要把html-webpack-plugin中针对代码优化相关的配置注释掉:


  plugins: [//存放所有插件
    new HtmlWebpackPlugin({
      template: "./src/index.html",//模版文件(源文件)地址
      filename: "index.html",//打包后文件名
      // minify:false,
      // minify: {
      //   removeAttributeQuotes: true,//删除双引号
      //   collapseWhitespace: true,//折叠空行(变成一行)
      // },
      hash: true,//引用时文件名加上hash戳
    }),
  ],

然后,如果你的file-loader 版本是 5.* 或以上版本,需要在webpack中修改file-loader配置:

      {
        test: /\.(png|jpg|gif)$/,
        use: [{
          loader: 'file-loader',
          options: {
            esModule: false
          }
        }]
      },
      {
        test: /\.html$/,
        use: "html-withimg-loader"
      }
如果是url-loaderhtml-withimg-loader搭配使用出现这个问题,解决办法相同。

主要是在配置中新增:

          options: {
            esModule: false
          }

默认是true 使用esModule 改为false就可以打包了

查看结果:

<img src="http://localhost:3000/e702de51403af91429843c1df58d3d49.png"></img>

图片显示正常。

5 资源分目录打包

可以给css、图片 等静态资源指定一个打包目录。

webpack配置:

module.exports = {
  plugins: [//存放所有插件
    new MiniCssExtractPlugin({
      filename: "css/main.css"//抽离css之后输出的文件名
    }),
  ],
  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.(png|jpg|gif)$/,
        //可以做限制,如:图片小于200k,用base64转化,否则用file-loader产生真实图片
        use: {
          loader: "url-loader",
          options: {
            esModule: false,
            limit: 200 * 1024,
            outputPath:"img/"
          }
        }
      },
    ]
  }
}

主要是修改了两处:

filename: "css/main.css"//抽离css之后输出的文件名
outputPath:"img/"

css输出路径增加文件夹;
图片加载时增加导出文件夹路径;

6 指定图片域名

可以指定只有加载图片资源时添加指定的域名路径。

webpack配置:

module.exports = {
  output: {
    filename: "bundle.[hash:8].js",//打包后的文件名
    path: path.resolve(__dirname, "dist"),//打包后的路径(文件夹路径),必须是绝对路径,"__dirname"指当前路径
  },
  module: {//模块
    rules: [//规则,多个loader
      {
        test: /\.(png|jpg|gif)$/,
        //可以做限制,如:图片小于200k,用base64转化,否则用file-loader产生真实图片
        use: {
          loader: "url-loader",
          options: {
            esModule: false,
            limit: 200 * 1024,
            outputPath:"img/",
            publicPath: "http://localhost:3000/",
          }
        }
      },
    ]
  }
}

output中的publicPath: "http://localhost:3000/",删掉;

往rules中图片loader里加入publicPath: "http://localhost:3000/",

这样可以实现只在加载图片时,采用域名的形式加载资源,其他css和js还是相对路径形式加载。

相当于部分添加域名。

但奇怪的是,图片loader中加了publicPath之后,outputPath属性就不生效了。谁给解释一下?但不影响图片加载。