webpack读书笔记——图片资源打包

746 阅读3分钟

图片引入方式

在实际的生产过程中有以下几种引入图片的方式

直接在html写入标签

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>webpack html打包</title>
</head>
<body>
  <h1 id="title">
      hello Webpack 2021
  </h1>  
  <img src="./imgs/webpack.jpg">
</body>
</html>

在css中中引入背景图片

.main{
    width: 300px;
    height: 300px;
    background-image: url(./imgs/angular.jpg);
    background-repeat: no-repeat;
    background-size: 100% auto;
    border: 3px solid green;
}

在js中创建图片引入

import img from './imgs/webpack.jpg';
var imgElement = document.createElement('img');
imgElement.src = img;
document.body.appendChild(imgElement);

url-loader

在 webpack 中引入图片需要依赖 url-loader 这个加载器。

安装

npm install url-loader -D

当然也可以将其写入配置中,以后与其他工具模块一起安装

"devDependencies": {
    "css-loader": "^6.3.0",
    "file-loader": "^6.2.0",
    "html-loader": "^2.1.2",
    "html-webpack-plugin": "^5.3.2",
    "less": "^4.1.2",
    "less-loader": "^10.0.1",
    "style-loader": "^3.3.0",
    "url-loader": "^4.1.1",
    "webpack": "^5.58.1",
    "webpack-cli": "^4.9.0",
    "webpack-dev-server": "^4.3.1"
  }

在 webpack.config.js 文件中配置如下

module: {
  loaders: [
    {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            // 图片大小小于20kb,就会base64处理
                            limit: 20 * 1024,
                            // url-loader默认使用es6模块化解析,html-loader引入图片使用的是commonjs规范
                            // 关闭url-loader的es6模块化,使用commonjs解析
                            esModule: false,
                            // outputPath: 'assets'
                            // 图片编译之后重命名
                            // [hash:10]获取图片hash前10位 [ext]取文件的原扩展名
                            name:'[hash:10].[ext]'
                        }
                    }
                ],
    }
  ]
}


test 属性代表可以匹配的图片类型,除了 png、jpg、gif 之外也可以添加 svg 等,以竖线隔开即开。

loader 后面中的options 中增加关于 url-loader 的一些配置项:

  • limit 字段代表图片打包限制,这个限制并不是说超过了就不能打包,而是指当图片大小小于限制时会自动转成 base64 码引用。上例中大于 20kb 字节的图片正常打包,小于 20kb 的图片以 base64 的方式引用。默认是无limit的。
  • esModule 关闭url-loader的es6模块化,使用commonjs解析。
  • name 图片编译之后重命名。
  • fallback 指定当前目标文件大小超出处理限制时,要使用的备用加载程序。 具体可以参考 url-loader的官方文档。

然后通过以上配置,在命令行控制台输入打包命令后,可以看到构建页面如下所示:

image.png

最终输出的打包的目录文件如下:

image.png

html-loader

打包后发现可以发现在html中的引入的图片路径写死的,并不会相对于build,导致无法找到该图片,使用html-loader来处理html中的图片。

安装

安装并配置 

npm i -D html-loader

在webpack.config.js 中配置文件如下:

{
    test: /\.html/,
    // 处理html文件中的img图片,负责引入img,从而可以被url-loader处理
    loader: 'html-loader'
}

再次打包之后可以看到html中的文件可以正常访问到。

遇到的问题

在项目实践中使用的是 webpack5 的版本打包构建的文件,

问题描述

使用webpack5进行图片资源打包时,打包后图片打不开,并且有重复的图片资源。

问题分析

1、webpack.config.js配置文件代码

/**
 * webpack 的配置文件
 * 指示 webpack 都做哪些工作
 * loader: 1. 下载  2. 使用(配置loader)
 * plugins: 1. 下载 2. 引入  3. 使用
 *  */
// resolve 用于拼接绝对路径的方法
const path = require('path');
const { resolve } = require('path')
const  HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    // webpack 打包的入口起点
    entry: './src/index.js',
    // 输出
    output: {
        // 输出文件名
        filename: 'main.js',
        // 输出的路径
        // --dirname是node.js的一个全局变量,表示当前执行脚本所在的目录
        path: resolve(__dirname, 'build'),
        publicPath: './'
        // publicPath: '../build/'
    },
    // loader的配置
    module: {
        // 详细的loader配置
        rules: [
            {
                // 匹配哪些文件
                test: /\.css$/,
                // 使用哪些loader进行处理
                use: [
                    // use数组中loader执行顺序从下网上执行
                    // 创建style标签,将js中的样式资源进行插入,添加到head中生效
                    'style-loader',
                    // 将css文件变成commonjs模块加载到js中,里面的内容是字符串
                    'css-loader'
                ]
            },
            {
                // 匹配哪些文件
                test: /\.less$/,
                // 使用哪些loader进行处理
                use: [
                    // use数组中loader执行顺序从下网上执行
                    // 创建style标签,将js中的样式资源进行插入,添加到head中生效
                    'style-loader',
                    // 将css文件变成commonjs模块加载到js中,里面的内容是字符串
                    'css-loader',
                    // 将less文件编译成css文件
                    // 需要下载 less 和 less-loader
                    'less-loader'
                ]
            },
            {
                // test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
                test: /\.(png|jpg|gif)$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            // 图片大小小于20kb,就会base64处理
                            limit: 20 * 1024,
                            // url-loader默认使用es6模块化解析,html-loader引入图片使用的是commonjs规范
                            // 关闭url-loader的es6模块化,使用commonjs解析
                            esModule: false,
                            // outputPath: 'assets'
                            // 图片编译之后重命名,[hash:6]获取图片hash前6位 [ext]取文件的原扩展名
                            name:'[hash:10].[ext]'
                        }
                    }
                ]
                
            },

            // {
            //     test: /\.(html|js|css|less|jpg|png|gif)/,
            //     loader: 'file-loader',
            //     options: {
            //         name: '[hash:6].[ext]'
            //     }

            // },

            {
                test: /\.html/,
                // 处理html文件中的img图片,负责引入img,从而可以被url-loader处理
                loader: 'html-loader'
            }
            
        ]

    },
    // plugins的配置
    plugins: [
        // 详细的plugins的配置
        // html-webpack-plugin
        new HtmlWebpackPlugin({
            title: 'test',
            // 功能:生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle(js/css)。 
            template: './src/test.html'
        })
        
    ],
    // 模式  默认是生产环境 production
    mode: 'development',
    //  开发服务器 devServer,主要用于自动化(自动化编译,自动化打开浏览器,有变动自动刷新浏览器~)
    // 只会在内存中进行编译打包,不会有任何输出
    devServer: {
        static: {
            directory: resolve(__dirname, 'build'),
          },
        hot: true,
        // 端口号
        port:8080,
        // 自动打开默认浏览器
        open:true,
        // 启用 gzip 压缩
        compress:true,
        proxy:{
            "/api":{
                // 目标地址
                target:"http://localhost:8888",
                // 路径重写,默认情况下,我们的/api也会被写入到URL中,如果希望删除,可以使用
                pathRewrite:{
                    "^/api":""
                },
                // 默认情况下不接受转发到https的服务器,如果希望支持,设置为false
                secure:false,
                // 是否更新代理后请求headers中的host地址
                changeOrigin:true
            }
    
        }
    },
    // watch: true
}

发现配置文件没有问题,打包时图片使用了url-loader和file-loader。考虑是不是这两个loader的问题。

到webpack官网查看资料以后,发现官方这样描述:

当在 webpack 5 中使用旧的 assets loader(如 file-loader/url-loader/raw-loader 等)和 asset 模块时,你可能想停止当前 asset 模块的处理,并再次启动处理,这可能会导致 asset 重复,你可以通过将 asset 模块的类型设置为 ‘javascript/auto’ 来解决。 所以我们在webpack5使用这些loader时需要添加:

  type: 'javascript/auto'

这样以后再使用webpack打包,发现图片可以正常访问。