【问题标题】:url-loader / file-loader breaking relative paths in css output using webpackurl-loader / file-loader 使用 webpack 破坏 css 输出中的相对路径
【发布时间】:2019-05-16 04:24:48
【问题描述】:

我正在使用带有一些插件和加载器的 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 使用相对路径在 body 上设置背景图片:

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 更改相对路径,或者只生成正确的路径?另请注意,在开发中使用 style-loader 将 css 注入 html 时,该路径有效,因为它是相对于 html 文件的。理想情况下,webpack 应该能够生成正确的相对路径,具体取决于我是在生产中提取 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());
}

【问题讨论】:

    标签: css webpack sass-loader urlloader webpack-file-loader


    【解决方案1】:

    已解决

    感谢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: '../../' };
    }
    

    然后确保规则数组中的第一个对象是用于 scss。有条件地添加这个有点乱,但现在可以了。

    【讨论】:

      【解决方案2】:

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

       output: {
           publicPath: '/'
       },
      

      【讨论】:

        【解决方案3】:

        尝试添加 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');
        }
        

        【讨论】:

        • 然后 webpack 无法从 style.scss 文件中找到图像,因为它在同一个文件夹中查找它。 (未找到模块:错误:无法解析“/Users/jlwalker/demo/src/assets/scss”中的“./background.jpg”)。它还使 dist/ 输出文件中的路径成为绝对路径,而理想情况下我更喜欢使用相对路径。
        • resolve-url-loader 有什么问题。你是在 sass-loader 上面加的吗?
        • 据我所知,resolve-url-loader 允许您在 sass 部分中使用与这些部分相关的路径,而不是相对于导入这些部分的 sass 文件。我有一个不同的问题。但是由于comment,我现在已经设法让它工作了。将很快更新我的帖子。无论如何,感谢您为我调查!
        • 使用文件加载器为我工作
        【解决方案4】:

        这是我的解决方案:

        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,
                            },
                        }
                    ],
                },
            ]
        

        【讨论】:

          猜你喜欢
          • 2017-10-27
          • 2017-05-09
          • 2018-08-11
          • 2023-04-01
          • 1970-01-01
          • 1970-01-01
          • 2019-02-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多