Closed zetas closed 9 years ago
Can you clarify your use case some more. You have an image name stored in the database, but the asset is stored in your application code?
The logo property stores a relative asset URL like "/assets/images/bar-23.jpg" and that actual file is in my public/assets/images folder of my ember-cli app, which gets output to the dist folder with the fingerprints added.
If there's a better way to achieve what I'm trying to do (allowing users to modify the bars logo) I'm all ears. I'm still early on in the development process.
Thanks.
I'm not sure if this will work in an ember app, but here is what I do with handlebars on my server side app. I have a helper like this:
var handlebars = require('handlebars');
var assetMap = require('../../dist/assets/assetMap.json');
var prepend = assetMap.prepend || '/';
handlebars.registerHelper('asset', function (asset) {
return prepend + assetMap.assets[asset];
});
And then in a handlebars template, I can access the asset via:
<link rel="stylesheet" href="{{asset 'path/to/filename.css'}}">
Perhaps you can use the assetMap.json
in some way to look up the filename at runtime.
I'm also building an ember project and am running into a similar issue. In a handlebars template, I bind the src attribute of an image to some string which I calculate in one of my Ember controllers. However, when I have fingerprinting/prepending enabled, these paths are not updated and the images are subsequently broken.
I may be able to get around this by defining the CDN path in an environmental variable, but it would be nice if we could do fingerprinting too.
Have you tried reading the assetMap as I described above? I think that may solve your problem.
Unless I'm missing something, an asset map isn't produced in ember-cli (or at least it doesn't appear in dist/assets after build).
Try passing generateAssetMap: true
in as one of the options.
Will give it a go. If it works I'll report back to the ember-cli folks :)
Adding generateAssetMap: true in the proper place in my Brocfile did produce the asset map. However, in ember-cli I don't think I can we can use helpers the way you use them. We'd have to use {{bind-attr href=something}}
.
Could you bind the attribute to a variable, which you can then create in your controller that reads in the asset map?
That could work. I'll try creating a Mixin in Ember that incorporates your idea so we can update dynamic paths created inside controllers, etc.
I can't seem to be able to access/import/require the assetMap in a controller, perhaps it's not created yet? Can ping the ember-cli folks too to see if they have ideas.
Can you post an example of what you are trying to accomplish? How you generate the URLs and how you use it in a template
So in my project I'm working on generating paths for movie posters. So, for example, I may have something like this in a controller:
posterURL: function() {
var prefix = config.environment === 'staging' ? config.cdnPath : '';
return prefix + 'img/posters/' + this.get('id') + '.jpeg';
}.property('id'),
I pull a CDN prefix from my environmental settings, but this doesn't do anything regarding hashes. Then I basically use the id of the movie from my current model and build the path from that.
Then, in my corresponding template, I have something like this:
<img {{bind-attr src=posterURL}} />
@rwjblue Do you have any ideas on the best approach to solve this problem?
This is a bit of a workaround, but you could use the customHash
option instead of the default md5 hashes for the fingerprint. Then, because you know what to expect for the custom hash, you can build that assumption into your computed property:
return prefix + 'img/posters/' + this.get('id') + '-' + myCustomHash + '.jpeg';
For a custom hash, I use the current git commit SHA. It's predictable (you can look it up), and will change every time you deploy so the cache still gets broken.
I'm going to close this for now. If you still are having trouble with this, please let me know.
I stumbled over the same problem. The workaround I've used now is async loading the assetMap.json and injecting a dependency in an initializer. It provides an assets.resolve(localPath)
function.
import Ember from 'ember';
export function initialize(container, application) {
application.deferReadiness();
var AssetMap = Ember.Object.extend();
var promise = new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.getJSON('assets/assetMap.json', resolve).fail(reject);
});
promise.then(function(assetMap) {
AssetMap.reopen({
assetMap: assetMap,
resolve: function(name) {
return assetMap.assets[name];
}
});
}, function() {
AssetMap.reopen({
resolve: function(name) {
return name;
}
});
}).then(function() {
container.register('assetMap:main', AssetMap, {singleton: true});
application.inject('component', 'assets', 'assetMap:main');
application.advanceReadiness();
});
}
export default {
name: 'asset-map',
initialize: initialize
};
This can then be used with this.assets.resolve('img/posters/' + this.get('id') + '.jpeg')
. Hope this helps someone else.
Hi everyone, I'm new to Ember here ... Can't see assetMap.json file on my project neither in my dist folder. Any ideas of how to achieve this in ember-cli ?
Use generateAssetMap
as shown in the readme https://github.com/rickharrison/broccoli-asset-rev
We're running into a similar issue. For our application, we're generating dynamic images from a helper and then injecting the correct one into a couple templates.
The use-case is pretty simple. We're checking the type of credit card a user has on file with us, then we're generating a path to the correct image asset (in our public folder) to display next to the card at checkout and in a user's settings.
Due to fingerprinting, our app is unable to find the asset path since we're generating the path outside our templates and stylesheets.We have a workaround for now however it'd be nice if we could fingerprint images from files outside our templates & stylesheets.
@mksplg +1
How would I register a HTMLBars helper which would do the same for me but in the templates?
{{asset-resolve 'name-of-asset'}}
@mksplg did you find a way to get the assetMap at compile-time?
My use-case is with ember-cli-deploy, which sends all the assets to (e.g.) S3, and only index.html
to your server, so there's no simple access to assetMap.json
(deployment will send it fingerprinted to S3). I stumbled upon ember-cli-inject-asset-map but there might be some cleanup to do there.
This is my helper asset-resolve
import Ember from 'ember';
export function assetResolve(asset) {
var fn = Ember.container.lookup('assetMap:main');
var res = asset;
if (fn) {
var a = fn(asset);
if (a) { res = a; }
}
return res;
}
export default Ember.Helper.helper(assetResolve);
I have chosen a slightly different solution. I have a config/cdn.json
file, and then I just read it in two places. I also use this package to read the current commit SHA and use it as a fingerprint:
// ember-cli-build.js
var cdnConfig = JSON.parse(require('fs').readFileSync('config/cdn.json'));
var cdnPath = cdnConfig[process.env.EMBER_ENV];
var isProductionLikeBuild = ... // check if production or staging or something
var app = new EmberApp(defaults, {
fingerprint: {
prepend: cdnPath,
enable: isProductionLikeBuild,
customHash: require('git-rev-sync').long()
})
// config/environment.js
var cdnConfig = JSON.parse(require('fs').readFileSync('config/cdn.json'));
ENV.APP.CDN_PATH = cdnConfig[process.env.EMBER_ENV];
ENV.APP.FINGERPRINT = require('git-rev-sync').long();
Yes, that duplicates the part of reading the file, but the stuff that is actually more likely to change, the paths themselves, are stored in one location.
With this, I can build a simple util:
import ENV from 'my-app/config/environment';
export function assetPath(asset, extension) {
return `${ENV.APP.CDN_PATH}assets/${asset}-${ENV.APP.FINGERPRINT}.${extension}`;
}
@Fryie so you don't use fingerprinting? But just pre-pending URL? How you deal with client side assets caching?
I do, I just excluded it from this example because it depends on a "isProductionLikeBuild" variable. edit: updated example
Oh I see what you mean now. Yeah, with fingerprinting you'd also need the specific asset fingerprint, so that solution won't work. I totally missed that.
you could specify a custom fingerprint hash: http://www.ember-cli.com/user-guide/#asset-compilation that could be the git commit, for example edit: updated my example above with that
@wehlutyk I am doing the same thing with ember-cli-deploy. Did you find a solution?
@seawatts unfortunately nothing implemented yet. I think the way to go is what's explained as option 2 in this comment, but I haven't had the time to implement it. My next free slot to do it is in a month or two (but I won't make any promises -- if you know how to do it feel free :) ).
(In the meantime, since I only have 4 dynamic url assets, whenever they change I build once, then copy those particular fingerprints by hand from assetMap.json
into my app code, then build again.)
There is some discussion over here. Unfortunately, it is not at all easy to come up with a working solution. In fact, we had to go through several iterations to have a real bug-free solution.
you'll want the
fingerprint: {
...
generateAssetMap: true,
fingerprintAssetMap: true
},
option, so your asset map is generated (and uploaded), and so it's fingerprinted as well (otherwise a client might retrieve an outdated asset map from the cache!).
Then, in your code you can retrieve the asset map via assets/assetMap.json
. Ember CLI will automatically replace this string with the correct URL to the fingerprinted asset map in the production build. Then follow a similar procedure as outlined here (ignore the ENV.APP.CDN_PATH part, this turned out not to work exactly because the asset map is cached by the cliented; instead just use the assets/assetMap.json
string and let Ember CLI replace it with the correct URL).
Also encountered this issue. I have image names coded directly into a plain javascript file that provides some data for the ui (app/ui-data.js), but I dynamically create the full paths for each url in my ui-data object. Just hard coding the full asset paths, and removing my code dynamically creates them, fixes the issue for me.
The full path makes broccoli-asset-rev recognize them and rewrites them, apparently in any source file anywhere in the ember app.
@devinrhode2 I wrote an article about fingerprinting - https://medium.com/@ruslanzavacky/ember-cli-fingerprinting-and-dynamic-assets-797a298d8dc6 and also created a relevant addon that helps to solve fingerprinting issues - https://github.com/RuslanZavacky/ember-cli-ifa. Its still not ideal, but at least its doing it from the "box".
Sounds like there is no real resolution to this still.
Dynamic URLs are a huge part of large, production systems. We can implement the workarounds, but I would suggest this must be on a high priority of fixes for your next release (please!)
@carrotalan you can easily use an addon that I've provided. Works well and for large production systems :) And if it does not satisfy you, author of this repo will likely be happy to get contributions that will solve the issue that you've described :)
Hi, I'm having some trouble with broccoli-asset-rev in ember-cli.
My use-case is loading a logo from the database like so:
The issue is the fingerprint for that image is not appended at runtime and so in production, none of these assets work. It's looking for /assets/images/bar023.jpg but the actual file is now /assets/images/bar023-ad232dd232d23423.jpg
Of course I can disable fingerprinting, and that's what I've done in the meantime but I really would like to be able to use it, just somehow append the fingerprint in the template or maybe as a property on the controller?
Thanks, David