Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

relative urls to images in css point to the wrong place #27

Closed
brainkim opened this issue Oct 1, 2014 · 24 comments
Closed

relative urls to images in css point to the wrong place #27

brainkim opened this issue Oct 1, 2014 · 24 comments

Comments

@brainkim
Copy link

brainkim commented Oct 1, 2014

I'm trying to compile a legacy css file. In this legacy file, there are relative url like `background-image: url(../images/cta-newsletter.png), which get resolved according to the location of the stylesheet. Unfortunately, the extract-text-plugin (or maybe one of the loaders?) will remove this relative url.
I use the url-loader for images like this:

{ test: /\.(png|jpg)$/,
  loader: 'url-loader?name=images/[name].[ext]&limit=8192' },

and the ExtractTextPlugin is added to the plugins array like this:

[..., new ExtractTextPlugin('css/[name].css'),]

so that compiled images and css files go into images and css respectively in the build dir, which mirrors what the src dir looks like.

Am I doing something wrong or crazy? Is there a way to have this plugin keep track of relative urls? Lemme know if this is unclear and I'll explain further.

Thank you!
Brian

@sokra
Copy link
Member

sokra commented Oct 4, 2014

That's a bug. The ExtractTextPlugin need to handle a filename like css/[name].css. As workaround you could use [name].css instead.

@sokra sokra added the type: Bug label Oct 4, 2014
@brainkim
Copy link
Author

brainkim commented Oct 4, 2014

Thanks for the response!

So just to clarify the behavior of the bug, webpack will correctly take into account the output path of images, but will fail to modify each path relative to the output css file. So, for instance, when I tried to manually make the output of the files relative to the css file, the css file would be changed from url(images/letterhead.png) to url(css/images/letterhead.png. I think normal webpack gets around this problem by finding chunks by their id, but extracting a css file would probably require more intensive path tracking of the source and build directories? As a workaround, I've flattened the output dir and that's worked great.

Let me know if there's anything I can do to help! I'm going to be poking around the webpack architecture to see if I can solve this bug myself but it is low priority given that I've found a decent workaround.

@sokra sokra closed this as completed in a95ce1e Oct 13, 2014
@sokra
Copy link
Member

sokra commented Oct 13, 2014

I added a publicPath option for the extract-text-plugin. So you can override it if different from the webpack publicPath

(not published yet)

@raypatterson
Copy link

I think I might be having a similar issue. I'm not sure if there's a way for the plugin to generate relative url() paths in the CSS it extracts or if this is even part of its responsibility.

I am currently, only able to load assets via url() the following way:

In the css-loader I define the app root path which allows me to reference the images with (app source) root relative paths. They are picked up by the file-loader, renamed and written to the root of the output dir.

With just this setting alone, regardless what directory a CSS file may be in, there is no file path for any values passed tourl().

E.g.

A file referenced in SASS as:
url('/images/test.jpg');

Is referenced in CSS as:
url(bfedb93f64bc5b68dba4ad4c84a77b6c.jpg).

I am assuming that this is because there is no awareness of the locations the various CSS files are being extracted to when these paths are being generated?

To overcome this, in the ExtractTextPlugin.extract options I set { publicPath: '/' } so that each reference becomes root relative.

It would be nice to have the option of using relative paths to make the output files more portable. I thought I'd inquire as to whether there is a way to achieve this with existing configurations before attempting to create a post processing step.

What might be helpful is way to access files being processed before they are output, manipulate them and pass them though. I'm not sure if there is already a plugin for this or not.

I've included the relevant portions of my config in case it helps explain.

var plugins = [
  new webpack.optimize.CommonsChunkPlugin({
    name: VENDOR_DIR,
    filename: '[name]/' + BUNDLE_FILENAMES.js,
    chunks: [VENDOR_DIR],
    minChunks: Infinity
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: COMMON_DIR,
    filename: '[name]/' + BUNDLE_FILENAMES.js,
    chunks: chunks
  }),
  new ExtractTextPlugin('[name]/' + BUNDLE_FILENAMES.css, {
    allChunks: true
  })
];

var modulesDirectories = [
  app_dir,
  'node_modules',
  'bower_components'
];

var loaders = [{
  test: /\.scss$/,
  loader: ExtractTextPlugin.extract(
    'style',
    'css?' +
    'root=' + app_dir + // Allows root relative paths in SASS
    '!sass?' +
    'outputStyle=expanded' +
    modulesDirectories.reduce(function(paths, path) {
      paths.push('&includePaths[]=' + path);
      return paths;
    }, []).join(''), {
      publicPath: '/' // Prepends 'url' paths in CSS output files

        // I could use something like...

        // manipulateFile: function(file) {
        //   return ...
        // }
    }
  )
}, {
  test: /\.(jpe?g$|gif|png)$/,
  loader: 'file'
}];

module.exports = {
  src: [
    '**/*.{js}'
  ],
  resolve: {
    modulesDirectories: modulesDirectories
  },
  entry: entry,
  plugins: plugins,
  module: {
    loaders: loaders
  },
  output: {
    filename: '[name]/' + BUNDLE_FILENAMES.js
  }
};

Thanks!

@sokra
Copy link
Member

sokra commented Mar 6, 2015

That's actually a problem. It occurs when you put your css files into different folders. I cannot fix it easily because the design is like this: when css code is extract from modules the output file is not yet known...

@raypatterson
Copy link

@sokra Ok, thanks for letting me know!

@sergelerner
Copy link

@sokra is there any progress/roadmap for this ? relative url are must for us and I dont know how to overcome this issue... we've recently switched our code base to work with webpack. Also Is there any alternative in webpack to scaffold css from sass with relative urls ?

@sokra
Copy link
Member

sokra commented Nov 28, 2015

@sokra is there any progress/roadmap for this ? relative url are must for us and I dont know how to overcome this issue... we've recently switched our code base to work with webpack. Also Is there any alternative in webpack to scaffold css from sass with relative urls ?

I think there is nothing do in this issue.

That's actually a problem. It occurs when you put your css files into different folders. I cannot fix it easily because the design is like this: when css code is extract from modules the output file is not yet known...

I was wrong. There is no problem here, just use publicPath: "../" for css files.

@woohling
Copy link

woohling commented Dec 12, 2016

Still met the same problem ... 😥, and I really do not prefer to use flatten folder structure in my dist folder. (there're several output css files, and it would seem to messy to put them all in one folder)
my src folder is sort of like this:
---images --- bg.jpg
---sass---bg.scss background-image: url('/images/bg.jpg);

and here's my dist folder output:
---images -- none
---css--bg.css background-image: url('/images/bg.jpg) => localhost:8080/images/bg.jpg

and here's my image loader config:
{ test: /.*\.(gif|png|jpe?g|svg)$/i, loader: 'url?name=images/[name].[ext]&limit=10000!image-webpack' //10KB }

Hence in bg.css output file, the background-image url path (localhost:8080/images/bg.jpg) was correct, but image was not rendered in dist/images folder. Seems the image loader was not used, which was quite frustrating.

However, if I changed the code in my sass bg.scss file
---images --- bg.jpg
---sass---bg.scss background-image: url('../images/bg.jpg);

output:
---images --- bg.jpg
---css--bg.css background-image: url('images/bg.jpg) => localhost:8080/css/images/bg.jpg

then the image would be rendered in my dist/images/bg.jpg, but in my dist/css/bg.css file, background-image url path ((localhost:8080/css/images/bg.jpg)), hence the image was not found.

in my new ExtractPlugin config, I used the publicPath: "../", but it still won't work.

Any Help? @sokra
Many thanks ~

@sykp241095
Copy link

@woohling Same issue.

@raviroshan
Copy link

@changLiuUNSW
Copy link

changLiuUNSW commented Jan 17, 2017

@woohling
In you first case background-image: url('/images/bg.jpg'), the reason why url-loader is not used is css-loader will not translate urls if they start with /.

Because url('/images/bg.jpg) will not be translated to require(image/bg.jpg), bg.jpg will not be picked up by url-loader.

Regarding you second case, you should fix it via overriding the publicPath of extract-text-webpack-plugin.

Please refer to this commit I did for angular-cli
angular/angular-cli#4036

@woohling
Copy link

woohling commented Jan 18, 2017

@changLiuUNSW I set the publicPath option to publicPath: '' , but still in the output css file, the path is css/images/bg.jpg;

@liuqipeng417
Copy link

@woohling you should look this
webpack 1:

ExtractTextPlugin.extract([notExtractLoader], loader, [options])

Creates an extracting loader from an existing loader.

  • notExtractLoader (optional) the loader(s) that should be used when the css is not extracted (i.e. in an additional chunk when allChunks: false)
  • loader the loader(s) that should be used for converting the resource to a css exporting module.
  • options
    • publicPath override the publicPath setting for this loader.

webpack: 2:

ExtractTextPlugin.extract(options: loader | object)

Creates an extracting loader from an existing loader. Supports loaders of type { loader: [name]-loader -> {String}, options: {} -> {Object} }.

Name Type Description
options.use {String}/{Object} Loader(s) that should be used for converting the resource to a CSS exporting module (required)
options.fallback {String}/{Object} loader(e.g 'style-loader') that should be used when the CSS is not extracted (i.e. in an additional chunk when allChunks: false)
options.publicPath {String} Override the publicPath setting for this loader

@woohling
Copy link

woohling commented Feb 8, 2017

@liuqipeng417 setting the publicPath didn't work for me.. 😥, the image-url in sass file still relative to dist/css/images/bg.img , not dist/images/bg.img

@sami616
Copy link

sami616 commented May 26, 2017

Intrigued to find out if anyone managed to solve this issue? Having the same issue. I ideally want to house my .css file inside a css/ dir in my dist output dir.

@raviroshan
Copy link

@sami616 : The below solution worked for me. You can try and confirm

https://stackoverflow.com/a/41758240/1681972

@chungchiehlun
Copy link

chungchiehlun commented Sep 22, 2017

@woohling #27
Maybe this will help.

@mhdalmajid
Copy link

we still struggling, I have the same issue , extract-text-webpack-plugin,
url should be dis/media/someimage.ext
but it point to dis/css/media/someimage.ext

@sykp241095
Copy link

@hamodey85 Suggest extract all static files in a same dir without subdirs.

build/
├── background.js
├── default-background.jpg
├── fontawesome-webfont.eot
├── fontawesome-webfont.svg
├── fontawesome-webfont.ttf
├── fontawesome-webfont.woff
├── fontawesome-webfont.woff2
├── icon_128.png
├── icon_16.png
├── icon_24.png
├── icon_32.png
├── search-white.svg
├── vimoment.css
├── vimoment.html
├── vimoment.js
└── weathericons-regular-webfont.woff

@mhdalmajid
Copy link

@huoxy my build file will be messy ,

@mhdalmajid
Copy link

the problem was with file-loader setting, I just fixed it by fixing the publicPath: publicPath: "../"

@jakenuts
Copy link

If you need to modify the url's without changing publicpath etc, you can use 'string-replace-loader' as shown below. (Took me weeks to work this out)

//==============================
// Extracted Styles (scss|sass|css|less)
//==============================
{
    test: /\.(scss|sass|css|less)$/,
    use: ExtractTextPlugin.extract({
        fallback: "style-loader",
        use: [
            { loader: 'string-replace-loader', 
                options: {
                     search:'"/client/', 
                     replace:'"', 
                     flags:'g'
                }},
            { loader: 'css-loader' },
            { loader: 'less-loader' }

        ]
    })
}

@nullhook
Copy link

nullhook commented Apr 6, 2018

@jakenuts your solution works. thank you!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests