Unable to use assets in url() in scss after upgrading to Angular 10

Issue

I upgraded my Angular application from v9 to v10. Almost everything worked but all my images used in url("assets/images/some/path/image.png") started to throw the exception-

ERROR in ./src/app/pages/about-us/about-us.component.scss
Module Error (from ./node_modules/postcss-loader/src/index.js):
(Emitted value instead of an instance of Error) CssSyntaxError: /Users/shashank/Projects/curika/temp-ssr/src/app/pages/about-us/about-us.component.scss:4:20: Can't resolve './assets/images/about-us.png' in '/Users/shashank/Projects/curika/temp-ssr/src/app/pages/about-us'

  2 |   display: block;
  3 |   min-height: 500px;
> 4 |   background: url("./assets/images/about-us.png") no-repeat center;
    |                    ^
  5 | }

Angular 10 error of assets

I tried various old links but none worked.

  1. https://github.com/angular/angular-cli/issues/12797
  2. https://github.com/angular/angular/issues/32811

Solution

Not really sure what’s changed in Angular 10?

But I found three solutions. The first solution I knew will work but that’s time taking to implement in an existing mid-size application. But if you have only a few assets to fix, you should go for the first solution only.

Solution 1 – Using relative assets path (Recommended)

The solution is to use the relative path (from your .scss file) of your assets. Basically adding ../ until the assets folder is reached.

:host {
    display: block;
    min-height: 500px;
    // Using relative path
    background: url('../../../assets/images/about-us.png') no-repeat center;
}

Pros

  1. This approach enables the hashing of your static assets. Once your application is built (using ng build --prod), your asset URL will be replaced with an MD5 hash to burst the caching.

    So your URL

    background: url('../../../assets/images/about-us.png') no-repeat center;
    

    will be replaced as

    background: url('about-us.add9979f32e1c969e6f8.png') no-repeat center;
    

    This is basically an MD5 checksum of the content of the image. So basically, when the image changes even by one pixel, this checksum will be changed by Angular. This helps you to burst caching in future when you change your image while keeping the file name the same.

    Read more here for knowledge.

  2. IDE (I use IntelliJ IDEA) does not show errors of the assets in your SCSS files that means if the file path is wrong, IDE will tell you in advance.

    IDE Errors Gone

  3. You get the directory linking. That means if I press Ctrl & click on a directory in the URL above, IDE will open up that directory.

Cons

  1. (Manageable) This might be a cumbersome approach as the developer has to write the asset which needs to be relative to the assets folder.

  2. (Manageable) The hashed asset (image in this case) will be copied to the root folder in the build (i.e. dist by default) directory which might fail your any kind of URL rules (for example, caching rules). So instead of-

    https://example.com/assets/images/about-us.png
    

    the following URL will be used-

    https://example.com/about-us.add9979f32e1c969e6f8.png
    
  3. (Manageable) If you change the path of your component, you have to change the image URL as well.


Solution 2 – Quick Fix

Based on the answer posted here https://github.com/angular/angular-cli/issues/10004#issuecomment-375969537, adding / in front of the URL worked.

:host {
    display: block;
    min-height: 500px;
    background: url('/assets/images/about-us.png') no-repeat center;
}

Pros

  1. You do not have to add many ../ prefixes to make it a relative URL.
  2. If you change the path of your component SCSS file, you don’t have to change the path of your assets in url("").

Cons

  1. The second solution will not work in the production build if --base-href is used (as stated here). angular-cli#18043.

  2. Your IDE keeps showing the path error even if the path is correct.

    IDE path error

  3. You do not get the hashed URLs to burst the cache (unlike solution 1)


Solution 3 – Fooling the Angular CLI processor (not recommended)

I looked into the CLI code & figured out that if a URL starts with ^, Angular ignores the asset by bypassing the URL.

:host {
    display: block;
    min-height: 500px;
    background: url('^assets/images/about-us.png') no-repeat center;
}

Source code- https://github.com/angular/angular-cli/blob/v10.0.0/packages/angular_devkit/build_angular/src/angular-cli-files/plugins/postcss-cli-resources.ts#L72

Pros

  1. You do not have to add many ../ prefixes to make it a relative URL.

  2. If you change the path of your component SCSS file, you don’t have to change the path of your assets in url("").

Cons

  1. This solution might get removed in the future releases as stated by one of the Angular CLI developers in #18013 (comment)

Answered By – Shashank Agrawal

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published