饥人谷技术博客程序员前端

url-loader处理css中的图片资源遇到的问题

2018-03-10  本文已影响369人  朱小维

处理css中的图片资源时,我们常用的两种loader是file-loader或者url-loader,两者的主要差异在于。url-loader可以设置图片大小限制,当图片超过限制时,其表现行为等同于file-loader,而当图片不超过限制时,则会将图片以base64的形式打包进css文件,以减少请求次数。
本文的主要想说的是我们在使用file-loader或url-loader时经常出现的图片地址错误导致图片引用不到的情况,及相应解决办法。

场景复现

工程目录如下


工程目录
index页面目录

webpack配置文件中,关于图片的处理:

            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 10000,
                    name: 'img/[name].[hash:7].[ext]'
                }
            },

index.js文件

import './index.scss'

index.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div class="pic"></div>
</body>
</html>

index.scss文件:

.pic{
  width:100px;
  height:100px;
  background: url('./1.jpg');
  background-size: 100px 100px;
}

当我们执行 npm run build后 查看dist中的情况如下:

image.png
我们通过服务 打开index.html会发现页面中并没有 图片,并且报错:
image.png
这是我们当然是要去看看 打包后的 css文件中的 图片路径了:
.pic{width:100px;height:100px;background:url(img/1.d1efbb3.jpg);background-size:100px 100px}
/*# sourceMappingURL=index.min.css.map?v=7b7c89f8*/

background:url(img/1.d1efbb3.jpg);,index.min.css文件竟然去自己的同级目录找img文件夹,当然找不到了
还记得我们的 dist目录情况么?

image.png
很显然img文件夹位于index.min.css上层,如果 是background:url(../img/1.d1efbb3.jpg);就对了。

然后我们尝试去修改webpack的配置文件,以达到我们的预期:

            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 10000,
                    name: '../img/[name].[hash:7].[ext]'
                }
            },

然后再npm run build
index.min.css 内的 background的图片地址的确变成了 我们想要的

.pic{width:100px;height:100px;background:url(../img/1.d1efbb3.jpg);background-size:100px 100px}
/*# sourceMappingURL=index.min.css.map?v=eef74865*/

但是悲剧的是!!!!! img 竟然被打包到了 dist文件夹的外面,不在位于dist内了,所以

现在的dist 之前的dist

是不是很抓狂……看来我们修改配置文件的方法是不对的。仔细想想,能明白其中的原因么?

打包的时候webpack会把 scss文件中的 background url 替换成我们webpack配置文件中的 options的name属性中设置的内容,同时把 scss文件中的 background url 中的图片文件 给复制到 webpack配置文件中的 options的name属性所指向路径下,关键就在这里了。

webpack配置文件中的 options的name属性所指向路径 是相对路径,那么这个路径到底是相对于谁呢?你仔细观察 会发现 它是相对于 dist 文件夹的,也就是webpack的出口路径。举个例子:

            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 10000,
                    name: 'img/[name].[hash:7].[ext]'
                }
            },

上面的配置,就会把图片 给复制到 dist/img/1.jpg,然后 将index.min.css 你的 background属性 改为background:url('img/1.png'),该路径也是相对路径,但是它不相对于 dist,而是相对于dist/css,因为我的css文件 并没有被输出到 dist的直接路径下,而是输出到了dist/css下,所以css 文件就会去dist/css/img/1.png去拿图片,但是图片却位于dist/img/1.png,这就最终导致了 css文件找不到图片。

配置文件复制图片是相对于 webpack 出口路径的 , css文件引用图片是相对于css文件所在路径的,如果这两个路径相同 也就是 webpack出口路径 = css文件所在路径 那么 很幸运 ,你的图片是可以找到的。但是一般情况下是不同的,我们习惯于 将出口路径 定为dist/ 然后将css文件输出到 'dist/css/' ,最终导致了引用不到图片的结果。

至此原因分析完毕。

解决方法:

在配置项内加入 publicPath 属性,设置为部署时的绝对路径

比如所 以后你的页面 会通过如下url方式让用户访问,所有前端文件都放置于

http://localhost:63342/url-loader-test/dist/

那么pubilcPath的 值就应该是 '/url-loader-test/dist/',也就是你的部署接口地址。

            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 10000,
                    name: 'img/[name].[hash:7].[ext]',
                    publicPath:"/url-loader-test/dist/"      //该地址不是唯一的,根据你的代码实际路由地址进行修改
                }
            },

这样做的原因是,webpack打包时,还会将图片复制到 dist/img/1.png,但是他会把css文件中的background url 改写为 publicPath + name ,本例中最后生成的index.min.css 如下:

.pic{width:100px;height:100px;background:url(/url-loader-test/dist/img/1.d1efbb3.jpg);background-size:100px 100px}
/*# sourceMappingURL=index.min.css.map?v=eef74865*/

这时css文件中的url 地址就变成了一个绝对 路由。

至此,问题解决。

上一篇下一篇

猜你喜欢

热点阅读