angular-cli: Can't use relative paths in url() in scss files
Bug Report or Feature Request (mark with an x
)
- [ ] bug report -> please search issues before submitting
- [x] feature request
Command (mark with an x
)
- [x] new
- [x] build
- [ ] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc
Versions
npm: 6.4.1 node: v10.7.0 ng cli: 6.2.6 macOS High Sierra
Repro steps
- Create new project
ng new ng-sass-test–style=scss
- Add following files:
- src
- sprite
- _sprite.scss
- sprite.svg
With the following content:
# _sprite.scss
.sprite-common {
background-image: url('sprite.svg');
}
Add the following line to src/styles.scss
.
@import '~src/sprite/sprite';
Add the same line to src/app/app.component.scss
.
The log given by the failure
ERROR in ./src/styles.scss (./node_modules/raw-loader!./node_modules/postcss-loader/lib??embedded!./node_modules/sass-loader/lib/loader.js??ref--15-3!./src/styles.scss)
Module Error (from ./node_modules/postcss-loader/lib/index.js):
(Emitted value instead of an instance of Error) CssSyntaxError: /***/ng-sass-test/src/sprite/_sprite.scss:2:22: Can't resolve 'sprite.svg' in '/***/ng-sass-test/src'
1 | .sprite-common {
> 2 | background-image: url('sprite.svg');
| ^
3 | }
ERROR in ./src/app/app.component.scss
Module Error (from ./node_modules/postcss-loader/lib/index.js):
(Emitted value instead of an instance of Error) CssSyntaxError: /***/ng-sass-test/src/sprite/_sprite.scss:2:22: Can't resolve 'sprite.svg' in '/***/ng-sass-test/src/app'
1 | .sprite-common {
> 2 | background-image: url('sprite.svg');
| ^
3 | }
Desired functionality
I would like to be able to use the relative file path in the scss file. I know this is solved by using an absolute path for the image. But I’m using the package svg-sprite, I’m not an expert in the package, but it looks like it doesn’t support generation of an absolute path. Maybe I’m missing something in the angular-cli setup, so I can use this way of path-handling.
Mention any other details that might be useful
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 36
- Comments: 41 (2 by maintainers)
Commits related to this issue
- feat(@angular-devkit/build-angular): rebase relative stylesheet assets when using preprocessors Previously, when using a preprocessor, resources (e.g., `url(./my-image.jpg)`) referenced in a styleshe... — committed to clydin/angular-cli by clydin 4 years ago
- feat(@angular-devkit/build-angular): rebase relative stylesheet assets when using preprocessors Previously, when using a preprocessor, resources (e.g., `url(./my-image.jpg)`) referenced in a styleshe... — committed to angular/angular-cli by clydin 4 years ago
works for me (version 8.0.1)
I think the recommended approach here is to put these sprite file in the assets folder, and use root level paths (starting with
/
) for urls in sass files that are imported by other sass files.In
scss
files at an absolute path;in your
angular.json
add the following so that the sprite is copied, underarchitect
->build
->options
From
svg-sprite
package point of view, there will be no changes.You can use inline CSS style
<div style="background-image: url('/assets/images/logo.svg');" ></div>
The solution is to write the path as if you were starting from “angular.json”.
Instead of
background-image: url('../assets/images/pattern-dot-grid.svg');
Write it like this (witout the dots at the beggining)
background-image: url('/assets/images/pattern-dot-grid.svg');
– this worked for me ☺
Please consider not removing
rebaseRootRelativeCssUrls
build option (https://github.com/angular/angular-cli/issues/14587) until this issue is fixed. Since this issue prevents using relative URLs, therebaseRootRelativeCssUrls
option is the only workaround when needing to specify a base-href when building.@pnrdk did you try the following (note the / between the ~ and ‘assets’)?
~/assets/images/myimage.png
@iwnow This has been said to cause the app to be deployed with images copies to the dist folder (out of the assets folder) meaning you have multiple copies for no reason.
Angular Team: Please fix this, it’s very sad that it’s now “The recommended method to transition is to use relative paths within the source stylesheet”.
This ticket has been here for well over a year. What was the plan? Was there one? It seems the idea was to just break AngularCLI and say use this method that doesn’t work and hope for the best.
the only way i found how to fix it in builds is to specify the base-href attribute to be the same as the path i plan to deploy to, for example:
and then in the SCSS file use:
background-image: url('~/assets/icon.svg')
.after building the app, the ~ char is replaced with whatever value you provide to the --base-href attribute.
Hi guys, I’ve had the same problem and I fixed it as @Dada-Tech has mentioned
I have my site on
https://url/account
, somebackground-image: url('/image.png')
and it was working on Angular v7.0.2. However, it is not working after migrating to v8.2.1v7.0.2 scss:
background-image: url('/image.png')
url after deploy:https://url/account/image.png
v8.2.1 scss:
background-image: url('/image.png')
url after deploy:https://url/image.png
FYI - the caret sign was previously discussed in the following issue https://github.com/angular/angular/issues/32811
the problem this works in dev env, but not when building the app. (in SCSS - didn’t try plain CSS)
the build output for ‘~/assets/images/logo.svg’ is -> ‘/assets/images/logo.svg’ which prevents from deploying the app in any other path than the root, even though in my index.html i set the baseHref to be relative ‘./’
background-image: url(‘…/…/assets/img/bg-masthead.jpg’); worked for me. Very annoying.
@michael-letcher yes I understand but I have no multiple copies, all works as expected this is a simple workaround, but I still want this to be fixed
I get the following, rocking Angular CLI: 7.3.0, Angular: 7.2.3.
@bnohad unfortunately this didn’t work with
--localize
flag that has been introduced in angular 9 to compile several language locales using one command. I useng build --prod --localize
command and has configured 2 languages but there no added language directory to url path when I write like thisbackground-image: url('~/assets/icon.svg')
But I see language directory in Html base tag. Probably this is bug of angular 9A couple of the workarounds here are basically: “just use absolute paths”. The issue is about the inability to use relative paths 😄
In some cases you can’t use absolute because you have a baseHrefUrl like
/en/
so / is going out of that folder to a path that doesn’t exist.You can workaround this using Express I guess but
The problem with that is that I can’t change the sprite.scss, it is generated by the svg-sprite package. For as far as I know, it does not have the option to generate with an absolute path.
Yes @devniel. And that was why I wasn’t allowed to add it to the documentation (reference: https://github.com/angular/angular/pull/32921#discussion_r331118890)
Just found that when using a caret
^
as the first character on the url provided inurl()
, the angular building process ignores it (it’s actually a postcss-loader plugin), so with that you can use anything including relative urls expecting different base-hrefs. example:Of course, there is an
assets
folder in angular where you will put the images (to have it working locally you can justurl("^assets/images")
) but the point is that when you want to deploy it in production, maybe you will copy your assets folder content to yourserver.com/myapp/myfiles
folder, so in this case it’s very useful, otherwise, the builder will try to resolve the path and it will throw an error because it can’t found the files (actually, it has a problem when the url is relative),In addition, as off-topic, when resolving the urls (not using ^), the files will be copied to the
dist/project
folder, not todist/project/assets
(that’s the destiny of theassets
folder configured inangular.json
), so it will be quite a mess. A solution is to override the webpack scss loaders or (a clean way) is to use the next approach by including the target files in the assets directories, even of third party modules.For reference: https://github.com/angular/angular-cli/blame/523a20d92bc516dbdf2ea17bc9b02d9402232c47/packages/angular_devkit/build_angular/src/angular-cli-files/plugins/postcss-cli-resources.ts#L72
It’s compiled to
in my case which is not what’s expected.
Globally I’d recommand to never use absolute paths in
url()
as it is pure CSS and is always relative to the index.html file in production.However, the compiler complains when using relative paths, especially if you import a
variables.scss
file containing assets in your components.This worked for me with the latest version of the CLI.
Tried it out, works perfect. Thanks for the idea @alan-agius4 !
Just had a quick look at this, at this is tricky one.
Since in
./src/app/app.component.scss
if you want to use relative url, the image src, should be../sprite/sprite.svg
, while forstyle.scss
it should be./sprite/sprite.svg
.