bholloway / resolve-url-loader

Webpack loader that resolves relative paths in url() statements based on the original source file
563 stars 71 forks source link

Url resolving and sass sourcemaps #25

Closed maps82 closed 5 years ago

maps82 commented 8 years ago

I have the following loader in webpack:

{ test : /.scss$/, loaders: ['style', 'css?sourceMap', 'resolve-url', 'sass?sourceMap'] }

If I keep the ?sourceMap part in the css loader, url resolving doesn't work. If I omit it, I have no working sass sourcemaps. How can I have both?

bholloway commented 8 years ago

There are some issues with sass-loader@>4 you may need to downgrade.

maps82 commented 8 years ago

Yes, therefore I'm using sass-loader 3.2.3, resolve-url-loader 1.5.0. Shouldn't it work with those versions?

bholloway commented 8 years ago

I believe the last release in sass-loader@3.x.x series was also broken and could not be unpublished. I'm not sure which one that is.

Last I used personally was sass-loader@~3.1.2. If you are getting problems with that version then your problem is unrelated to the recent sass-loader incompatibility.

maps82 commented 8 years ago

Just tried with 3.1.2 but still no success. Do you now of an example configuration / project where it works? If not it's also ok, I just wanted to know if it's generally possible to have url resolving together with sass source maps. I can also wait for new releases of sass-loader / resolve-url-loader and then retry.

bholloway commented 8 years ago

I have something but it uses webpack-configurator so may be too confusing.

This loader configuration will build this todo project.

It is interesting that I am extracting the css. Certainly I am not hot-reloading. There is an open issue (#11) with webpack-dev-server, so keep that in mind.

Perhaps as a data-point you should extract the css and see if it works correctly. If so then it is not a problem with resolve-url-loader. In that case I would need to see a full project in order to help.

bholloway commented 8 years ago

Probably unrelated but definitely put the full name on the loaders, i.e. write css-loader not css.

I once had a horrid bug with loaders being confused with project packages.

Also, your regex should escape the period i.e. test : /\.scss$/.

cevou commented 8 years ago

I think source maps only work if you use ExtractTextPlugin. If you don't use it the CSS styles will be inserted with some JavaScript code and the source maps won't be loaded correctly. I was also not yet able to get CSS source maps working in dev environment using webpack-dev-server.

Update: If I use your configuration + inline source maps it seems to kind of work. The CSS is inserted as blob and the files are also there. However, the paths are not prefixed with webpack:// like all the other paths in the source map.

image

maps82 commented 8 years ago

Thanks for the example, I now have:

{
    test: /\.scss$/,
    loaders: ['style', 'css-loader?sourceMap', 'resolve-url-loader?sourceMap', 'sass-loader?sourceMap']
}

So, I added ?sourceMap also to the resolve-url-loader as in your example, but still no success. In my HMR config sourcemaps work (@cevou: although the styles are injected by css, sourcemaps still magically works ;)), but my fonts are not loaded, so url-resolving still seems to fail.

BTW: I updated all loaders to the latest version now (resolve 1.6.9 sass 4.0.0)

bholloway commented 8 years ago

Ensure you have loaders for fonts.

Next try removing resolve-url-loader and using asset paths relative to the top level sass file.

Once that works reinstate resolve-url-loader and use relative asset paths.

bholloway commented 7 years ago

@maps82 How are you going with this?

UGLHong commented 7 years ago

Just to update you since @maps82 seems to dissappear into thin air =(

It still doesn't work at this point of time. I have everything updated to the latest version.

my webpack config.

{
      test : /\.(css|scss)$/,
      loaders : ['style-loader', 'css-loader?sourceMap', 'resolve-url-loader?sourceMap', 'sass-loader?sourceMap']
    }

As usual, removing ?sourceMap from 'css-loader?sourceMap' works. Looking forward for your help. Thanks for your time and effort.

bholloway commented 7 years ago

@UltimateGoDLikE I defer to this comment since I don't have experience with HMR.

Could you please confirm that extracted css (using ExtractTextPlugin) works correctly to establish the source code and loader-chain is generally good.

It may be premature but (assuming there is a down-stream problem with the style-loader or HMR) I also mention adjust-sourcemap-loader in case it helps with debugging or adjusting the source-maps.

wait-hua commented 7 years ago

I also having this problem, when I use the sourceMap, the img url() did not work . { test : /.scss$/, loaders : ['style-loader', 'css-loader?sourceMap', 'resolve-url-loader?sourceMap', 'sass-loader?sourceMap'] }

bholloway commented 7 years ago

@UltimateGoDLikE @wait-hua @maps82 I think you need to write a simple sample project.

This will either work (and so help you with your main project) OR the problem will remain, you can open-source it, and we can discuss.

Otherwise we will not move forward with this.

dkrichards86 commented 7 years ago

@bholloway I'm running into similar issues on a project.

In development, the following loader rule does not resolve urls, fonts in my case. Removing options: { sourceMap: true } from css-loader does resolve the fonts.

{
  test: /\.scss$/,
  use: [
    { loader: 'style-loader' },
    { loader: 'css-loader', options: { sourceMap: true } },
    { loader: 'resolve-url-loader', options: { sourceMap: true } },
    { loader: 'sass-loader', options: { sourceMap: true } }
    ]
}

In production, I use extract-text-plugin to extract my CSS. Fonts are resolved properly in this case.

{
  test: /\.scss$/,
  use: ExtractTextPlugin.extract({
    fallback: "style-loader",
    use: [
      { loader: 'css-loader', options: { sourceMap: true } },
      { loader: 'resolve-url-loader', options: { sourceMap: true } },
      { loader: 'sass-loader', options: { sourceMap: true } }
    ]
}

I made an example repo for debugging purposes. https://github.com/dkrichards86/resolve-url-sourcemap-example

If there's anything I can do to help, please let me know.

bholloway commented 7 years ago

@dkrichards86 Sorry I did not get to this sooner, I have been snowed under.

Refer to this similar problem.

I will make a PR on your example project to better illustrate.

I don't think publicPath is necessarily the best solution. I have not thought about it in depth. But at least it might move you forward.

bs-thomas commented 6 years ago

Hmm, I wonder if this issue has been resolved? I'm getting the same problem where if I remove sourceMap, it will fail to find the font file as per below. Adding "sourceMap: true" solves this problem, but hmm, would be odd to include sourceMap in production I would think.

Module not found: Error: Can't resolve './MaterialIcons-Regular.eot'
dev1lmini commented 6 years ago

@bs-thomas I have noticed that same issue. Is there any solution to solve this?

bs-thomas commented 6 years ago

@dev1lmini Yes my solution was to drop using resolve-url-loader.

I used the "importer" option in my sass-loader, and custom rewrite these URLs. This problem only happens for me on css files, and scss files had no issues. So my importer looks like this:

                importer: function(url, prev, done) { // Function to rebase css url()s so that it points to the correct relative URLs
                  if( url.endsWith('.css') ) {
                    for (let includePath of this.options.includePaths.split(';')) {
                      if ( fs.existsSync(path.join(includePath, url)) ) {
                        let sassPath = path.resolve('./scss');
                        let relativeToIncludePath_posix = path.relative(sassPath, includePath).split(path.sep).join(path.posix.sep);
                        let relativeToImportPath_posix = path.posix.join(relativeToIncludePath_posix, path.posix.dirname(url));
                        let contents = fs.readFileSync(path.join(includePath, url), 'utf8');
                        let contents_cssUrlRewritten = cssUrlRewriter(contents, function(url) {
                          if( url.startsWith('data:') || url.startsWith('#') ) {
                            return url;
                          }
                          return path.posix.join(relativeToImportPath_posix, url);
                        });
                        return {
                          contents: contents_cssUrlRewritten
                        };
                      }
                    }
                  }
                  return url;
                }

Hope it helps.

bholloway commented 6 years ago

@bs-thomas This is very interesting. Thanks for sharing.

In your solution the normal webpack importer seems to be the fallback, as seen here.

~It would be nice if this were a general solution and we could deprecate resolve-url-loader. However for feature based paths (primary use-case) we want to be relative to the current file. I don't see that we get access to that, but I will look further at the "contextual scope" in libsass.~

EDIT - Sorry I misunderstood. This hook will not process url() only @import statements in the scss.

bs-thomas commented 6 years ago

@bholloway Yes, this basically reads the file as a whole. I use this as a starting point, and used another package called "cssUrlRewriter" to deal with the rewriting of the url()s.

bholloway commented 5 years ago

Please refer to #97 as version 3 may help any open issues.

bholloway commented 5 years ago

I'm going to close this ageing issue because we have a new version 3.0.0 which (e2e testing confirms) is much better.

Please open a fresh issue for any ongoing problems and link to this one as needed.

I'm not opposed to reopening this issue but certainly lets talk with respect to the new version.