Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Images in templates are not fingerprinted #3415

Closed
texel opened this issue Dec 5, 2016 · 33 comments
Closed

Images in templates are not fingerprinted #3415

texel opened this issue Dec 5, 2016 · 33 comments
Labels
feature Issue that requests a new feature type: faq

Comments

@texel
Copy link
Contributor

texel commented Dec 5, 2016

OS?

Mac OS X

Versions.angular-cli: 1.0.0-beta.21

node: 6.9.1
os: darwin x64

Repro steps.

Due to the way that assets are built, references to images in html templates are not processed by webpack and therefore aren't fingerprinted. Furthermore, the src attributes don't get prefixed by publicPath (in the event that the PR #3285 is merged) and we don't have the flexibility to locate images with their components (#3292)

The log given by the failure.

n/a

Mention any other details that might be useful.

I have a branch that uses html-loader instead of raw-loader for html files, which fixes all these problems. I'd be willing to create a PR that makes this change, perhaps only if passed a config option, but I'm open to other ideas and would like to get the opinion of the angular-cli team as to whether this is something they're interested in supporting.

@hansl
Copy link
Contributor

hansl commented Dec 5, 2016

The problem is that html-loader is not Angular2 friendly. It messes up the paths and doesn't understand the templates. We're looking at it but had to remove it (see #2537 and all related issues). We need more investigation.

@hansl hansl added effort2: medium (days) needs: investigation Requires some digging to determine if action is needed type: discussion feature Issue that requests a new feature labels Dec 5, 2016
@hansl
Copy link
Contributor

hansl commented Dec 5, 2016

Oh and for reference, the assets path being wrong is webpack-contrib/html-loader#85.

@texel
Copy link
Contributor Author

texel commented Dec 6, 2016

@hansl I'm not sure what you mean by messing up paths? You can get html-loader to play nicely with Angular 2 by passing it a -minimize flag, I have it working just fine in a non-angular-cli app, and I've hacked in support for it in our custom angular-cli branch. It supports the current use of the assets folder by prefixing with ~, so <img src="~assets/images/foo.png"> will be interpreted as require('assets/images/foo.png') while <img src="assets/images/foo.png"> will be interpreted as require('./assets/images/foo.png').

I'm a bit confused though, what was the issue with base href exactly?

@clydin
Copy link
Member

clydin commented Dec 6, 2016

The change would essentially break all existing projects that use img tags. The use of the ~ is also webpack specific so institutionalizing its use would break down the CLI's abstraction around webpack.

Looking at the documentation, the html-loader does seem to have a setting named root, which could be set to the project root and allow root-relative URLs to be used instead of the ~. Whether that is better or not is up to question (e.g., confusion with regards to base href usage). Also, its viability would need to be tested of course; and it would still be a breaking change.

@texel
Copy link
Contributor Author

texel commented Dec 6, 2016

@clydin At first it should probably be opt-in, though I'd love to find a way to make it backwards compatible with existing projects. To your point yes, ~ is webpack-specific but it's something that already works in CSS @import statements: @import "~assets/stylesheets/variables.scss";.

It seems like there's a bit of a philosophical split here with regard to how assets are resolved- in most cases (TypeScript files, CSS, etc) they're hooked into the Webpack system and resolved on-disk at compile time, but in templates they're referred to by relative path.

For what it's worth, at my company we serve all our assets (JS and otherwise) from a CDN, and only serve the template from our primary domain. By setting publicPath in Webpack, our configuration works out of the box in both development and prod, plus we get fingerprinting (and even inlining if we want) of our images for free.

The only way to support this use case with the current incarnation of angular-cli is to manually prefix every src attribute with our CDN URL which is a non-starter. I suppose we could write a build task that does string replacement on the built artifacts but that still doesn't get us 1) cache busting and 2) the ability to refer to images outside the assets folder.

I'm open to other ways of solving this problem and I'm certainly sensitive to the backward-compatibility concerns. Perhaps a custom html loader that processes paths differently, eg src="assets/images/foo.png" is the equivalent of require('assets/images/foo.png') and src="./images/foo.png" is equivalent of require('./images/foo.png')?

@clydin
Copy link
Member

clydin commented Dec 6, 2016

@texel, I agree as to the value it would provide. Implementing it with minimal upheaval is the problem.

As to the use of the tilde, yes it currently works in other areas (as do several other webpack/webpack-plugin related capabilities), but they are currently not (at least to my knowledge) documented as supported or recommended features of the CLI. Personally, I view them no different than internal APIs: They work but expect them to break in the future.

@jupapios
Copy link

are there any updates on this issue?

@donovankim
Copy link

+1

@balteo
Copy link

balteo commented May 6, 2017

Any update on this issue? Also see #4212

@filipesilva
Copy link
Contributor

We had this in once, by using HTML-loader, but it broke a lot of projects (see #2396).

@Zefling
Copy link

Zefling commented May 23, 2017

Is it not possible to have a parameter for disabled the control on url?
Like css-loader?url=false

@asnowwolf
Copy link

I think this request is a common requirement, in fact, I have been using my customized version, and never put any file in the asset directory, can provide an option to allow users to choose which way to use?
Thank you.

@filipesilva
Copy link
Contributor

#8139 is a duplicate of this issue, but there's really good insights there onto why this is hard.

@asnowwolf it's great to know that you've come up with a solution that fits your usecase. I am interested in how you did it. Would you be interested in making a rough PR and we can see if we can take it from there? Don't worry too much about making it look good for now, just the basic logic to see if there's any important thing missing.

@asnowwolf
Copy link

Ok, thank you. I will be about to submit a PR next week. The basic idea is to add an option in .angular-cli.json to identify the processing strategy used in this project.

@asnowwolf
Copy link

asnowwolf commented Oct 26, 2017

@filipesilva
I have just found a new way that may be able to gracefully solve this issue, see the PR #8190

@asnowwolf
Copy link

asnowwolf commented Oct 26, 2017

But I could not fully understand the issue described in #8139, my current understanding is that HTML-Loader does not support the template with angular directives and binding syntax, e.g. <img src="{{id}}.jpg"/>, but the specific situation I do not know. Is there a demo project that can reproduce this issue?

asnowwolf pushed a commit to asnowwolf/html-loader that referenced this issue Oct 26, 2017
It is useful for handling Angular templates correctly. see angular/angular-cli#3415
@brunor2509
Copy link

@filipesilva is there any update or news for this issue?

@nkm8
Copy link

nkm8 commented Feb 14, 2018

It is really troubling that a basic, fundamental need like this remains unresolved after over 12 months. The entire 'new world' in angular is for everything to be built around components. However, if the components aren't self-contained (images/assets/etc. owned by the component, not the project), then I don't understand how components can be easily re-used between projects.

Perhaps on a larger scale this issue also relates to the discussion around the angular package format and how components are meant to be distributed/referenced by multiple projects.

Regardless, unless people follow the monorepo/monoproject approach, I don't see a simple path forward for sharing components at this point.

@stephengardner
Copy link

It's been a long migration for me over to Angular from AngularJS, and I am hoping some of these features will hit the horizon. Subbed here

@yjaaidi
Copy link

yjaaidi commented May 3, 2018

In order to fix this issue, I usually add declare var require: (path: string) => any to src/typings.d.ts to fix missing typing and I create component properties pointing to the images:

@Component({
    template: `<img [src]="logoUrl">`
})
export class LogoComponent {
    logoUrl = require('./logo.png')
}

@clydin clydin removed effort2: medium (days) needs: investigation Requires some digging to determine if action is needed labels Jul 2, 2018
@netsrotr
Copy link

As angular 6 is now final and public: how is this solved there? Can you provide a back port to NG5 to prevent lots of @yjaaidi solution(s)??

@NVK15
Copy link

NVK15 commented Nov 12, 2018

any solution for adding hash to images files or other type of files in assets folder? any updates on this?

@yjaaidi
Copy link

yjaaidi commented Nov 13, 2018

By the way, I wrote a blog post about this.
https://blog.wishtack.com/2018/06/20/unleash-the-power-of-webpack-in-angular/

The nice thing is that you end up with build errors if the picture is not there plus it works with any kind of file.

Have a nice day!

@mgechev
Copy link
Member

mgechev commented Dec 17, 2018

@texel this is out of our roadmap. @yjaaidi's blog post describes a possible solution although it may have some performance implications, and introduce extra boilerplates.

I'd recommend you to look at ngx-build-plus, so you can introduce a custom webpack config.

@mgechev mgechev closed this as completed Dec 17, 2018
@th0r
Copy link

th0r commented Apr 9, 2019

@mgechev I'm kindly asking you to revisit this decision. I was shocked that Angular CLI doesn't support such a common and a must-have use case like rewriting asset URLs in component templates! What is the recommended approach to refer images from the components then if I want to upload all of them to the CDN? Hash all of them manually, write the names map to the manifest.json, send it to the client and use some helper/pipe to rewrite them in the runtime? But this solution doesn't scale and require a lot of manual work.

@mgechev mgechev added the needs: discussion On the agenda for team meeting to determine next steps label Apr 9, 2019
@mgechev mgechev reopened this Apr 9, 2019
@mgechev
Copy link
Member

mgechev commented Apr 9, 2019

If you need my input, we can discuss when I'm back in the office.

@asnowwolf
Copy link

asnowwolf commented Apr 10, 2019

I think we needn't provide a solution that works for "anywhere, any file". It only needs to support the most common situations and avoid introducing side effects.
For example, the <img src="./some-file.png"> (common) can be directly supported, while <img src="./some-{{files}}.png"> (not common) can prompt the user to change to <img [src]="file">, and provide a utility function loadAsset() (essentially require()) allows the user to call in the component. And also, for backward compatibility, only add the fingerprint to the relative path starting with ./, and the absolute path starting with / uses the original way, and even further: Use the original way for the files in the assets section of angular.json.

@MartinMa
Copy link

What would an alternative approach using ngx-build-plus look like? Has anyone tried this yet and is willing to share his/her knowledge?

@mgechev
Copy link
Member

mgechev commented Jul 25, 2019

After looking at this issue again today and discussing it for a while, we think that it's a good candidate for a third-party plugin that can be integrated in a CLI project using ngx-build-plus.

Our main concern is that a lot of the asset references in templates are dynamic. In a dataset of over 1,500 project we found that over 34% of the bindings to an src attribute of an image are dynamic. Unfortunately, dynamic bindings cannot be resolved at build time. Imagine the scenario:

@Component({
  template: '<img [src]="foo">'
})
class ImgComponent {
  foo: string = localStorage.get('image');
}

It is impossible at build time to know the value of the src attribute.

It's possible, however, to handle part of the use cases (the other 64% from our dataset). This is a great candidate for a third-party plugin that you can use with the CLI. If anyone is willing to contribute, feel free to share an insight in this issue.

If the plugin satisfies most of our users' needs for adding a hash in the name of static assets referenced in templates, we'll be happy to reconsider and introduce it as part of the CLI core.

@mgechev mgechev closed this as completed Jul 25, 2019
@mgechev mgechev removed the needs: discussion On the agenda for team meeting to determine next steps label Jul 25, 2019
@th0r
Copy link

th0r commented Jul 25, 2019

@mgechev but how do you propose to solve this issue?

@mgechev
Copy link
Member

mgechev commented Jul 25, 2019

Possible third-party solution is a webpack plugin which parses the component template, discovers all the statically referenced resources, calculates their hash and appends it to their names.

Alternatively, now, you can take advantage of the static nature of CSS and use classes with background images, instead of <img> elements.

Another solution would be to control your caching policy or introduce a service worker that takes care of that.

Few sample solutions on top of my head.

@angular-automatic-lock-bot
Copy link

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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature Issue that requests a new feature type: faq
Projects
None yet
Development

Successfully merging a pull request may close this issue.