Skip to content

image assets cache purge question #3959

Closed

Description

@mkoczorowski

Hi there,

I noticed that all assets are copied over to the dist directory. However even if we change the image in src/assets directory. The image wont be pulled in after release as name is the same.
It would be nice if during a release we update urls in css/html simply appending version number of sort in css such as:

url(assets/logo.png) -> url(assets/logo.png?123)

this would force the browser to download new image. Is this something we can do with cli ?

Thanks for the help

Activity

  1. Meligy commented on Jan 13, 2017

    @Meligy
    Contributor

    There's something in master not yet released.

    A new flag for ng build that's called output-hashing. It takes one of the following values: none, all, media, bundles.

    I suspect you can try setting it to all whenever the next version is released.

    P.S.

    Reference: #3885

  2. un33k commented on Jan 24, 2017

    @un33k

    @Meligy what you have found in master is --output-hashing which is available as of beta.26 and apparently doesn't touch the assets directory and its content as per this.

  3. adamdport commented on Jan 26, 2018

    @adamdport

    @hansl @Meligy A year later, it looks like --output-hashing has no effect on anything in assets. The entire directory is just copied into the build folder without any means of cache invalidation. Should this be reopened?

  4. macleanpinto commented on Apr 10, 2018

    @macleanpinto

    @hansl @Meligy

    ng build --env=prod --output-hashing=all

    The entire directory is copied into the build folder. According to the build tests https://github.com/angular/angular-cli/blob/master/tests/e2e/tests/build/output-hashing.ts

    export default function() {
    return Promise.resolve()
    .then(() => writeMultipleFiles({
    'src/styles.css': 'body { background-image: url("./assets/image.png"); }'
    }))
    // use image with file size >10KB to prevent inlining
    .then(() => copyProjectAsset('images/spectrum.png', './src/assets/image.png'))
    .then(() => ng('build', '--output-hashing=all'))
    .then(() => expectFileToMatch('dist/test-project/index.html', /runtime.[0-9a-f]{20}.js/))
    .then(() => expectFileToMatch('dist/test-project/index.html', /main.[0-9a-f]{20}.js/))
    .then(() => expectFileToMatch('dist/test-project/index.html', /styles.[0-9a-f]{20}.(css|js)/))
    .then(() => verifyMedia(/styles.[0-9a-f]{20}.(css|js)/, /image.[0-9a-f]{20}.png/))

    The defect needs to be reopened.

  5. clydin commented on Apr 10, 2018

    @clydin
    Member

    Assets are intended to be copied verbatim with no additional processing. That is their defining characteristic.
    The test above is also turning the ./assets/image.png file into a resource (used by a global stylesheet). Resources, in contrast to assets, are processed by the system and will be potentially inlined, optimized, and/or hashed depending on the options provided. In practice, an application would generally not have an file be both an asset and a resource as this would cause the file to be present twice within the build output. Once as a directly copied asset and once as a processed resource.

  6. macleanpinto commented on Apr 10, 2018

    @macleanpinto

    "assets": [
    "assets",
    "favicon.ico",
    "resources",
    "i18n"
    ]

    are the files mentioned as assets in angular-cli.json

    I18n contains 2 files

    1. en.json
    2. fr.json

    I am using them for translations.

    These files are cached. As per the documention

    output-hashing=all

    must add hashing to all files, irrespective of contents in assets.

  7. adamdport commented on Apr 10, 2018

    @adamdport

    My team ended up appending a timestamp of the release onto our assets, eg. en.json?v=123456.

    @clydin If assets were intentionally not hashed, what is the suggested approach for invalidating cache of assets?

  8. jeffora commented on Nov 19, 2018

    @jeffora

    @clydin I would also love to know what the recommended practice is for this

  9. clydin commented on Nov 21, 2018

    @clydin
    Member

    Please see the following for recommended practices. Note that server configuration is a critical element to an effective caching strategy.
    https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching

  10. jeffora commented on Nov 21, 2018

    @jeffora

    Thanks for the article @clydin. I totally agree that correct cache configuration on the server is important for ensuring browsers treat cached assets correctly. However, a common strategy to ensure the browser immediately requests a new version when an asset has changed is to use unique names for assets based on their contents. The article you linked specifically calls this out:

    How do you get the best of both worlds: client-side caching and quick updates? You change the URL of the resource and force the user to download the new response whenever its content changes. Typically, you do this by embedding a fingerprint of the file, or a version number, in its filename—for example, style.x234dff.css.

    With the behaviour of angular just copying the assets with no processing, no hash is generated for these assets, making it not possible to achieve this, and it was this I was hoping you had advice on.

  11. clydin commented on Nov 21, 2018

    @clydin
    Member

    @jeffora Further in that same section, the example specifically using an image (as a token asset example) without a unique hash in the file name. max-age combined with ETags are highly effective for image/video/etc. assets.

  12. jeffora commented on Nov 22, 2018

    @jeffora

    Sure, for a photo that rarely or never changes, where the user experience will not change with an out of date image. However, if the asset is an SVG for a menu item, or something that should be considered part of a single "deployment", there is no way to make sure a new version of the app will reference the latest version of the asset.

    Another issue is that as assets are not processed at all, they do not follow the --deploy-url semantics, so if all assets are uploaded to a CDN at a different domain name, the image assets maintain their relative paths to the host domain.

  13. clydin commented on Nov 22, 2018

    @clydin
    Member

    In that case, you have several options. Three of which are to either set the image to no-cache (like the index) and ensure Etags are being used; with HTTP/2 there is no reconnection overhead. Or if the SVG is small, inline it in the template HTML. Or use a CSS background image; which has numerous advantages over an HTML img element (e.g., transformations, animations, etc.).

    As to the second aspect, base HREF would be the preferred option in that scenario. There is rarely a reason to use deploy URL over base HREF.

  14. jeffora commented on Nov 22, 2018

    @jeffora

    Ok thanks for the discussion. It sounds like there is no out of the box support via the angular cli, so I'll look into 6+ builder pack options to customise it ourselves.

    Base href is not really appropriate for this use case, as that tells the browser that all relative URLs on the page should be interpreted as relative to the base href, which is not the behaviour we're after. We serve the site (index.html) from one domain, e.g. site.example.com, and all relative URLs should be relative to that domain (e.g. relative AJAX calls to site.example.com/someapi). All JS/CSS/image assets are uploaded to a CDN hosted at a different domain, e.g. cdn.example-static.net, for a variety of reasons - one of these being that this prevents the browser from sending unnecessary cookies to the server when retrieving static assets.

    The other options suggested might work for specific cases, but they all feel like workarounds - surely there is a valid (and possibly common) use case where static assets that are not JS / CSS should be processed through the same content pipeline as JS / CSS. This is fully supported by webpack, so it would be nice to have an easy way to opt in to this functionality in angular.

  15. clydin commented on Nov 22, 2018

    @clydin
    Member

    With HTTP/2’s header compression, the entire cookie can be encoded in 1 to 2 bytes for repeat requests. There’s no need for a complex setup if cookie request elimination is the primary goal.

  16. angular-automatic-lock-bot commented on Sep 9, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  17. locked and limited conversation to collaborators on Sep 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions