url-loader / file-loader разрывая относительные пути в выводе css с помощью веб-пакета
Я использую веб-пакет с некоторыми плагинами и загрузчиками, чтобы взять мою папку 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, чтобы эти файлы можно было проанализировать через веб-пакет, а любые изображения в них можно обработать с помощью 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 я либо внедряю его в html-файлы с помощью style-loader в разработке, либо извлекаю его в собственный файл при производстве с помощью MiniCssExtractPlugin.
Однако, когда webpack анализирует index.html и style.scss, относительные пути заменяются на "assets/img/pic.jpg" и "assets/img/backgorund.jpg" соответственно. Это не нарушает путь в index.html, так как это фактически тот же относительный путь, но это явно проблема для style.css. Как мне остановить url-loader от изменения относительных путей или просто сгенерировать правильные? Также обратите внимание, что, когда CSS внедряется в HTML с помощью style-loader в разработке, путь работает, так как он тогда относительно файла HTML. В идеале веб-пакет должен иметь возможность генерировать правильный относительный путь в зависимости от того, извлекаю ли я css в производственном процессе или внедряю его в процессе разработки.
Я попытался использовать resol-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());
}
2 ответа
РЕШИТЬ
Решено благодаря этому сообщению на github: https://github.com/webpack-contrib/mini-css-extract-plugin/issues/44.
Просто добавьте параметр 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
}
}
]
},
...
Чтобы использовать загрузчик стилей в режиме разработки вместо MiniCssExtractPlugin, как в моем оригинальном webpack.config.js, вам нужно будет добавить опцию в условно, потому что загрузчик стилей не принимает опцию publicPath. Я сделал это в нижней части webpack.config.js примерно так:
if (!devMode) {
module.exports.module.rules[0].use[0].options = { publicPath: '../../' };
}
Затем убедитесь, что первый объект в массиве правил предназначен для scss. Какой-то грязный способ добавить это условно, но пока подойдет.
Потратил на это agaes! настройка общественного пути ниже отсутствует!
output: {
// publicPath: '/'},
Попробуйте добавить опцию 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');
}
Вот мое решение:
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,
},
}
],
},
]