简体   繁体   中英

Webpack [url/file-loader] is not resolving the Relative Path of URL

I am facing a problem in Webpack regarding Relative Path. Let me try to explain the scenario :

I have 2 separate project in Workspace directory :

  1. Project-A [Bundling using Gulp] : Stable & Working
  2. Project-B [Bundling using Webpack] : New project

As both the projects are using same Styling, so I wanted to reuse the SCSS files [consisting of standard variables, predefined layouts, modals, classes etc] of Project A into Project B .

在此输入图像描述

Now, if I am trying to import Project-A index.scss in Project-B index.scss as another partial [ Commenting out the Background Image URL Depency ], webpack is able to generate the required CSS output file.

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

But as Project-A's index.scss is further referring background images from the respective Relative-Path, the webpack build is throwing error

'File / dir not found in XYZ/Project-B/Source/Stylesheets'.

Exact Error Block :

ERROR in ./src/assets/stylesheets/index.scss Module build failed: ModuleNotFoundError: Module not found: Error: Cannot resolve 'file' or 'diWorkSpace\\Project_B\\src\\assets\\stylesheets

screenshot : **在此处输入图片说明**

I am not able to understand, why Webpack is not able to resolve the Relative path of assets inside Project-A and still looking inside 'Project B' .

Here is the Code-Repo URL for the simulated issue : https://github.com/raviroshan/webpack-build-issue/tree/master/WorkSpace

Steps to reproduce.

  1. Download the Repo.
  2. Browse inside Project_B folder, and do a NPM install.
  3. Run 'webpack'. It would build correctly as Relative Image URL code is commented out.
  4. Now put back the commented line of code : https://github.com/raviroshan/webpack-build-issue/blob/master/WorkSpace/Project_A/assets/stylesheets/index.scss#L27

So, finally after so much struggle, got a proper SOLUTION .

It turns out to be an issue with CSS-loader ie it is not able to resolve the URL with respective to current file.

Using resolve-url-loader solved this problem. 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')

Here is updated Code-Repo with solution : https://github.com/raviroshan/webpack-build-issue

Note : Don't omit -loader Your Webpack.config.js should always use the long-form of the loader name (ie the -loader suffix).

There is another package called resolve-url which Webpack can confuse with resolve-url-loader.

It seems like it's css-loader fault and the way it resolves paths in @import and url() . It tries to resolve all paths — even those from imported stylesheets — relative to the main CSS file — which in your case is /Project_B/src/assets/stylesheets/index.scss .

Don't cry! There's a solution!

Maybe it's not perfect, but it's the best one I came with so far.

Create a global variable $assetsPath holding a path to assets relative to the current stylesheet . Then prepend this variable to all your url() values.

In your /Project_A/assets/stylesheets/index.scss you'd write:

/*/ 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");
    }
}

In your /Project_B/src/assets/stylesheets/index.scss you'd write:

/*/ 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";

The Aftermath

If you bundle Project-A with Gulp it's gonna see Project-A's code as:

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

Although, when you bundle Project-B with Webpack it's gonna see Project-A's code as:

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

Therefore, you are saved.

Most definitely I'll look closer at this issue. All of this could be avoided if url-loader would respect a path in the @import statement and apply it to referenced assets accordingly. Either I'm missing something or it should be considered as a bug.

I hope you have a wonderful day!
~Wiktor

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM