我正在将Webpack与一些插件和加载程序结合使用,以获取src /文件夹并构建dist /文件夹。 url-loader(当图像大于特定限制时回退到文件加载器)正在将它在我的html和scss文件中找到的图像输出到预期的正确目录。但是,它会更改这些文件中的相对路径,从而输出具有错误路径的css文件。
文件结构:
src/
index.html
assets/
js/
index.js
scss/
style.scss
img/
pic.jpg
background.jpg
dist/
index.html
assets/
js/
index.js
css/
style.css
img/
pic.jpg
background.jpg
您可以看到我的dist /文件夹镜像了我的src /文件夹,除了scss编译为css。
src / index.js导入index.html和style.scss,以便Webpack可以解析这些文件,并且其中的任何图像都可以由url-loader处理:
index.js
import '../../index.html';
import '../scss/style.scss';
style.scss使用相对路径在主体上设置背景图像:
style.scss
body {
background: url('../img/background.jpg');
}
index.html仅使用相对路径显示图像:
index.html
<img src="./assets/img/pic.jpg" alt="pic">
我使用HtmlWebpackPlugin在我的html文件中进行复制,因为它允许我指定要自动包含为脚本标签的块。对于CSS,我要么使用开发中的style-loader将其注入html文件,要么使用MiniCssExtractPlugin将其提取到生产环境中的自己的文件中。
但是,当webpack解析index.html和style.scss时,相对路径分别被替换为'assets / img / pic.jpg'和'assets / img / backgorund.jpg'。这不会破坏index.html中的路径,因为它实际上是相同的相对路径,但这显然是style.css的问题。如何停止url-loader更改相对路径,或仅生成正确的路径?另请注意,在开发中使用样式加载器将css注入html时,该路径有效,因为该路径是相对于html文件的。理想情况下,webpack应该能够根据我在生产中提取css还是在开发中注入css来生成正确的相对路径。
我尝试使用resolve-url-loader,指定publicPath和outputPath,当然也可以在线搜索答案,但是运气不佳。
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
mode: devMode ? 'development' : 'production',
entry: {
index: './src/assets/js/index.js',
},
output: {
filename: 'assets/js/[name].js',
path: path.resolve(__dirname, 'dist')
},
devServer: {
contentBase: path.join(__dirname, 'src'),
watchContentBase: true,
hot: devMode,
},
devtool: devMode ? 'source-map' : '(none)',
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'src/index.html',
}),
new MiniCssExtractPlugin({
filename: 'assets/css/style.css',
})
],
module: {
rules: [
{
test: /\.html$/,
use: [
{
loader: 'html-loader'
}
]
},
{
test: /\.(jp(e?)g|png|svg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
name: 'assets/img/[name].[ext]'
}
}
]
},
{
test: /\.scss$/,
use: [
{
loader: devMode ? 'style-loader' : MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
sourceMap: devMode,
importLoaders: 2
}
},
{
loader: 'sass-loader',
options: {
sourceMap: devMode
}
}
]
}
]
}
};
if (devMode) {
module.exports.plugins.push(new webpack.HotModuleReplacementPlugin());
}
答案 0 :(得分:3)
已解决
解决了感谢github上的这篇文章:https://github.com/webpack-contrib/mini-css-extract-plugin/issues/44#issuecomment-379059788。
只需将publicPath选项添加到MiniCssExtractPlugin中,如下所示:
...
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../../' // path to director where assets folder is located
}
},
{
loader: 'css-loader',
options: {
sourceMap: devMode,
importLoaders: 2
}
},
{
loader: 'sass-loader',
options: {
sourceMap: devMode
}
}
]
},
...
要在开发模式下使用样式加载器,而不是像我最初的webpack.config.js中那样使用MiniCssExtractPlugin,则必须有条件地添加该选项,因为样式加载器不接受publicPath选项。我是在webpack.config.js的底部这样做的:
if (!devMode) {
module.exports.module.rules[0].use[0].options = { publicPath: '../../' };
}
然后确保rules数组中的第一个对象用于scss。有条件地添加此内容的一种混乱方式,但目前仍可以执行。
答案 1 :(得分:0)
尝试添加publicPath选项
{
loader: 'url-loader',
options: {
limit: 8192,
name: "[name].[ext]"
publicPath: '/assets/img/ //<-- assuming assets is in web root
}
}
然后将style.scss更改为
body {
background: url('background.jpg');
}
答案 2 :(得分:0)
这是我的解决方法:
const devMode = process.env.NODE_ENV !== 'production';
...rules: [
{
test: /\.scss$/,
use: [
devMode ? 'style-loader' :
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
}
},
{
// translates CSS into CommonJS
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
// Autoprefixer usw.
loader: 'postcss-loader',
options: {
ident: 'postcss',
},
},
{
// compiles Sass to CSS, using Node Sass by default
loader: 'sass-loader',
options: {
sourceMap: true,
},
}
],
},
]
答案 3 :(得分:0)
对此花费了很多精力!缺少下面的公共路径设置!
output: {
// publicPath:'/' }