2createStudio / postcss-sprites

Generate sprites from stylesheets.
MIT License
413 stars 50 forks source link

Wrong path in multi-level dir #44

Closed re54k closed 8 years ago

re54k commented 8 years ago

Hi, I got a wrong path when using sprites in different level directories. e.g.

app/
  img/
    sp-num1/
    sp-num2/
  css/
    x.css
    folder/
      y.css

Code in x.css :

.class1 {
    background: url('../img/sp-num/1.png');
}
.class2 {
    background: url('../img/sp-num/2.png');
}

Code in y.css :

.class1 {
    background: url('../../img/sp-num2/3.png');
}
.class2 {
    background: url('../../img/sp-num2/4.png');
}

After transforming, y.css got a wrong url path:

.class1 {
    background: url('../img/sp-num2.png');
}

Right url should be ../../img/sp-num2.png.


Review the source code, line 459:

image.spriteUrl = _path2.default.relative(opts.stylesheetPath, image.spritePath);

should be replaced by:

var styleFilePath = opts.relativeTo === RELATIVE_TO_RULE ? rule.source.input.file : root.source.input.file;
image.spriteUrl = _path2.default.relative(_path2.default.dirname(styleFilePath), image.spritePath);

Please check this.

vvasilev- commented 8 years ago

Hi, Can you paste your configuration so I can reproduce the bug?

re54k commented 8 years ago

Configuration:

{
    stylesheetPath: './src/css',
    spritePath: './src/img/',
    filterBy: function(img) {
        if ( /\/sp\-/.test(img.url) ) {
            return Promise.resolve();
        }
        return Promise.reject();
    },
    groupBy: function(img) {
        var match = img.url.match(/\/(sp\-[^\/]+)\//);
        return match ? Promise.resolve(match[1]) : Promise.reject();
    }
}

With code _path2.default.relative(opts.stylesheetPath, image.spritePath); sprite path will always be same path relative to options.stylesheetPath. But the expected url should be relative path from sprite path to css file which use this sprite.

vvasilev- commented 8 years ago

I think that it's better to use the onUpdateRule hook to rewrite the url of sprite.

var path = require('path');
var sprites = require('postcss-sprites').default;
var spritesUpdateRule = require('postcss-sprites').updateRule;
var opts = {
    stylesheetPath: './src/css',
    spritePath: './src/img/',
    filterBy: function(img) {
        if ( /\/sp\-/.test(img.url) ) {
            return Promise.resolve();
        }
        return Promise.reject();
    },
    groupBy: function(img) {
        var match = img.url.match(/\/(sp\-[^\/]+)\//);
        return match ? Promise.resolve(match[1]) : Promise.reject();
    },
    hooks: {
        onUpdateRule: function(rule, comment, image) {
            image.spriteUrl = path.relative(rule.source.input.file, path.resolve(image.spritePath));

            // Call the built-in logic
            spritesUpdateRule(rule, comment, image);
        }
    }
}

See Output Dimensions for detailed usage of onUpdateRule hook.

re54k commented 8 years ago

It looks better. Thank you!