Webpack 解决 CSS 图片加载问题

已经纯在的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module: {
rules: [
{
test: /(logo|outlier|coaching)\.png$/,
loader: 'file-loader?name=./[path][name].[ext]'
},
{
test: /\.(png|jpg)$/,
loader: 'file-loader?name=./[path][name].[ext]&publicPath=.',
exclude: /(logo|outlier|coaching)\.png$/
}
]
},
plugins: [
new ExtractTextPlugin({
filename: './css/[name].css',
allChunks: true
})
]

如上面所示的配置文件,由于配置了 extract-text-webpack-plugin 并且把 css 文件放在了 css 目录下,导致 css 中引用图片的相对路径要发生变化。所以配置了两个图片加载器,来区分 css 与 jsx 中加载的图片。css 中加载的图片要单独配置 publicPath 来修改相对路径。最终结果是 jsx 引用图片的路径是 ./img/logo.png,css 中引用的图片是 ../img/loginbg.png,看似问题是解决了。但是为了区分 jsx 与 css 加载的图片,jsx 中加载的图片要明确指明是哪些,精确到文件名,css 中加载的图片要排除在 jsx 中加载的图片。这就导致了,每加一次图片都要检查下 webpack 的配置文件。团队来新成员了,都要熟悉这条规则。不利于后期维护。

解决问题

基于你遇到过问题别人都会遇到的原则,去网上寻找答案。其实这个问题在项目中 15 年就纯在了 :(

1,google webpack loader image different js and css

恰好第一个结果就指向了 file-loaderissues/272 @evilebottnawi 回答到

@a-carvallo Please read my notices, relative urls is out of scope file-loader, it should be done by minifier/uglifier. Main function file-loader is save file to fs and output public path to this asset and all. Change url in css should be done with cssnano or csso. Thanks!

这事不归 file-loader 管?

2,ExtractTextPlugin

既然不归 file-loader 管,那就看看 ExtractTextPlugin 官方文档,有没有这关于方面的配置。找到一个稍微有用点的配置 url: false,结果 webpack 根本就不处理 css 的 url() 引用了😂

1),ExtractTextPlugin issue list

在次基于你遇到过问题别人都会遇到的原则,去看看 issue list 里面有没有人提到同样的问题,结果还真让我找到了。publicPath parameter doesn’t work? #246
然后就是一通尝试。

2),output. publicPath

1
2
3
output: {
publicPath: './'
}

发现改的是全局的 publickPath。结果 js 和 css 都加载不成功了

3),loader.publicPath

看到 @mohammadalipak 给出的配置

1
2
3
4
5
6
7
8
{
test: /\.global\.scss$/,
use: ExtractTextPlugin.extract({
use: [...],
fallback: 'style-loader',
publicPath: './',
})
},

发现使用的是 loader 里面的 publicPath,但是根据以往的经验修改 loader 里面的 publicPath 影响的是其他的地方对自己的引用,比如 file-loader,管他呢先试试再说。

见证奇迹的时刻,竟然 css 里面的 url() 发生了变化。如果真是这样就解决了 jsx 与 css 对图片引用不好区分的问题,经过多番试验证实确实就是这样。至此问题就算解决了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module: {
rules: [
{
test: /\.s?css$/,
use: ExtractTextPlugin.extract({
use: [
{loader: 'css-loader', options: {minimize: true}},
{loader: 'postcss-loader', options: postcssOpts},
{loader: 'sass-loader'}
],
publicPath: '.',
})
},
{
test: /\.(png|jpg)$/,
loader: 'file-loader?name=./[path][name].[ext]'
}
]
}