Code Monkey home page Code Monkey logo

Comments (37)

RuslanZavacky avatar RuslanZavacky commented on July 17, 2024 5

@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".

from broccoli-asset-rev.

rickharrison avatar rickharrison commented on July 17, 2024 1

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.

from broccoli-asset-rev.

mksplg avatar mksplg commented on July 17, 2024 1

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.

from broccoli-asset-rev.

Fryie avatar Fryie commented on July 17, 2024 1

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).

from broccoli-asset-rev.

carrotalan avatar carrotalan commented on July 17, 2024 1

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!)

from broccoli-asset-rev.

rickharrison avatar rickharrison commented on July 17, 2024

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?

from broccoli-asset-rev.

zetas avatar zetas commented on July 17, 2024

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.

from broccoli-asset-rev.

EmergentBehavior avatar EmergentBehavior commented on July 17, 2024

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.

from broccoli-asset-rev.

EmergentBehavior avatar EmergentBehavior commented on July 17, 2024

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.

from broccoli-asset-rev.

rickharrison avatar rickharrison commented on July 17, 2024

Have you tried reading the assetMap as I described above? I think that may solve your problem.

from broccoli-asset-rev.

EmergentBehavior avatar EmergentBehavior commented on July 17, 2024

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).

from broccoli-asset-rev.

rickharrison avatar rickharrison commented on July 17, 2024

Try passing generateAssetMap: true in as one of the options.

from broccoli-asset-rev.

EmergentBehavior avatar EmergentBehavior commented on July 17, 2024

Will give it a go. If it works I'll report back to the ember-cli folks :)

from broccoli-asset-rev.

EmergentBehavior avatar EmergentBehavior commented on July 17, 2024

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}}.

from broccoli-asset-rev.

rickharrison avatar rickharrison commented on July 17, 2024

Could you bind the attribute to a variable, which you can then create in your controller that reads in the asset map?

from broccoli-asset-rev.

EmergentBehavior avatar EmergentBehavior commented on July 17, 2024

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.

from broccoli-asset-rev.

EmergentBehavior avatar EmergentBehavior commented on July 17, 2024

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.

from broccoli-asset-rev.

rickharrison avatar rickharrison commented on July 17, 2024

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

from broccoli-asset-rev.

EmergentBehavior avatar EmergentBehavior commented on July 17, 2024

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}} />

from broccoli-asset-rev.

rickharrison avatar rickharrison commented on July 17, 2024

@rwjblue Do you have any ideas on the best approach to solve this problem?

from broccoli-asset-rev.

chnn avatar chnn commented on July 17, 2024

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.

from broccoli-asset-rev.

rickharrison avatar rickharrison commented on July 17, 2024

I'm going to close this for now. If you still are having trouble with this, please let me know.

from broccoli-asset-rev.

marlonmantilla avatar marlonmantilla commented on July 17, 2024

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 ?

from broccoli-asset-rev.

rickharrison avatar rickharrison commented on July 17, 2024

Use generateAssetMap as shown in the readme https://github.com/rickharrison/broccoli-asset-rev

from broccoli-asset-rev.

ehubbell avatar ehubbell commented on July 17, 2024

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.

from broccoli-asset-rev.

kgish avatar kgish commented on July 17, 2024

@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'}}

from broccoli-asset-rev.

wehlutyk avatar wehlutyk commented on July 17, 2024

@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.

from broccoli-asset-rev.

kgish avatar kgish commented on July 17, 2024

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);

from broccoli-asset-rev.

Fryie avatar Fryie commented on July 17, 2024

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}`;
}

from broccoli-asset-rev.

RuslanZavacky avatar RuslanZavacky commented on July 17, 2024

@Fryie so you don't use fingerprinting? But just pre-pending URL? How you deal with client side assets caching?

from broccoli-asset-rev.

Fryie avatar Fryie commented on July 17, 2024

I do, I just excluded it from this example because it depends on a
"isProductionLikeBuild" variable. edit: updated example

from broccoli-asset-rev.

Fryie avatar Fryie commented on July 17, 2024

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.

from broccoli-asset-rev.

Fryie avatar Fryie commented on July 17, 2024

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

from broccoli-asset-rev.

seawatts avatar seawatts commented on July 17, 2024

@wehlutyk I am doing the same thing with ember-cli-deploy. Did you find a solution?

from broccoli-asset-rev.

wehlutyk avatar wehlutyk commented on July 17, 2024

@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.)

from broccoli-asset-rev.

devinrhode2 avatar devinrhode2 commented on July 17, 2024

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.

from broccoli-asset-rev.

RuslanZavacky avatar RuslanZavacky commented on July 17, 2024

@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 :)

from broccoli-asset-rev.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.