Vue-loader: 生成的css文件中background url()图片路径问题

Created on 22 Nov 2016  ·  45Comments  ·  Source: vuejs/vue-loader

重现项目在这

使用vue init webpack创建的项目,改了三个地方

  1. webpack.base.conf.js配置文件output的publicPath注释起来
  2. App.vue中给body加了background样式
  3. 把url-loader的limit改成了6000,避免base64转换而不使用file-loader

现象:

npm run dev没问题 因为跟build的目录不同
当npm run build后
提取出来的css文件中url()中图片的路径是static/img/logo.82b9c7a.png这样的,应该是根据url-loader来的,但这个路径是相对于css文件的,所以造成找不到这张图片

个人几个解决方案:

  1. 把webpack配置文件的output的publicPath设置成’/‘(初始化的项目默认是这样的),这样所有引用文件都会从’/‘开始,不会出现找不到文件的情况。但我是在一个域名下有多个项目的,不一定会把这个项目放到根目录。如:a.com/test1/index.html 会放到test1目录下,如果设置成’/‘就会直接到a.com/下找,还是会找不到,如果修改成/test1 因为这个目录非常多,更新特别频繁,如果每一个都需要修改也挺麻烦,上边的修改把output的publicPath注释起来也是因为这个
  2. webpack.prod.conf.js中ExtractTextPlugin插件目录中的css文件夹搞成上级目录“..”,这样css文件就会跟index.html在相同目录,其中的url目录就会正确了,但感觉破坏了目录结构,不知道好不好~(现在用的这种解决方案,因为多个项目可以使用相同的配置)

    3. 手动改~因为这几次样式里边url()用的还比较少,多了就不靠谱了

这个问题纠结了很久 看了css-loader file-loader文档,看了很多以前的issue,网上查了很久,都没有找到相应的解决方法,因为实在找不到应该修改哪一部分。上边说的几个解决方法,总感觉不靠谱~
忍不了了所以来提个issue 望大牛们指点迷津

improvement

Most helpful comment

对于楼主的问题,主要是需要单独为 css 配置 publicPath 。
ExtractTextWebpackPlugin 提供了一个 options.publicPath 的 api,可以为css单独配置 publicPath 。

对于用 vue-cli 生成的项目,dist 目录结构如下:

├── index.html
└── static
    ├── css
    ├── img
    └── js

经常遇见的问题是 css 中 background-image 的相对路径不能正确的引用到 img 文件夹中。但是用 ExtractTextWebpackPlugin 的 publicPath 配置就可以。

更改 build/utils.js 文件中 ExtractTextPlugin 插件的options 配置:

    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        publicPath: '../../',         // 注意配置这一部分,根据目录结构自由调整
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }

最后附上 extract-text-webpack-plugin 的文档。
https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/master/README.md

All 45 comments

同求问

我也有引用图片出了问题

same to me
it seems option.publicPath of ExtractTextPlugin is broken here

return ExtractTextPlugin.extract('vue-style-loader', sourceLoader,{
    publicPath: "../../../../"
})

just work the same as publicPath: "../" and publicPath: "/"

if set to publicPath: "./../", webpack error with any .vue
Module not found: Error: Cannot resolve 'file' or 'directory' ./../../../../node_modules/extract-text-webpack-plugin/"}

mark

同问,主要问题出在background-image的引用里,每次都要先把图片import 进来

同问

这个问题 很严重的 因为我们做汽车网站的 有些时候背景图会用到很多!

将真,我也遇到这种问题 ,找了好几天这个问题,最后不得已把这个图片转换成了base64。。。

同问,目前采用手动的方式处理了,没有转化成base64的大图片,路径都会相对css的static,所以错误.只能在打包后生成的app.css里面全部替换,将./static替换成../static,这样暴力解决的,但......

我的解决了,路径改为绝对路径就没问题了

这问题还在讨论啊,根据dev/build,给file-loader设置不同的publicPath可以解决dev build时路径不同的问题

但是JS和CSS中图片路径,分别是根据所被引用的CSS或者JS的路径来计算相对路径。如果两者层次不同,就无法用../多次的方式回到相同的某路径来统一路径。这个问题我也没找到方法,但是直接规避就好了

关注一下你的.vue文件,相对于这个来。就可以的

mark

mark,也遇到这个问题了,第三方组件里面的css引用img图片了,路径就不对了

对于楼主的问题,主要是需要单独为 css 配置 publicPath 。
ExtractTextWebpackPlugin 提供了一个 options.publicPath 的 api,可以为css单独配置 publicPath 。

对于用 vue-cli 生成的项目,dist 目录结构如下:

├── index.html
└── static
    ├── css
    ├── img
    └── js

经常遇见的问题是 css 中 background-image 的相对路径不能正确的引用到 img 文件夹中。但是用 ExtractTextWebpackPlugin 的 publicPath 配置就可以。

更改 build/utils.js 文件中 ExtractTextPlugin 插件的options 配置:

    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        publicPath: '../../',         // 注意配置这一部分,根据目录结构自由调整
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }

最后附上 extract-text-webpack-plugin 的文档。
https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/master/README.md

如果说由后端php分配域名,而我的页面static不放在根目录如何解决,也就不能使用绝对路径了

@pspgbhu 这个办法太好了!!!!!!!!!!!!!!!!!!!!!!!!!!!!

@pspgbhu 解决了,感谢!

@pspgbhu 非常赞,终于找到完美解决方案啦!

更改下问题样式,改好看点~

mark

@pspgbhu 确实能解决问题 mark

@pspgbhu 你的方法成功! 感謝大神

@pspgbhu 问题解决了,谢谢大佬

@pspgbhu O(∩_∩)O 谢谢,找了一晚上的解决方案,这个最简单有效了!!!

@pspgbhu Thanks.

{
                test: /\.scss$/,
                use: extractSass.extract({

                    use: [
                        {
                            loader: "css-loader",
                            options: {
                                minimize: true,
                            }
                        },
                        {
                            loader: "resolve-url-loader"
                        },
                        {
                            loader: "sass-loader",
                            options: {
                                sourceMap: true
                            }
                        }
                    ],                 
                    fallback: "style-loader",
                    publicPath: "../"

                })
},

还是无法解决!

@zigang93

更改 build/utils.js 文件中 ExtractTextPlugin 插件的options 配置:

    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        publicPath: '../../',         // 注意配置这一部分,根据目录结构自由调整
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }

@pspgbhu 赞一个,完美

@pspgbhu
更改 build/utils.js
这句我有点不肯定 是在node_module??
我根本没有用vue-loader.. 我是看到很多issue 引导我来这里

问题出于我的file-loader 的 publicPath ,
终于解决了我的疑问和问题了

我的问题通过干掉postcss的postcss-url插件解决了

其实我也没理解题主的意思,是不是想一次build 在不同的publicPath环境中运行,通过css 的相对路径加载图片。感觉这样确实有难度。因为,所有的图片都是放到imgs直接目录下ExtractTextPlugin稍微改下就可以实现,但如果imgs里面再分gif,png,jpg文件夹,相对路径就更复杂了,需要ExtractTextPlugin去读取你的css提取目录配置,不同图片的 url-loader(file-loader)目录规则,才能决定如何替换。
如果是绝对路径的,设置publicPath就可了,如果是test1下面就设置成 ‘/test1/’
vue 项目中发现的一个事情是,如果css 引用的是绝对定位的static下的图片,貌似不经过url-loader处理的,直接复制static下的图片到dist下的static下面引用。

我们似乎忘记了有这么一个标签 <base href="资源路径" />
http://www.w3school.com.cn/html5/tag_base.asp

@laozhujia 在.vue单文件组件中写样式,背景图片url使用绝对路径可以避免使用相对路径层级过深的问题,但是打包后依旧是绝对路径,如果项目不是跑在根目录下就会出现问题;请问有什么好的解决办法嘛,求教

@badaoshen 假设你项目放在test目录下,如果目录和工程一致,直接设置publicPath=‘/test/' ,打包后会在所有引用前加上这个publicPath的路径, vue-cli2.0配置webpack.base.conf.js 中output.publicPath, 可以直接修改,也可以保留build.assectsPublicPath 修改config目录下index里build.assetsPublicPath。如果是img css 另外存放目录,可以参考 本页 pspgbhu 的修改ExtractTextPlugin的publicPath 覆盖output的publicPath方法
(引用不是static 目录下的图片,需要使用url-loader加载图片,不然应该没法实现图片引用)
注意vue-cli3.0以后,publicPath 变成了vue.config.js 里的baseUrl 设置如下
baseUrl: process.env.NODE_ENV === 'production' ? '/test/' : '/',
vue-cli3.0 的ExtractTextPlugin设置没研究过,见谅。(3.0配置和2.0有巨大差别,入坑要谨慎)

@laozhujia 查了下webpack关于路径处理的文档,使用绝对路径的时候会被直接忽略,例如:

background-image: url("/static/img/baseBg.png");
//打包后原封不动emmmmmm····

但是在css中使用相对路径会因为项目文件分级出现异常多的"../../../../../",最后的解决方案是使用模块路径,图片放到src/assets/img中,自己配置了一个alias:

//在webpack.base.conf.js中
alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      'img':resolve('src/assets/img')  //配置一个img的别名指向src/assets/img
    }
//相对应的路径就写成:
background-image: url("~img/baseBg.png");//"~"号代表使用alias
//打包发布的时候参照pspgbhu的方法配置

此方案优点就是路径简洁明了,打包的时候会转为相对路径便于项目发布,缺点就是IDE无法识别,会提示错误 ( 辣鸡webstorm(メ゚Д゚)メ逃~

@pspgbhu 试了一下, 解决了我的问题, 感谢!

对于楼主的问题,主要是需要单独为 css 配置 publicPath 。
ExtractTextWebpackPlugin 提供了一个 options.publicPath 的 api,可以为css单独配置 publicPath 。

对于用 vue-cli 生成的项目,dist 目录结构如下:

├── index.html
└── static
    ├── css
    ├── img
    └── js

经常遇见的问题是 css 中 background-image 的相对路径不能正确的引用到 img 文件夹中。但是用 ExtractTextWebpackPlugin 的 publicPath 配置就可以。

更改 build/utils.js 文件中 ExtractTextPlugin 插件的options 配置:

    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        publicPath: '../../',         // 注意配置这一部分,根据目录结构自由调整
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }

最后附上 extract-text-webpack-plugin 的文档。
https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/master/README.md

请问升级到webpack4怎么解决的这个问题

@Yanhongliang100 可以使用MiniCssExtractPlugin.loader,同样的配置。

@Yanhongliang100 可以使用MiniCssExtractPlugin.loader,同样的配置。

能否贴下代码看看?

@Yanhongliang100 可以使用MiniCssExtractPlugin.loader,同样的配置。

能否贴下代码看看?

项目是以 vue-element-admin 为基础构建的,升级到webpack4后,将build/utils.js 中
loaders.push(MiniCssExtractPlugin.loader)
修改为

loaders.push({
    loader: MiniCssExtractPlugin.loader,
        options: {
          // 解决css中backgroud-url资源在编译后的路径问题
          publicPath: '../../'
        }
 })

@badaoshen 我项目部署在了二级域名下,导致css背景图都显示不出来,配置了url-loader也没生效,看到你的方案才意识到自己写的绝对路径没有被解析,现在已经完美解决了,非常感谢!O(∩_∩)O

```js
module: {
rules: [
{
test: /.less$/i,
use: [
devMode ? 'vue-style-loader' :
{
loader: MiniCssExtractPlugin.loader,
options: {
/*
* 复写css文件中资源路径
* 因为css文件中的外链是相对与css的,
* 我们抽离的css文件在可能会单独放在css文件夹内
* 引用其他如img/a.png会寻址错误
* 这种情况下所以单独需要配置../,复写其中资源的路径
*/
publicPath: '../'
}
},
'css-loader',
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true
}
}
}
]
},
]
}

Was this page helpful?
0 / 5 - 0 ratings