Webpack [url/file-loader] 不解析 URL 的相对路径

IT技术 javascript reactjs webpack urlloader webpack-style-loader
2021-04-27 15:29:32

我在 Webpack 中遇到了关于相对路径的问题。让我试着解释一下这个场景:

我在Workspace 目录中有 2 个单独的项目

  1. 项目-A [使用 Gulp 捆绑]:稳定且有效
  2. Project-B [Bundling using Webpack]:新建项目

由于两个项目都使用相同的样式,所以我想将项目 A的 SCSS 文件 [由标准变量、预定义布局、模态、类等组成] 重用到项目 B 中

在此处输入图片说明

现在,如果我尝试在 Project-B index.scss 中导入 Project-A index.scss 作为另一个部分 [注释掉背景图像 URL 依赖项],webpack 能够生成所需的 CSS 输出文件。

// Import Project A SCSS [Common Varibles, Classes, Styling etc] 
@import "../../../../Project_A/assets/stylesheets/index";

但是由于 Project-A 的 index.scss 进一步引用了来自相应相对路径的背景图像,webpack 构建抛出错误

“在 XYZ/Project-B/Source/Stylesheets 中找不到文件/目录”。

确切的错误块:

./src/assets/stylesheets/index.scss module构建失败:ModuleNotFoundError:找不到module:错误:无法解析“文件”或“diWorkSpace\Project_B\src\assets\stylesheets”

截屏 : **在此处输入图片描述**

我无法理解,为什么 Webpack 无法解析 Project-A 中资产的相对路径,并且仍在查看 'Project B' 内部

这是模拟问题的代码库 URL:https : //github.com/raviroshan/webpack-build-issue/tree/master/WorkSpace

重现步骤。

  1. 下载回购。
  2. 浏览 Project_B 文件夹,并进行 NPM 安装。
  3. 运行'webpack'。当相对图像 URL 代码被注释掉时,它会正确构建。
  4. 现在放回注释的代码行:https : //github.com/raviroshan/webpack-build-issue/blob/master/WorkSpace/Project_A/assets/stylesheets/index.scss#L27
3个回答

所以,经过这么多的斗争,终于得到了一个合适的解决方案

结果证明是 CSS-loader 的问题,即它无法解析与当前文件相关的 URL。

使用resolve-url-loader解决了这个问题。 https://www.npmjs.com/package/resolve-url-loader

 // Old Loader Config in Webpack-entry
 loader: ExtractTextPlugin.extract('style-loader', 'css-loader?sourceMap!sass-loader?sourceMap')

 // New [Fixed] Loader Config in Webpack-entry
 loader: ExtractTextPlugin.extract('style-loader', 'css-loader?sourceMap!resolve-url-loader!sass-loader?sourceMap')

这是更新的 Code-Repo 解决方案:https : //github.com/raviroshan/webpack-build-issue

注意:不要省略 -loader 你的 Webpack.config.js 应该总是使用加载器名称的长格式(即 -loader 后缀)。

还有另一个名为 resolve-url 的包,Webpack 可能会将其与 resolve-url-loader 混淆。

好像它的CSS-装载机故障并解决了路径的方式@importurl()它尝试解析所有路径——即使是来自导入样式表的路径——相对于主 CSS 文件——在你的情况下是/Project_B/src/assets/stylesheets/index.scss.

不要哭!有一个解决方案!

也许它并不完美,但它是我迄今为止最好的。

创建一个全局变量,$assetsPath保存相对于当前样式表的资产路径然后将此变量添加到您的所有url()值中。

在你的/Project_A/assets/stylesheets/index.scss你会写:

/*/ Using !default we can override this variable even before the following line: /*/
$assetsPath: '../' !default;

.container {
    /*/ ... /*/
    .content-wrapper {
        /*/ ... /*/
        background-image: url($assetsPath + "images/content-bg.jpg");
    }
}

在你的/Project_B/src/assets/stylesheets/index.scss你会写:

/*/ The following variable will override $assetsPath defined in the imported file: /*/
$assetsPath: '../../../../Project_A/assets/';

/*/ Import Project A SCSS [Common Varibles, Classes, Styling etc] /*/
@import "../../../../Project_A/assets/stylesheets/index";

善后

如果您将 Project-A 与 Gulp 捆绑在一起,它会看到 Project-A 的代码为:

        /*/ ... /*/
        background-image: url("../images/content-bg.jpg");

虽然,当您将 Project-B 与 Webpack 捆绑在一起时,它会看到 Project-A 的代码为:

        /*/ ... /*/
        background-image: url("../../../../Project_A/assets/images/content-bg.jpg");

因此,您保存。

我肯定会仔细研究这个问题。如果url-loader尊重@import语句中的路径并将其相应地应用于引用的资产,则所有这些都可以避免要么我遗漏了某些东西,要么应该将其视为错误。

我希望你有一个美好的一天!
~维克托

您需要将 publicPath 设置为相对路径以获取文件加载器中的相对路径。