url-loader / file-loader使用webpack打破CSS输出中的相对路径

Jor*_*ker 1 css urlloader webpack sass-loader webpack-file-loader

我正在将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
Run Code Online (Sandbox Code Playgroud)

如您所见,我的dist /文件夹镜像了我的src /文件夹,除了scss被编译为css。

src / index.js导入index.html和style.scss,以便那些文件可以由webpack解析,并且其中的任何图像都可以由url-loader处理:

index.js

import '../../index.html';
import '../scss/style.scss';
Run Code Online (Sandbox Code Playgroud)

style.scss使用相对路径在主体上设置背景图像:

style.scss

body {
    background: url('../img/background.jpg');
}
Run Code Online (Sandbox Code Playgroud)

index.html只是使用相对路径显示图像:

index.html

<img src="./assets/img/pic.jpg" alt="pic">
Run Code Online (Sandbox Code Playgroud)

我使用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());
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ber 6

在这上面花了很多年!publicPath下面的设置丢失了!

 output: {
     publicPath: '/'
 },
Run Code Online (Sandbox Code Playgroud)


Jor*_*ker 5

解决

解决了由于这个职位上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
            }
        }
    ]
},
...
Run Code Online (Sandbox Code Playgroud)

要在开发模式下使用样式加载器而不是像我最初的webpack.config.js中那样使用MiniCssExtractPlugin,您将必须有条件地添加选项,因为样式加载器不接受publicPath选项。我是在webpack.config.js的底部这样做的,如下所示:

if (!devMode) {
    module.exports.module.rules[0].use[0].options = { publicPath: '../../' };
}
Run Code Online (Sandbox Code Playgroud)

然后确保rules数组中的第一个对象用于scss。有条件地添加此内容的一种混乱方式,但现在可以执行。


var*_*ons 3

尝试添加 publicPath 选项

 {
    loader: 'url-loader',
    options: {
        limit: 8192,
        name: "[name].[ext]"
        publicPath: '/assets/img/   //<-- assuming assets is in web root
    }
 }
Run Code Online (Sandbox Code Playgroud)

并将 style.scss 更改为

body {
    background: url('background.jpg');
}
Run Code Online (Sandbox Code Playgroud)