【问题标题】:How to override single files from gem assets for assets:precompile?如何从 gem 资产中覆盖单个文件以获取资产:预编译?
【发布时间】:2013-05-02 08:58:11
【问题描述】:

情况

我使用带有自己的 JavaScript 和样式表资产的 gem。此 gem 使用标准的 application.js 和 application.css 清单来要求其所有资产:

[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 …

在开发模式下,我可以通过将单个资产文件放在 [my_app]/app/assets 文件夹中来覆盖它们,例如:

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

然后在 Rails 中配置的加载路径确保 [my_app]/app/assets 中的文件覆盖 [gem]/app/assets 中的文件。

但是当我使用 rake assets:precompile 预编译资产时,覆盖文件 menu.js 不会替换 gem 中的原始文件。编译后的application.js 包含来自原始menu.js 的代码。

演示

查看此测试应用的实际行为:https://github.com/widescape/AssetCompileTest

注意事项

到目前为止,我发现require_tree在当前文件的目录中查找文件,查找多个加载路径(例如app/资产或供应商/资产)。因此,如果当前文件是 [gem]/app/assets/javascripts/gem_name/application.jsSprockets#require_tree 只会在 [gem]/app/assets/javascripts/gem_name/ 中查找更多文件,并且不会使用其他加载路径,例如 [my_app]/app/assets/…

我不愿意将所有资产文件从 gem 复制到我的应用程序/资产中,只是为了覆盖一个文件。并且 fork gem 来自定义单个文件也没有太大的吸引力。

还有其他方法吗?

注意:我知道我可以创建一个自定义 JavaScript 文件 menu_patched.js,它会覆盖原始文件中定义的对象和方法并将其放置,以便在原始文件之前应用其定义对象和方法被调用(猴子修补 JavaScript 风格)。但我在这里寻找更清洁的解决方案。

【问题讨论】:

    标签: ruby-on-rails gem assets sprockets


    【解决方案1】:

    在您在on GitHub 发布的演示代码中,您的 application.js 具有:

    //= require any_gem
    

    这并没有引入目录,它引入了any_gem.js,这是Gem 的清单文件,它引入了所有 Gem 的JS 文件。如果您不想要所有文件,那么您需要通过明确列出它们来更改它以仅引入您想要的文件:

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

    然后您可以添加回您自己的所有 JS 文件,包括您的覆盖,使用:

    //= require_tree .
    

    顺便说一句,在创建演示应用方面做得很好!你是孩子们的榜样。

    【讨论】:

    • 你是对的,require_tree ./any_gem 将引入[my_app]/app/assets/any_gem/* 的目录内容。但是,require_tree 将包含 gem 中包含的所有其他 JavaScript 文件。它只会包含与包含文件相关的文件。不幸的是,那是how require_tree works。 Sprocket 不会在 require_tree 文件列表中查找每个文件的加载路径。
    • 我担心,我正在寻找的答案可能不是(更改的)代码行,而是不同的编码模式......
    • 是的,宝石应该提供他们自己的方式来让你不碍事并允许你覆盖行为; Sprockets 没有给你一个很好的覆盖机制。尽管如此,为了排除您不想要的文件,一个接一个地要求 Gem 的 JS 文件(放弃 Gem 提供的 any_gem.js 的便利性)会更易于维护和更好。例如。 //= require ../../../vendor/assets/javascripts/any_gem/other
    • 好的,按照您的方法,我创建了分支solution-with-individual-inclusions,其中还包括验证该解决方案在开发和生产环境中是否有效。 See the changes for details.
    • 您想更改答案以反映此解决方案吗?那么我很乐意接受你的回答并用赏金奖励你。 :)
    【解决方案2】:

    application.rbproduction.rb 中,您可以预先或附加更多资产路径。

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

    参考资料:

    【讨论】:

    • 问题是不是 gem 资产可能没有被加载。问题是,应用程序/资产不会覆盖已编译静态资产中的 gem/assets。请参阅示例应用程序 github.com/widescape/AssetCompileTest 以查看实际行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多