【问题标题】:Remove development gems from production with Bundler and Rails 4使用 Bundler 和 Rails 4 从生产中删除开发 gem
【发布时间】:2017-02-06 22:44:18
【问题描述】:

问题

我们部署的应用程序中包含开发依赖项。我们有很多开发依赖项。这会增加工件大小和生产中的内存消耗,因为所有这些依赖项都是require'd。大多数实例都部署在云中,因此更多的内存 = 更大的实例需要更多的钱。我们希望减少大小/内存,并在部署的工件和开发环境之间进行更清晰的分离。一个特别的重点是在生产环境中需要therubyrhino,即使我们的资产是预编译的。

上下文

This question 有一些投票率极高的 cmets 提出了同样的问题(请参阅 this one 和 this one),但我实际上没有看到任何答案。

查看Rails upgrade guide,建议如下:

同样,资产预编译是使用以下命令完成的:
RAILS_ENV=production rake assets:precompile

正如链接问题中所讨论的,这意味着生产中需要所有 gem。从根本上说,这对我来说没有意义,我觉得我错过了一些明显的东西。资产预编译的全部意义在于我们避免在生产中这样做,所以这个命令(据我所知)应该是这样的:
RAILS_ENV=development RAILS_ENV_TARGET=production rake assets:precompile
或者一些生意。

我已经阅读了关于旧 Rails 票 here 的讨论,似乎没有回答这个问题 - 我们如何从生产环境中获取开发依赖项?一位用户特别总结了同样的问题here

我仍然感到震惊的是,生产中的 ruby​​racer 等默认情况下的内存膨胀很差,特别是如果预编译是核心的建议并且在这一点上被广泛接受的最佳实践。许多人可能永远不会停止考虑,即使他们在资产组被删除后来到 Rails,或者从未考虑过它是否能达到这一目的——至少在生成的 Gemfile 中提供建议性评论可能是个好主意。

现在,对于开发人员来说,由于从预编译任务中删除了加载组,因此对于他们知道在生产 Web 或工作进程中不需要的 gem,现在可以解决这个问题。我现在基本上将其作为样板包含在新应用程序中: namespace :assets do # Override sprockets-rails task to put back assets group require, so as to # avoid memory bloat in web processes :-/ task :environment do Bundler.require(:assets) Rake::Task['environment'].invoke end end
加上将Bundler.require(*Rails.groups(assets: %w[development test])) 恢复为config/application.rb。真是一团糟。

仅供参考,du 在我的机器上报告 ruby​​racer 为 17MB,并且它不使用自动加载。我们没有使用任何 CoffeeScript 视图模板。

该评论的作者提出了一种解决方法,但稍后在线程中讨论了该策略的缺陷,这让我感到紧张。

tl;博士:

我们如何从生产运行时移除开发依赖项?或者,我错过了什么,为什么这种能力是可取的/默认的?

【问题讨论】:

    标签: ruby-on-rails-4 asset-pipeline bundler precompile dev-to-production


    【解决方案1】:

    我们如何从生产运行时移除开发依赖项?

    您引用的线程中的This comment 有启用旧:assets 组行为的说明:

    将config/application.rb 中的Bundler.require(*Rails.groups) 更改为Bundler.require(*Rails.groups(assets: %w[development test])),并将其添加到您的rake 任务中:

    namespace :assets do
      # Override sprockets-rails task to put back assets group require, so as to
      # avoid memory bloat in web processes :-/
      task :environment do
        Bundler.require(:assets)
        Rake::Task['environment'].invoke
      end
    end
    

    或者,我错过了什么,为什么这种能力是可取的/默认的?

    所以,严格来说,这些不是开发依赖项。你真的不应该那样想它们,因为资产预编译应该发生在生产环境中,即使它只是在部署期间。您绝对不应该在您的开发人员机器上进行预编译。

    最重要的是,自资产管道的早期版本以来,特定于资产的 gem 和生产 gem 之间的界限变得更加模糊。例如,现在许多 gem 都希望有一个可用的 javascript 解释器。此外,许多 Rails 应用程序现在在视图中使用 .coffee 模板(而不是 .js.erb),并且由于这些无法预编译,coffeescript 必须在生产中可用。

    基本上,随着 rails 贡献者开始从:assets 组中删除越来越多的 gem,他们意识到它不再需要存在,如果它消失了,事情就会变得简单。它最初只是为了避免意外的按需编译而存在,但在 Rails 4 中更新了资产管道,以期望默认情况下只提供静态资产。

    最终,它可能不是最优化内存的决定(因为您require正在使用一堆您从未使用过的宝石)但它是最普遍兼容的。

    编辑:另请参阅 this question 了解更多讨论/此问题的答案。

    【讨论】:

    • Rails 环境设置为“生产”的预编译与实际生产环境有什么区别?我们在 CI 服务器上预编译我们的资产,然后将它们与应用程序的其余部分捆绑在一起,并将其放到生产环境中。如果您能够在开发环境中为生产进行预编译,为什么不呢?看看这对“仅 API”Rails 的支持有何影响会很有趣,这将是 Rails 开发依赖的更多原因。
    • 另外,感谢您的详尽回答!有趣的是,这在某种程度上是一个有意的决定。我仍然觉得很奇怪,Rails 并没有捆绑 PostgreSQL,只是因为很多人使用它——它是单独安装在主机上的。为什么 JS 解释器不同?或者不是,它只是一个足够常见的用例,以这种方式看起来更容易?我很难想到除了 JS 解释器之外的其他任何东西,这对于部署资产完全预编译的应用程序是有意义的——还有什么其他例子可以说明当前的设计决策?
    • 我认为这并不能真正彻底解决问题。它会使 gem 超出内存,但它们仍然必须存在于生产机器上,因为像 rake db:migrate 这样的东西也会命中 environment 任务,不是吗?听起来真正分离开发和生产环境的最可行方法是避免Bundler.require...
    • 在部署方面,您的 CI 服务器是生产环境的一部分。您希望能够像测试应用程序本身一样测试部署问题。因此,将“生产”与“暂存”进行比较可能更有意义——您的暂存环境应该允许您在模拟实际生产部署的环境中捕获和重现预编译问题。
    • 这也是为什么我不认为这些依赖项是“开发”的原因,以及为什么在本地机器上预编译不是一个好主意。因为在一个 10 人的团队中,如果某人的资产预编译不正确而他们没有意识到,那么您将如何在他们破坏您的生产部署之前检测到它?即使你检测到它,你如何在不借用他们的笔记本电脑的情况下重现和调试它?
    猜你喜欢
    • 2013-05-15
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 2013-11-09
    • 2011-05-25
    • 2013-03-24
    • 2023-03-31
    • 2012-03-17
    相关资源
    最近更新 更多