How to override single files from gem assets for assets:precompile?

╄→гoц情女王★ 提交于 2019-12-04 17:26:45

问题


Situation

I use a gem that brings its own JavaScript and stylesheet assets. This gem uses a standard application.js and application.css manifest to require all its assets:

[gem]/app/assets/javascripts/gem_name/application.js
  require_tree .

[gem]/app/assets/javascripts/gem_name/backoffice/menu.js
  … some JavaScript code …

[gem]/app/assets/javascripts/gem_name/backoffice/forms.js
  … some JavaScript code …

In development mode I can then override single asset files by placing them in [my_app]/app/assets folder, e.g.:

[my_app]/app/assets/javascripts/gem_name/backoffice/menu.js

The load paths configured in Rails then ensure that files in [my_app]/app/assets override files in [gem]/app/assets.

But when I precompile the assets using rake assets:precompile, the overriding file menu.js doesn't replace the original file from the gem. The compiled application.js contains the code from the original menu.js.

Demo

See the behavior in action with this test app: https://github.com/widescape/AssetCompileTest

Considerations

So far, I found out that require_tree looks up files only in the directory of the current file and does not look across multiple load paths (e.g. app/assets or vendor/assets). So if the current file is [gem]/app/assets/javascripts/gem_name/application.js, Sprockets#require_tree will only look in [gem]/app/assets/javascripts/gem_name/ for more files and will not use the other load paths like [my_app]/app/assets/….

I am reluctant to copy all asset files from the gem into my app/assets only to override one single file. And forking the gem to customize a single file doesn't have a great appeal, too.

Is there any other way?

Note: I am aware that I could create a custom JavaScript file menu_patched.js that overrides the objects and methods defined in the original file and place it so that its definitions will be applied before the original objects and methods are called (monkey patching JavaScript style). But I am looking for a cleaner solution here.


回答1:


In the demo code you posted at on GitHub, your application.js has:

//= require any_gem

That does not bring in a directory, it brings in any_gem.js, which is the Gem's manifest file that brings in all of the Gem's JS files. If you do not want all of the files, then you need to change that to bring in only the files you want by listing them explicitly:

//= require ../../../vendor/assets/javascripts/any_gem/do_not_override.js

Then you can add back in all of your own JS files, including your overrides, with:

//= require_tree .

BTW, great job on creating the demo app! You're a role model for the kids.




回答2:


In application.rb or production.rb, you can prepend or append more assets path.

config.assets.prepend_path 'vendor/assets/jquery'
config.assets.append_path 'vendor/assets/something'

References:

  • sprockets/railtie source code
  • Sprockets: Manipulating the Load Path


来源:https://stackoverflow.com/questions/16435428/how-to-override-single-files-from-gem-assets-for-assetsprecompile

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!