config.assets.compile=true,为什么不呢?

config.assets.compile=true in Rails production, why not?

提问人:jrochkind 提问时间:1/11/2012 更新时间:12/14/2018 访问量:79363

问:

安装的默认 Rails 应用程序已在生产环境中。rails newconfig.assets.compile = false

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

那么,如果我开始生产会发生什么?config.assets.compile = true

我不需要再跑了。我相信会发生的是,第一次请求资产时,它将被编译。这将是第一次对性能的影响(这意味着你通常需要在生产环境中有一个 js 运行时来做到这一点)。但除了这些缺点之外,在资产被延迟编译后,我认为对该资产的所有后续访问都不会对性能造成影响,应用程序的性能将与初始首次点击延迟编译后的预编译资产完全相同这是真的吗?precompile

我错过了什么吗?还有其他原因不投入生产吗?如果我在生产中有一个 JS 运行时,并且愿意在首次访问资产时牺牲性能下降,以换取不必运行,这有意义吗?config.assets.compile = trueprecompile

Ruby-on-Rails 资产管道 生产环境

评论

1赞 Mauro 6/20/2018
警告,旧版本的链轮包含一个错误,如果 config.assets.compile 配置为 true,则存在目录遍历漏洞 ( blog.heroku.com/rails-asset-pipeline-vulnerability )
3赞 schmijos 1/8/2020
这正是 Stackoverflow 应该如何工作的。一个写得很好的问题和一个写得很好的答案。我爱你,无论是op还是@richard-hulse。

答:

0赞 Sergio Tulentsev 1/11/2012 #1

来自官方指南

在第一个请求中,将按照上面的开发中所述编译和缓存资产,并更改帮助程序中使用的清单名称以包含 MD5 哈希。

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

此模式使用更多内存,性能比默认值差,因此不建议使用。

此外,如果您使用 Capistrano 进行部署,预编译步骤一点也不麻烦。它会为你照顾它。你只是运行

cap deploy

或(取决于您的设置)

cap production deploy

你都准备好了。如果您仍然不使用它,我强烈建议您检查一下。

评论

0赞 jrochkind 1/12/2012
那么你认为官方指南中的语言同意我的观点吗?我看过那个指南,我不太确定它是否意味着我上面的建议,你怎么看?这是我的问题。
0赞 Sergio Tulentsev 1/12/2012
是的,你说的基本上是一样的。我建议你不要打开实时编译。
1赞 Frederick Cheung 1/11/2012 #2

这与预编译不同,即使在第一次点击之后也是如此:因为文件没有写入文件系统,所以它们不能直接由 Web 服务器提供。一些 ruby 代码将始终参与其中,即使它只是读取缓存条目。

评论

0赞 jrochkind 1/11/2012
嗯,我以为 ,编译后的资产将被写入文件系统。是否确定?让我检查一下......precompile=true
1赞 jrochkind 1/12/2012
呃,我认为你是对的——它们被写入文件系统,但它看起来像是 in 而不是 ,所以不是 Web 服务器可以看到的地方,它们仍然将由 rails 应用程序而不是 Web 服务器提供服务。等等。你觉得是这样吗?tmp/cachepublic/assets
0赞 Frederick Cheung 1/12/2012
正确。不会像让 Web 服务器直接接收它们那样快。如果您将像 cloudfront 这样的 cdn 放在应用程序前面,可能无关紧要
284赞 Richard Hulse 1/12/2012 #3

我写了那段指南。

您绝对不想在生产环境中进行实时编译。

当您编译时,会发生以下情况:

对 /assets 中文件的每个请求都会传递给 Sprockets。在对每个资产的第一次请求中,它被编译并缓存在 Rails 用于缓存的任何内容(通常是文件系统)中。

在后续请求中,Sprockets 收到请求,必须查找指纹文件名,检查构成资产的文件(图像)或文件(css 和 js)是否未被修改,然后是否有缓存版本。

这是 assets 文件夹插件使用的任何供应商/assets 文件夹中的所有内容

这是很大的开销,因为老实说,代码没有针对速度进行优化。

这将影响资产通过网络到达客户端的速度,并将对您网站的页面加载时间产生负面影响。

与默认值比较:

当资产已预编译且编译处于关闭状态时,将编译资产并将其指纹识别到 .Sprockets 将普通文件名到指纹文件名的映射表返回给 Rails,Rails 将其写入文件系统。清单文件(Rails 3 中的 YML 或 Rails 4 中具有随机名称的 JSON)在启动时由 Rails 加载到内存中,并缓存以供资产辅助方法使用。public/assets

这使得使用正确的指纹资产生成页面的速度非常快,并且文件本身的服务速度很快。两者都比实时编译快得多。

为了获得管道和指纹识别的最大优势,您需要在 Web 服务器上设置遥远的未来标头,并为 js 和 css 文件启用 gzip 压缩。Sprockets 会写入资产的 gzip 版本,您可以将服务器设置为使用这些版本,而无需为每个请求执行此操作。

这样可以尽可能快地以尽可能小的尺寸将资产分发给客户端,从而加快页面的客户端显示速度,并减少(使用遥远的未来标头)请求。

因此,如果您正在实时编译,则为:

  1. 很慢
  2. 缺乏压缩
  3. 将影响页面的呈现时间

  1. 越快越好
  2. 压缩
  3. 删除从服务器听到的压缩(可选)。
  4. 最小化页面的呈现时间。

编辑:(回答后续评论)

管道可以更改为在第一个请求时进行预编译,但这样做存在一些主要障碍。首先是必须有一个指纹名称的查找表,否则帮助程序方法太慢。在按需编译的 senario 下,当编译或请求每个新资产时,需要有某种方式附加到查找表中。

此外,在编译并到位之前,有人将不得不在未知的时间内支付缓慢的资产交付的代价。

默认,即一次离线支付编译所有内容的价格,不会影响公众访问者,并确保在上线之前一切正常。

交易破坏者是它给生产系统增加了很多复杂性。

[编辑,2015年6月]如果您阅读本文是因为正在寻找部署期间编译时间慢的解决方案,那么您可以考虑在本地预编译资产。有关此内容的信息,请参阅资产管道指南。这允许您仅在发生更改时在本地进行预编译,提交更改,然后在没有预编译阶段的情况下进行快速部署。

评论

1赞 jrochkind 1/12/2012
谢谢,我已经接受了你的回答。但现在我的问题是,好吧,它现在不这样做,但可以想象,你认为 Asset Pipeline 可以有一个功能,它可以在第一次请求时延迟编译,就像预编译一样,包括写入 ./public 和更新指纹清单?
0赞 Richard Hulse 1/12/2012
见上文。这是一个问题,因为 Capistrano 不适合您吗?
0赞 jrochkind 2/17/2012
我不使用 Capistrano。我以前不需要,增加的复杂性是不值得的。也许资产管道是压垮骆驼并需要它的最后一根稻草。在您看来,在没有capistrano或类似工具的情况下,使用资产管道管理Rails部署是不可行的吗?很遗憾,对于简单的设置来说,手动完成过去并不是什么大问题。
0赞 Richard Hulse 2/20/2012
你确实需要 Capistrano for Rails 3.1。当旧应用仍在运行时,这些资产将编译到新的公共目录中。编译完成后,新版本将进行符号链接,服务器会自动重新启动。
0赞 Isaac Betesh 6/14/2013
“为了获得管道和指纹识别的最大优势,您需要在 Web 服务器上设置遥远的未来标头,并为 js 和 css 文件启用 gzip 压缩。”--您能否提供一些说明或链接来说明如何执行此操作?
7赞 dbKooper 8/7/2012 #4

减少预编译的开销。

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赞 William Denniss 12/12/2013 #5

对于使用 Heroku 的任何人:

如果您部署到 Herkou,它将在部署期间自动为您进行预编译,如果未包含已编译的资产(即 not committed),因此不需要 ,或提交预编译的资产。public/assetsconfig.assets.compile = true

Heroku 的文档在这里。建议使用CDN来消除dyno资源上的负载。

1赞 Mohammed Saleem 6/19/2014 #6

设置config.asset.compile = false

添加到您的 Gemfile

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

安装捆绑包

rake assets:precompile

然后启动服务器

评论

0赞 Mohammed Saleem 6/19/2014
就我设置的文件而言,因为没有添加预编译机制。因此,每次我们启动服务器时,加载页面都需要太多时间(当请求命中时,处理请求和编译资产)。现在我包含在 Gemfile 中并运行命令,它会先编译资产。现在我设置并启动服务器,页面加载没有任何延迟。(只处理请求,不进行资产编译)config.asset.compile = true in production.rbturbo-sprockets-rails3rake assets:precompileconfig.asset.compile = false in production.rb
2赞 Andre Figueiredo 5/9/2015
值得一提的是,这仅在 Ruby 3 上是必需的turbo-sprockets-rails3
0赞 Aurel Branzeanu 12/14/2018 #7

因为它打开了一个目录遍历漏洞 - https://blog.heroku.com/rails-asset-pipeline-vulnerability