在Rails生产环境中,为什么不使用config.assets.compile=true?

204
< p > rails new 安装的默认 Rails 应用程序在生产环境中使用 config.assets.compile = false

而通常的做法是在部署应用程序之前运行 rake assets:precompile,以确保所有资产管道资产都已编译。

那么,如果我在生产环境中设置了 config.assets.compile = true 会发生什么?

我将不再需要运行 precompile。我认为的情况是,第一次请求资产时,它将被编译。这将是一个性能损失,首次访问时会很慢(这意味着通常需要在生产中运行 js 运行时来完成此操作)。除了这些缺点之外,在资产被懒惰地编译后,我认为所有后续对该资产的访问都不会有任何性能损失,应用程序的性能将与预编译资产相同。这是真的吗?

我是否遗漏了什么?在生产环境中不设置 config.assets.compile = true 的其他原因吗?如果我在生产中拥有 JS 运行时,并愿意在第一次访问资产时进行性能降级的交换,以换取不必运行 precompile,这有意义吗?


1
警告:旧版本的Sprockets存在漏洞,如果将config.assets.compile配置为true,则存在目录遍历漏洞的风险(https://blog.heroku.com/rails-asset-pipeline-vulnerability)。 - Mauro
3
这正是Stackoverflow应该运作的方式。一个写得好的问题和一个写得好的答案。我爱你们两个,楼主和@richard-hulse。 - schmijos
7个回答

284

我写的是这篇指南的一部分。

在生产环境中,绝对不要实时编译代码。

当你开启编译模式时,以下情况会发生:

所有请求 /assets 文件夹下文件的请求都会被传递到 Sprockets。对于每个资源的首次请求,它会被编译并缓存在 Rails 使用的缓存(通常是文件系统)中。

在随后的请求中,Sprockets 接收请求,查找指纹文件名,检查组成该资源的文件(图片或css和js)是否已被修改,如果有缓存版本则提供服务。

这是 assets 文件夹中的所有内容和插件使用的任何 vendor/assets 文件夹中的内容。

这会带来很多开销,因为实际上该代码并没有针对速度进行优化。

它会影响资产传输到客户端的速度,并且会对您的网站页面加载时间产生负面影响。

与默认设置相比:

当资产预编译且编译关闭时,资产会被编译并生成指纹到 public/assets 目录。Sprockets 返回一个映射表,将普通文件名映射到指纹文件名,然后写入文件系统。清单文件(在 Rails 3 中为 YML,在 Rails 4 中为具有随机名称的 JSON)由 Rails 在启动时加载到内存中,并缓存以供资产帮助程序使用。

这使得页面的生成与正确的指纹资源非常快速,而文件本身的服务则以 web 服务器从文件系统快速提供。两者都比实时编译要快得多。

为了最大限度地利用管道和指纹,您需要在 Web 服务器上设置远期头,并为 js 和 css 文件启用 gzip 压缩。Sprockets 写出了资产的 gzip 版本,您可以将其设置为服务器使用,从而无需为每个请求执行此操作。

这最大程度地加快了资产传输到客户端的速度,并使页面显示尽可能快,减少了(通过远期标头)请求。

如果您是实时编译,则:

  1. 非常缓慢
  2. 缺乏压缩
  3. 将影响页面的渲染时间

相对而言:

  1. 尽可能快地进行
  2. 压缩的
  3. 从服务器移除压缩开销(可选)。
  4. 最小化页面的渲染时间。

编辑:(回答跟进评论)

管道可以在第一次请求时更改为预编译,但是有一些主要障碍需要克服。首先,必须有一个带指纹名称的查找表,否则辅助方法将太慢。在按需编译的情况下,每个新资产编译或请求时都需要有一种方法来附加到查找表。

此外,有人必须承担缓慢资产交付的代价,直到所有资产都编译并就绪。

默认情况下,在一次脱机编译所有内容的情况下,不会影响公共访问者,并确保在上线之前一切正常。

不能接受的是这会给生产系统增加很多复杂性。

[编辑,2015年6月]如果您正在阅读此内容,因为您正在寻找部署期间慢速编译的解决方案,则可以考虑在本地对资产进行预编译。有关此信息,请参见资产管道指南。这样,您可以仅在更改时在本地预编译,然后进行快速部署,无需预编译阶段。


1
谢谢,我已经接受了你的答案。但现在我的问题是,好吧,它现在不这样做,但你认为资产管道可能有一个功能,在第一次请求时进行惰性编译,完全像预编译一样,包括写入./public并更新指纹清单吗? - jrochkind
你确实需要使用Capistrano来管理Rails 3.1。在新的public目录中编译资产时,旧的应用程序仍在运行。当编译完成后,新版本会被建立符号链接并自动重启服务器。 - Richard Hulse
为了充分利用管道和指纹识别的优势,您需要在Web服务器上设置远期头,并为js和css文件启用gzip压缩。请问是否能提供一些如何执行此操作的说明或链接? - Isaac Betesh
从指南开始:http://guides.rubyonrails.org/asset_pipeline.html#server-configuration - Richard Hulse
有人知道如何检测文件是否是预编译的吗? - knagode
显示剩余4条评论

7
为了减少预编译的开销。
Precompile everything initially with these settings in production.rb
# Precompile *all* assets, except those that start with underscore
config.assets.precompile << /(^[^_\/]|\/[^_])[^\/]*$/

您可以在*.html.erb文件中使用像"/assets/stylesheet.css"和"/assets/web.png"这样的图片和样式表。


6

对于使用Heroku的用户:

如果你部署到Herkou,它会自动在部署期间为你完成预编译,如果未包含已编译的资源(即未提交public/assets文件夹),因此不需要设置 config.assets.compile = true,也不必提交预编译的资产。

Heroku的文档可以在这里找到。建议使用CDN以减轻动态资源的负载。


1

即使在第一次访问后,它也不会与预编译相同:因为文件没有写入文件系统,所以无法直接由Web服务器提供服务。即使只是读取缓存条目,也始终涉及一些Ruby代码。


嗯,我以为使用 precompile=true 后,编译后的资源会被写入文件系统。你确定吗?让我检查一下... - jrochkind
1
呃,我想你是对的 - 它们确实被写入文件系统,但似乎是在tmp/cache而不是public/assets中,因此不是Web服务器可以看到的位置,它们仍将由Rails应用程序而不是Web服务器提供服务。唉。你觉得这样正确吗? - jrochkind
正确。不会像让Web服务器直接获取它们那样快。如果在应用程序前面放置CDN(如CloudFront),可能并不重要。 - Frederick Cheung

1

config.asset.compile = false设置为false

在您的Gemfile中添加

group :assets do gem 'turbo-sprockets-rails3' end

安装bundle

运行rake assets:precompile

然后启动您的服务器


只要我在production.rb文件中设置了config.asset.compile = true,因为没有添加预编译机制。由于这个原因,每次启动服务器时加载页面需要太长时间(当请求到达时,同时处理请求和编译资产)。现在我在Gemfile中包含了turbo-sprockets-rails3并运行命令rake assets:precompile,它会提前编译资产。现在我在production.rb中设置了config.asset.compile = false并启动服务器,页面加载没有任何延迟。(只处理请求而不进行资产编译) - Mohammed Saleem
2
值得一提的是,在 Ruby 3 上只有 turbo-sprockets-rails3 是必需的。 - Andre Figueiredo

0

0

来自官方指南

在第一次请求时,资产将按照上述开发中的方式进行编译和缓存,并且助手中使用的清单名称将被更改以包括MD5哈希。

Sprockets还将Cache-Control HTTP标头设置为max-age=31536000。这向服务器和客户端浏览器之间的所有缓存表明,此内容(提供的文件)可以缓存1年。这样做的效果是减少从您的服务器请求此资产的数量;该资产有很大机会在本地浏览器缓存或某些中间缓存中。

此模式使用更多内存,性能较差,不建议使用。

此外,如果您在部署中使用Capistrano,预编译步骤也不会有任何问题。它会为您处理。您只需运行

cap deploy

或者(根据您的设置)

cap production deploy

然后你就准备好了。如果你还没有使用它,我强烈建议你去试试。


那么你认为官方指南中的语言是否与我一致吗?我看过那个指南,不太确定它是否意味着我上面所提出的,你觉得呢?这是我的问题。 - jrochkind
是的,你基本上说了同样的话。我建议你不要打开实时编译。 - Sergio Tulentsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接