【问题标题】:Dependency included in gemspec not added to asset pipeline in rails enginegemspec 中包含的依赖项未添加到 rails 引擎中的资产管道
【发布时间】:2012-08-28 16:31:32
【问题描述】:

我正在编写一个具有一些依赖关系的 Rails 引擎。我已经在 gemspec 中指定了依赖项,并且当我运行 bundle install 时引擎正在找到它们(即 Gemfile.lock 看起来正确)。当我想在 Ruby 文件中使用插件时,我可以这样做,但需要在文件顶部显式地require dependency-name

但是,当我想使用依赖项的资产管道时,sprockets 却找不到它。

我(目前)正在使用的应用程序是位于 rails 插件的测试文件夹中的虚拟应用程序。如果我在引擎的 Gemfile(实际上是虚拟应用程序的 Gemfile)中指定 Sprockets 可以找到资产,但如果我在 gemspec 中指定它们则不能。我不想依赖 Gemfile,因为这意味着任何使用我的插件的应用程序都需要手动将我的所有依赖项添加到他们的 Gemfile 中。出于同样的原因,我不想要涉及更新应用配置文件的解决方案。

当 gemspec 包含依赖项时,这有效(在 ruby​​ 文件中):

require 'dependency-name'

但是当 gemspec 中包含依赖项时,这(在 JS 文件中)不起作用:

//= require 'dependency-name'

当 Gemfile 包含依赖项时,不需要 require。我认为这很清楚,但如果您需要更多细节,请告诉我。

【问题讨论】:

    标签: rubygems ruby-on-rails-3.1 asset-pipeline ruby-on-rails-plugins


    【解决方案1】:

    我需要在我的 engine.rb 中明确包含依赖项,以便它的资产最终进入我的资产管道。不知道为什么这是必要的,因为 Alastor 的回答对我来说听起来是正确的。值得注意的是,依赖项是我使用 bundler 创建的 gem,尽管我不明白为什么会有所作为。

    module MyRailsPluginFull
      class Engine < ::Rails::Engine
        require 'dependency1'
        require 'dependency2'
      end
    end
    

    于 2012 年 11 月 23 日添加

    我花了更多时间使用引擎,我想我现在更充分地理解了这一点。 Gemspec 只是所需依赖项的列表,但 gemspec 不会指示应用程序在启动时从这些依赖项中加载文件。另一方面,Gemfiles 会在启动期间加载所有文件。

    于 2015 年 3 月 20 日添加

    我在 2 年前所说的“Gemfiles,另一方面,在启动期间会加载所有文件”并不完全正确。这在 Rails 中几乎是正确的,默认情况下运行 Bundler.require 以要求 Gemfile 中列出的所有依赖项,如生成器文件 here 所示 - 请注意,虽然 Rails 的默认行为已从 Rails3 更改为 Rails 4,但正如所讨论的 @ 987654322@,两者都使用Bundler.require。但是,有充分的理由使用Bundler.setup,然后在实际上依赖depedency1 的任何文件中使用显式require "dependency1"。 参见this discussionBundler.requireBundler.setup

    此外,正如@nruth 在 cmets 中指出的那样,这可能会导致加载不必要的类。但是,如果依赖项设计得很好,它的类将主要是自动加载的,从而为需要整个依赖项创建最小的开销。或者,如果它在一个单独需要的文件中定义了它的引擎,你可以只包含引擎文件,它应该将必要的文件添加到你的资产路径中,允许你在 CSS 和 JS 清单中要求它的资产。请参阅this bootstrap-sass example,其中 gem 将其所有资产添加到 config.assets.paths 并将其中一些资产添加到 config.assets.precompile

    虽然这个问题已经有几年了,我什至不记得我当时写的是什么 Rails Engine,但我怀疑正确的方法应该更接近这个:

    module MyRailsPluginFull
      class Engine < ::Rails::Engine
        initializer 'bootstrap-sass.assets.precompile' do |app|
          require 'dependency1'
    
          # add dependency1's assets to the list of paths
          app.config.assets.paths << ...
        end
      end
    end
    

    但请注意,这不是必需的——依赖项本身应该已经定义了这个初始化器,这样简单地要求它就足够了,就像上面的引导示例一样。

    【讨论】:

    • 非常感谢,这对我帮助很大!
    • 这似乎工作(很好),但如果您正在预编译资产,这是否意味着在生产中加载不必要的东西?
    • 如果您要将代码打包为 gem,您不知道您的最终客户是否想要使用 Bundler.setupBundler.require 并且您不想强制他们到任何一个。因此,您需要明确地require 任何需要的依赖项。这就是为什么@CarlosDiógenes 的评论中链接的示例会这样做。同时,这意味着更长的加载时间和可能不必要的类加载,除非您需要的依赖项使用autoload
    【解决方案2】:

    您根据http://edgeguides.rubyonrails.org/engines.html 设计引擎?如果您的引擎类继承自 Rails::Engine,它确实应该自己找到所有资产。

    【讨论】:

    • 评论 Isaac 自己的回答:在 gemspec 中但在引擎自己的 Gemfile 中未指定依赖项时,您是否注意到行为上的差异?
    • 是的,我注意到rake tasks are only inherited when you specify in the Gemfile。您可能是对的,这是另一个区别,尽管我现在有点忙,无法验证。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多