美文网首页饥人谷技术博客程序员前端
url-loader处理css中的图片资源遇到的问题

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

作者: 朱小维 | 来源:发表于2018-03-10 17:18 被阅读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 地址就变成了一个绝对 路由。

    至此,问题解决。

    相关文章

      网友评论

      • 546a12363de6:这样确实能解决问题,但多了一个工作。就是每个不同项目名字,都需要重新配置一下webpack.config.js这个publicpath, 这对于一个月有很多项目的开发来说,非常傻且多余。以前使用grunt的时候,grunt的配置文件配置好后,就几乎不用改动的。
        说实话,webpack比较傻。各个功能插件彼此独立但又耦合(比如fileloader的publicpath和mincssextract的publicpath,两个设置有覆盖又有耦合关系。烦的一逼)。
        546a12363de6:我QQ:373384979
        546a12363de6:经过摸索,终于找到了同时满足html,css对img的相对路径的方法,不用楼主这样每个项目都要修改webpack.config.js的配置的方法了。需要了解的加我QQ吧,我截图给你。
      • 夸父壮阳:如果在background-image中使用绝对路径,打包后还是原路径未处理,例如background-image: url("/static/img/baseBg.png")打包后原封不动,请问这种情况怎么解决?
        夸父壮阳:@朱小维 谢谢回复,已解决。参看这个:https://github.com/vuejs/vue-loader/issues/481#issuecomment-413076372
        朱小维:能否让我知道你加的绝对路径是怎么样的?
      • 昵称已被使用_:url-loader 中的publicPath参数使用绝对路径真是好,给我提了醒,解决了困扰我2天的问题.
        我html和css中都引用了图片,html在dist根目录下,css在idist/mg目录下,使用相对路径生成的图片路径是一样的,但是html和css目录结构不一样,导致总有一方引用不到图片.现在把output的publicPath参数改成绝对路径解决了问题.
        项目地址:https://github.com/yanxiaojun617/webpack4-bootstrap4-demo/
        朱小维:很高兴能够帮助你
      • 工具速递:嗨你好,按照你的做法,这个问题我还是没有解决?
        能指导一下吗

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

      本文链接:https://www.haomeiwen.com/subject/cuavfftx.html