question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

url() with variable or relative path in sass/scss is broken

See original GitHub issue

This issue organizes many issues around relative url() in sass/scss and adds many information.

(Please convert to discussion if it should be a discussion.)

Related: #6618, #3164, #2993, #5337, #4269

Premise

sass does not support rebasing relative url (https://github.com/sass/libsass/issues/532). For example,

/* src/foo.scss */
@import "./nested/bar.scss";

/* ---- */
/* src/nested/bar.scss */
.bar {
  background: url('./bar.png'); /* intends nested/bar.png */
}

becomes

/* src/foo.css */
.bar {
  background: url('./bar.png'); /* becomes src/bar.png */
}

Also there is no API for custom rebasing (https://github.com/sass/sass/issues/2535).

In sass-loader, this feature is not implemented. It presents resolve-url-loader for solution. This one rebases url after converted to css and uses sourcemaps to obtain the original file path.

Current Vite’s implementation

It is implemented by this rebaseUrls function. This function is called inside importer option which is passed to sass. But importer will only be called if it is not a relative import because of the resolve order.

Loads are resolved by trying, in order:

  • Loading a file from disk relative to the file in which the @use or @import appeared.
  • Each custom importer.
  • Loading a file relative to the current working directory.
  • Each load path in includePaths.
  • Each load path specified in the SASS_PATH environment variable, which should be semicolon-separated on Windows and colon-separated elsewhere.

Interface LegacyStringOptions<sync> importer

Which means if a file is resolved by relative path, rebaseUrls functions won’t be called. The example is below.

/* src/foo.scss */
@import "./nested/bar.scss";
/* @import "/@/nested/bar.scss"; */ /* if a alias is used `rebaseUrls` will be called */

/* ---- */
/* src/nested/bar.scss */
.bar {
  background: url('./bar.png');
}

This is why #6618 only happened when alias is used. (So url won’t be rebased if it is imported by relative path.)

Also rebaseUrls is doing the transform over sass files and this makes it unable to rebase url including variables like url($url) (#3164, #2993, #5337). This can be mitigated by not transforming url which starts with a variable (#4269). But it won’t work if it is used like below.

$url: './relative.png';

.foo {
  background: url($url);
}

Solutions

I suggest several solutions.

  1. Since this is not a sass’s official feature, drop this feature(rebasing relative path) from Vite.
    • Supporting absolute paths (including paths from config.root) is easily achieveable by doing rebaseUrls after the content is transformed to css.
  2. Mitigate as much as possible
    • I have no idea how to call rebaseUrls even if it is imported by relative path.
  3. Implement a logic simillar to resolve-url-loader.
    • Maybe if the sourcemaps are enabled, UrlRewritePostcssPlugin can handle this.

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:16
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
andyexetercommented, Nov 8, 2022

@sapphi-red I was talking about this one:

sass does not support rebasing relative url (sass/libsass#532). For example,

/* src/foo.scss */
@import "./nested/bar.scss";

/* ---- */
/* src/nested/bar.scss */
.bar {
  background: url('./bar.png'); /* intends nested/bar.png */
}

becomes

/* src/foo.css */
.bar {
  background: url('./bar.png'); /* becomes src/bar.png */
}

However, upon trying to create a reproducer it does in fact seem to be working as expected now.

I suspect my issue is being caused by using Vite in a Symfony application with https://github.com/lhapaipai/vite-bundle

Apologies 😃

0reactions
sapphi-redcommented, Nov 20, 2022

@andyexeter I see. It would be great if you create a new issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

SASS relative url wrongly configured - Stack Overflow
I am working on React project and I have a problem with pointing to the image assets from scss files with relative paths....
Read more >
Dart Sass Command-Line Interface
This option controls how the source maps that Sass generates link back to the Sass files that contributed to the generated CSS. Dart...
Read more >
sass-loader - npm
If you pass the generated CSS on to the css-loader , all urls must be relative to the entry-file (e.g. main.scss ).
Read more >
url() - CSS: Cascading Style Sheets - MDN Web Docs
The url() CSS function is used to include a file. The parameter is an absolute URL, a relative URL, a blob URL, or...
Read more >
roots/bud-sass
When using @roots/bud-sass , you will find that the url() function is not working as expected. This is because the url() function is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found