Skip to content
This repository has been archived by the owner on Jun 10, 2018. It is now read-only.

Disable .erb caching in development #563

Closed
rymohr opened this issue Apr 16, 2014 · 14 comments
Closed

Disable .erb caching in development #563

rymohr opened this issue Apr 16, 2014 · 14 comments

Comments

@rymohr
Copy link

rymohr commented Apr 16, 2014

This is a follow up to #486.

My original suggestion to add a nocache directive is too heavy-handed. Instead, I think simply not caching .erb assets in development is the proper way to go. Better yet, piggyback on config.cache_classes or config.action_view.cache_template_loading to decide if these assets are cached or not.

Caching them in development makes them practically useless as mentioned by @PikachuEXE and @dekart.

In production these assets should always be cached and served separately by the asset host. If you need these to be dynamic in production just use a standard AC view to generate the javascript dynamically as @josh mentioned.

@josh
Copy link
Contributor

josh commented Apr 16, 2014

I still have no intention of supporting this.

@dekart
Copy link

dekart commented Apr 17, 2014

@josh, is it a design-driven decision or would it help if we'll provide a pull request? I'm just curious why you're not intended to support it, is there any reason for this.

@timmfin
Copy link

timmfin commented Apr 17, 2014

I understand where @josh is coming from here. Sprockets is intended to handle static files (and eventually be pre-compiled, shipped to CDN, etc). While offering a way to make those static files seem dynamic would certainly be helpful in your use case, I'm not sure that is a good thing for Sprockets overall. It could very well lead to people accidentally relying on that dynamic behavior, and be surprised when they deploy out to prod and things behave differently.

Is there a way you can make this .erb file depend on the some/all of the other files that contribute to it? For example, in our custom internal I18n setup, we make some compiled JS files depend_on the language string files (that are just .yaml). So when those language string files are edited the JS files are automatically invalidated and ready to re-compile next request.

So, I'd recommend registering your own engine for your file so that you can run custom code that calls #depend_on_asset(...) where needed (and if you provide an absolute path, I believe you can depend on files that don't live inside the Sprocket paths).

@josh
Copy link
Contributor

josh commented Apr 17, 2014

config.cache_classes or config.action_view.cache_template_loading to decide if these assets are cached or not.

This still not an ideal work flow. The reason those Rails configs work is that Rails always rereads all the files everytime it boots. A more similar analogy would be compiling to byte then loading the app from the bytecode. Now you have to decide when you recompile. If every deploy you want to reread and reprocess every file, sprockets already works that way. You're builds will be really slow, but I guess you can make that trade off. The big performance win comes from reusing artifacts from previous deploys.

Sprockets is intended to handle static files (and eventually be pre-compiled, shipped to CDN, etc).

Yes.

You really want your build to be deterministic. If you can run you build, and every time produces different results, you're going to have a bad time. This probably includes anytime you might think to call into ActiveRecord in your assets.

It could very well lead to people accidentally relying on that dynamic behavior, and be surprised when they deploy out to prod and things behave differently.

I've been tempted for a while to pull support for .erb into a plugin. That would come with warning labels and whatever in the README. Also note that in the future, any .erb file will not work with sourcemaps.

@rymohr
Copy link
Author

rymohr commented Apr 17, 2014

In our case the only .erb asset is the one that generates the asset manifest so the client can dynamically load assets by logical path without hitting the rails stack. It generates a file similar to the new manifest.json, only it maps logical paths to their fingerprinted urls.

Here's an example from our latest deploy (only top-level modules are included):

var Manifest = {
  "loader/index.js":"//kumu.s3.amazonaws.com/production/public/assets/loader/index-a5d3c62d37840117202c3afb1560be42.js",
  "loader/index.css":"//kumu.s3.amazonaws.com/production/public/assets/loader/index-2993385f9828b0ac0ff24a9cb651e66a.css",
  "main/index.js":"//kumu.s3.amazonaws.com/production/public/assets/main/index-a688fb720e7eabdc29942be82fea0041.js",
  "main/index.css":"//kumu.s3.amazonaws.com/production/public/assets/main/index-34fd0cadc388dbc2f4cfd60afbc97ff6.css"
};

This gets consumed by a simple module loader that can then be called with:

Module.load("main").then(...)

I understand the desire for builds to be deterministic though, and caching is usually a good thing. I'll look into other ways to build the manifest outside of the asset pipeline.

@josh
Copy link
Contributor

josh commented Apr 17, 2014

@rymohr I do the exact same thing. depend_on_asset should work fine.

Heres a snippet from our ace requirejs loader

ace.config.modules =
<% for m in Assets.ace_modules %>
  <%=
    depend_on_asset "sprockets-#{m}.js"
    "\"#{m}\": \"\#{assetHostUrl}assets/#{environment["sprockets-#{m}.js"].digest_path}\""
  %>
<% end %>

@rymohr
Copy link
Author

rymohr commented Apr 17, 2014

Thanks @josh. I'll give that a try.

@dekart
Copy link

dekart commented Apr 18, 2014

@josh is that possible to do the same by depending on file outside of the assets folder? We're precompiling some of our data from RAILS_ROOT/db folder used by both client and server, as well as texts from RAILS_ROOT/config/locales.

@dekart
Copy link

dekart commented Apr 18, 2014

I think I've found a solution for my case. In the file that depends on some content outside of assets folder I'm adding this:

<%
  ([Rails.root.join('db/data').to_s] + Dir[Rails.root.join('db/data/**/*')]).sort.each do |f|
    depend_on(f)
  end
%>

It works just fine in 2.11.0, didn't check in later versions yet.

@josh
Copy link
Contributor

josh commented Apr 18, 2014

I think depend_on just requires the file to be in the rails root in 2.x.

On Apr 18, 2014, at 1:07 AM, Aleksey Dmitriev [email protected] wrote:

@josh is that possible to do the same by depending on file outside of the assets folder? We're precompiling some of our data from RAILS_ROOT/db folder used by both client and server, as well as texts from RAILS_ROOT/config/locales.


Reply to this email directly or view it on GitHub.

@josh josh closed this as completed Apr 23, 2014
@coli
Copy link

coli commented Apr 29, 2014

This is really needed for something like js_assets which dumps the list of assets in a js erb file

@jeremyhaile
Copy link

I successfully used depend_on_asset to solve this problem!

@zampino
Copy link

zampino commented Apr 30, 2015

great! @dekart thanks for the solution! I finally understood depent_on_asset vs depend_on

@hammady
Copy link

hammady commented Dec 6, 2016

This solved my problem, Thanks! I had a routes_json.js.erb that is never changed, but depends on the changing routes.rb (I want routes to be available in the static js client views).
This is how I did it:

# app/assets/javascripts/routes.js.erb
<% depend_on Rails.root.join('config').join('routes.rb') %>
routes_hash = <%= MyApp::Application.routes_json.html_safe %>

where routes_json computes a json representation of the routes.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants