node-sass-asset-functions icon indicating copy to clipboard operation
node-sass-asset-functions copied to clipboard

Allow relative assets

Open henrahmagix opened this issue 9 years ago • 2 comments

I ended up writing my own custom function to produce relative asset urls. It is possible due to this.options.file – the filepath of the Sass file being rendered – being available inside the function.

I will figure out how to apply it to this repo and submit a pull-request. In the meantime, the code is pasted below and an example project is available at https://github.com/henrahmagix/node-sass-relative-asset-url

Related to #5


var assetUrl = function (type, $assetPath) {
    var assetsPathForType = {
        image: 'app/media/images',
        font: 'app/media/fonts'
    };
    if (!assetsPathForType[type]) {
        throw new Error(`assetUrl: type ${type} not supported, must be one of ${Object.keys(assetsPathForType)}`);
    }
    var assetPath = $assetPath.getValue();
    var sassFilepath = this.options.file;
    // Since sassFilepath is a file, we need to normalise for
    // directory relations.
    var relativeToStylesRoot = path.relative(path.dirname(sassFilepath), 'sass');
    var stylesRootToAssets = path.relative('app/styles', assetsPathForType[type]);
    var stylesToAssetpath = path.join(relativeToStylesRoot, stylesRootToAssets, assetPath);
    var urlString = `url('${stylesToAssetpath}')`;
    return new sassTypes.String(urlString);
};

gulp.task('sass', () => {
    return gulp.src('sass/**/*.sass')
        .pipe(sass({
            functions: {
                'image-url($filepath)': function ($filepath) {
                    return assetUrl.call(this, 'image', $filepath);
                },
                'font-url($filepath)': function ($filepath) {
                    return assetUrl.call(this, 'font', $filepath);
                }
            }
        }).on('error', sass.logError))
        .pipe(gulp.dest('app/styles'));
});

Input

// main.sass
body
    background-image: image-url('myimage.png')
// nested/nested.sass
.nested
    background-image: image-url('nested/mynestedimage.png')

Output

/* main.css */
body {
  background-image: url('../media/images/myimage.png'); }
/* nested/nested.css */
.nested {
  background-image: url('../../media/images/nested/mynestedimage.png'); }

henrahmagix avatar Sep 20 '16 15:09 henrahmagix

If you can setup a test which demonstrates that relative paths are not working, that would be great!

koenpunt avatar Oct 22 '16 18:10 koenpunt

I am also having trouble with relative URLs. It seems like this suggested approach does not handle relative URLs inside of files that are @importd by this.options.file. The this.options.file only points to the entry SASS file, not the currently processed SASS file.

joeljeske avatar Nov 03 '16 16:11 joeljeske