无法使用 Webpack 解析 CSS 中背景图像的绝对 url() 路径
Unable to resolve absolute url() paths for background images in CSS with Webpack
我有以下 Webpack 配置(粗略地说,它已针对此 post 进行了简化):
const rootPublic = path.resolve('./public');
const LOCAL_IDENT_NAME = 'localIdentName=[name]_[local]_[hash:base64:5]';
const CSS_LOADER = `css?sourceMap&${LOCAL_IDENT_NAME}&root=${rootPublic}`;
const SASS_LOADER = 'sass?sourceMap&includePaths[]=' + path.resolve(__dirname, './src/styles');
// ... loaders:
loaders: [
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'url-loader?limit=10000&name=[path][name].[ext]'
},
{
test: /\.scss$/,
loader: config.DEVELOPMENT_MODE ? `style!${CSS_LOADER}!autoprefixer!${SASS_LOADER}`
: ExtractTextPlugin.extract('style', `${CSS_LOADER}!autoprefixer!${SASS_LOADER}`)
}, // ...
]
现在这对于在 scss 文件中正常引用的图像非常有效:
.some-static-class {
background: url('/images/bg.png');
}
但是,当使用 :local
指令时,它 不 工作:
:local .SomeClass {
background: url('/images/bg.png');
}
我认为这是因为 root
是为 CSS 加载程序定义的。我收到构建错误:Module not found: Error: Cannot resolve 'file' or 'directory' ./../../../../../../../../images/bg.gif
如果我从 css-loader 配置中删除 root
,那么它构建正常,但路径 "looks" 在 Chrome 的检查器中是正确的,但是当您在新选项卡中实际打开 link 时,它指向:chrome-devtools://devtools/bundled/"/images/bg.png"
显然无法正确解析。
我不确定问题是否出在 url-loader
配置上,或者到底发生了什么。
我试过不同的 webpack 配置来指定 resolve.root、resolve.modulesDirectories 等,但完全不确定它们是否有任何影响,或者我是否完全错误.我也遇到了 resolve-url-loader
但不确定这是否是我所需要的。
有什么想法吗? MTIA!
更新
我应该注意,它在 Safari 中运行良好,但在 Chrome 中却不行。所以这似乎是一个 Chrome 特有的错误,但必须在 Safari 中完成我们所有的开发是不切实际的。
我也遇到了,vue-style-loader,它是 style-loader 的一个分支,声称可以解决这个问题,但是它解决这个问题的方式是依赖于一个 hacky 弃用的 escape/unescape 方法.
我能想到的一个可能的解决方案如下:
使用resolve-url-loader
(紧接在sass-loader
之后):
style!${CSS_LOADER}!autoprefixer!resolve-url!${SASS_LOADER}
然后,为静态图片定义一个resolve.alias:
resolve: {
alias: {
images: path.join(__dirname, 'public/images')
}
}
然后在 CSS 中,您可以像这样指向图像:
:local .SomeClass {
background: url('images/bg.png');
}
根据您的 URL 结构,您可能还需要调整 url-loader
名称参数:
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'url-loader?limit=10000&name=images/[name].[ext]'
}
所以我不知道是否有更简洁的方法来解决这个问题,但这是迄今为止我能想到的最好方法。我欢迎任何反馈或替代方案。
谢谢!
2016 年 6 月 30 日更新
有几个 PR 可以解决这个问题,但是维护者更喜欢将解决方案放在 CSS AST 中而不是 CSS 加载器中...
https://github.com/webpack/style-loader/pull/124
https://github.com/webpack/style-loader/pull/96
希望很快就会有真正的修复...
使用 webpack 2:
在您的 .scss 文件中,在路径前使用 ~。
.yourClass {
background: url('~img/wallpaper.png');
}
利用 webpack 的解析根,将其添加到您的 webpack.config.js:
resolve: {
modules: [
path.resolve(root),
'node_modules'
]
},
它应该也适用于@import,例如@import "~otherfile.scss"
我有以下 Webpack 配置(粗略地说,它已针对此 post 进行了简化):
const rootPublic = path.resolve('./public');
const LOCAL_IDENT_NAME = 'localIdentName=[name]_[local]_[hash:base64:5]';
const CSS_LOADER = `css?sourceMap&${LOCAL_IDENT_NAME}&root=${rootPublic}`;
const SASS_LOADER = 'sass?sourceMap&includePaths[]=' + path.resolve(__dirname, './src/styles');
// ... loaders:
loaders: [
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'url-loader?limit=10000&name=[path][name].[ext]'
},
{
test: /\.scss$/,
loader: config.DEVELOPMENT_MODE ? `style!${CSS_LOADER}!autoprefixer!${SASS_LOADER}`
: ExtractTextPlugin.extract('style', `${CSS_LOADER}!autoprefixer!${SASS_LOADER}`)
}, // ...
]
现在这对于在 scss 文件中正常引用的图像非常有效:
.some-static-class {
background: url('/images/bg.png');
}
但是,当使用 :local
指令时,它 不 工作:
:local .SomeClass {
background: url('/images/bg.png');
}
我认为这是因为 root
是为 CSS 加载程序定义的。我收到构建错误:Module not found: Error: Cannot resolve 'file' or 'directory' ./../../../../../../../../images/bg.gif
如果我从 css-loader 配置中删除 root
,那么它构建正常,但路径 "looks" 在 Chrome 的检查器中是正确的,但是当您在新选项卡中实际打开 link 时,它指向:chrome-devtools://devtools/bundled/"/images/bg.png"
显然无法正确解析。
我不确定问题是否出在 url-loader
配置上,或者到底发生了什么。
我试过不同的 webpack 配置来指定 resolve.root、resolve.modulesDirectories 等,但完全不确定它们是否有任何影响,或者我是否完全错误.我也遇到了 resolve-url-loader
但不确定这是否是我所需要的。
有什么想法吗? MTIA!
更新
我应该注意,它在 Safari 中运行良好,但在 Chrome 中却不行。所以这似乎是一个 Chrome 特有的错误,但必须在 Safari 中完成我们所有的开发是不切实际的。
我也遇到了,vue-style-loader,它是 style-loader 的一个分支,声称可以解决这个问题,但是它解决这个问题的方式是依赖于一个 hacky 弃用的 escape/unescape 方法.
我能想到的一个可能的解决方案如下:
使用resolve-url-loader
(紧接在sass-loader
之后):
style!${CSS_LOADER}!autoprefixer!resolve-url!${SASS_LOADER}
然后,为静态图片定义一个resolve.alias:
resolve: {
alias: {
images: path.join(__dirname, 'public/images')
}
}
然后在 CSS 中,您可以像这样指向图像:
:local .SomeClass {
background: url('images/bg.png');
}
根据您的 URL 结构,您可能还需要调整 url-loader
名称参数:
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'url-loader?limit=10000&name=images/[name].[ext]'
}
所以我不知道是否有更简洁的方法来解决这个问题,但这是迄今为止我能想到的最好方法。我欢迎任何反馈或替代方案。
谢谢!
2016 年 6 月 30 日更新
有几个 PR 可以解决这个问题,但是维护者更喜欢将解决方案放在 CSS AST 中而不是 CSS 加载器中...
https://github.com/webpack/style-loader/pull/124 https://github.com/webpack/style-loader/pull/96
希望很快就会有真正的修复...
使用 webpack 2:
在您的 .scss 文件中,在路径前使用 ~。
.yourClass {
background: url('~img/wallpaper.png');
}
利用 webpack 的解析根,将其添加到您的 webpack.config.js:
resolve: {
modules: [
path.resolve(root),
'node_modules'
]
},
它应该也适用于@import,例如@import "~otherfile.scss"