Avoid *.js.erb files by building all the asset_pat

2019-03-12 09:17发布

问题:

So I want to avoid processing JavaScript files with ERB just so I can get a proper asset path to, say, an image.

Currently, this seems like the popular approach:

var myImage = "<%= asset_path('my_image') %>";

Which, of course, requires the filename be changed to "*.erb" so that it'll be processed.

I'd much rather isolate the ERB ugliness to one point in my project making a single manifest file (say, "assets.js.erb") that computes and makes available all the asset paths my JavaScript needs.

I can certainly do it WETly by tackling it case-by-case:

ASSETS =
  "my_image": "<%= asset_path('my_image') %>"

window.assetPath = (path) -> ASSETS[path]

But, I'd really rather just write some ERB to recurse through all of my asset_paths.asset_environment.paths and build a big object literal manifest for me, so that my real application JavaScript can confidently call:

var myImage = assetPath('my_image');

Any ideas on (1) if there's an easier way to do this that I missed, or (2) how I'd accomplish a search of all the potential valid arguments to asset_path?.

回答1:

An easier way :

  1. Get the assets prefix in your .js.erb : <%= Rails.configuration.assets.prefix %>. If an absolute path is needed, you can also get the application URL (it's more complicated to get it from rails, so you can just hardcode it in your .js.erb ?)

  2. If you are working with precompiled assets, get the fingerprint of your file which is stored in manifest.yml (at <%= Rails.configuration.assets.manifest %>). The manifest contains a list with all your assets and their respective fingerprints (documentation)

  3. Make assetPath just prepending the application URL + prefix to your image name or fingerprint

An inconvenient is that you have to specify the full image name (included the extension).



回答2:

It depends on the context of where this image is used.

Use Case 1: The image is decorative and needs to be dynamically swapped. Example: Spinner, while data is loading. In this case, I refer to is in my sass and java script.

.spinner
   background-image: url(image_path("spinner.png"))

Then I would operate with classes in java script and not images.

   $.addClass('spinner')

Use Case 2: Image is part of an object.

There are many situations, when an image actually belongs to a object. In this case, I create a json file, which stores the data and the image reference like this. Then I use erb to unwrap the image reference - my_object.json.erb:

 {
    "icon" : "<%=image_path("icons/my_icon.png")%>",
    "label":"My label",
    "description":"My description"
 }

Use case 2 requires more work on javascript side to load the json files, but it opens very powerful extensibility options.

Asset pipeline handles both cases famously.



回答3:

Old question, but there is nice way to accomplish this. Just to explain the context of my solution: I need to display markers in a map, which have different possible icons based on the JS dynamic variables. Strangely, using the <%= asset_path('" + somefunction(raw_value) + "') %> was not working. Then, I've looked for the solution bellow.

Concretely, the solution I am using has only one js.erb file which stores the values of the images, and their fingerprinted names, which can be get by a function, image_path. After that, all my other JS files can be free of the asset_path and, consequently, of the .erb

Create a file images.js.erb in your_application/app/assets/javascripts with the following content:

<%
    imgs = {}
    Dir.chdir("#{Rails.root}/app/assets/images/") do
        imgs = Dir["**"].inject({}) {|h,f| h.merge! f => image_path(f)}
    end
%>

window.image_path = function(name) {
    return <%= imgs.to_json %>[name];
};

Require this file in your application.js, which is normally in the same directory as above:

//= require ...
//= require ...
//= require images
//= require_tree .

Then, inside the JS that you've been using <%= asset_path('image.png') %>, you will use instead image_path('image.png');

Credits to this blog post for posting a Coffee script version from which I've based mine.