Rails 生产环境中的 config.assets.compile=true,为啥不呢?

Posted

技术标签:

【中文标题】Rails 生产环境中的 config.assets.compile=true,为啥不呢?【英文标题】:config.assets.compile=true in Rails production, why not?Rails 生产环境中的 config.assets.compile=true,为什么不呢? 【发布时间】:2012-02-07 23:05:14 【问题描述】:

rails new 安装的默认 Rails 应用在生产中具有 config.assets.compile = false

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

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

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

我有什么遗漏吗?还有什么其他理由不在生产中设置config.assets.compile = true?如果我在生产环境中有一个 JS 运行时,并且愿意为资产的 first 访问权而权衡性能下降,以换取不必运行precompile,这是否会使有意义吗?

【问题讨论】:

警告,旧版本的 sprockets 包含一个错误,如果 config.assets.compile 配置为 true,则存在目录遍历漏洞的风险 (blog.heroku.com/rails-asset-pipeline-vulnerability) 这正是 *** 的工作方式。一个写得很好的问题和一个写得很好的答案。我爱你 op 和 @richard-hulse。 【参考方案1】:

我写了那部分指南。

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

编译后,会发生以下情况:

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

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

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

这是很多开销,因为老实说,代码并未针对速度进行优化。

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

与默认比较:

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

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

要获得管道和指纹识别的最大优势,您需要在 Web 服务器上设置远期标头,并为 js 和 css 文件启用 gzip 压缩。 Sprockets 编写资源的 gzip 版本,您可以将其设置为服务器使用,从而无需为每个请求都这样做。

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

所以如果你在现场编译它是:

    很慢 缺乏压缩 会影响页面的呈现时间

对比

    尽快 压缩 删除从服务器听到的压缩(可选)。 最小化页面的渲染时间。

编辑:(回答后续评论)

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

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

默认情况下,编译所有内容的费用一次离线支付,不会影响公共访问者,并确保一切在上线之前都能正常工作。

关键在于它给生产系统增加了很多复杂性。

[编辑,2015 年 6 月] 如果您正在阅读本文是因为您正在寻找在部署期间编译时间较慢的解决方案,那么您可以考虑在本地预编译资产。这方面的信息在asset pipeline guide 中。这允许您仅在发生更改时在本地进行预编译,提交该更改,然后进行快速部署,无需预编译阶段。

【讨论】:

谢谢您,我已接受您的回答。但现在我的问题是,好吧,它现在不这样做,但可以想象,你认为资产管道可以有一个特性,它在第一次请求时延迟编译,就像预编译一样,包括写入 ./public 并更新指纹清单? 见上文。这是因为 Capistrano 不适合您的问题吗? 我不使用 Capistrano。我以前不需要,增加的复杂性是不值得的。也许资产管道是压垮骆驼并需要它的稻草。在您看来,使用资产管道没有 capistrano 或类似方法来管理 Rails 部署是不可行的?很遗憾,对于简单的设置,过去手动操作并不是什么大问题。 你真的需要 Capistrano for Rails 3.1。当您的旧应用程序仍在运行时,这些资产会在新的公共目录中编译。编译完成后,新版本被符号链接,服务器自动重启。 "为了获得管道和指纹识别的最大优势,您需要在 Web 服务器上设置远期标头,并为 js 和 css 文件启用 gzip 压缩。"--请您提供有关如何执行此操作的一些说明或链接?【参考方案2】:

为了减少预编译的开销。

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”

【讨论】:

【参考方案3】:

对于任何使用 Heroku 的人:

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

Heroku 的文档是 here。建议使用CDN 来消除 dyno 资源上的负载。

【讨论】:

【参考方案4】:

它与预编译不同,即使在第一次命中之后:因为文件没有写入文件系统,它们不能直接由 Web 服务器提供服务。总是会涉及到一些 ruby​​ 代码,即使它只是读取缓存条目。

【讨论】:

嗯,我认为使用precompile=true,编译后的资产将被写入文件系统。你确定吗?让我检查一下…… 呸,我认为你是对的——它们被写入文件系统,但它看起来像在 tmp/cache 而不是 public/assets,所以不是 Web 服务器可以看到的地方,它们仍将由 rails 应用程序而不是 Web 服务器提供服务。废话。你觉得对吗? 正确。不会像让网络服务器直接接收它们那样快。如果你在你的应用前面放一个像 cloudfront 这样的 cdn 可能没关系【参考方案5】:

设置config.asset.compile = false

添加到您的 Gemfile

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

安装包

运行rake assets:precompile

然后启动你的服务器

【讨论】:

据我设置config.asset.compile = true in production.rb文件,因为没有添加预完成机制。由于每次我们启动服务器时都需要花费太多时间来加载页面(当请求同时处理请求和编译资产时)。现在我在 Gemfile 中包含了 turbo-sprockets-rails3 并运行命令 rake assets:precompile 它会先编译资产。现在我设置config.asset.compile = false in production.rb 并启动服务器,页面加载没有任何延迟。 (只处理请求,不编译资产) 值得一提的是,turbo-sprockets-rails3 仅在 Ruby 3 上是必需的【参考方案6】:

来自官方guide:

在第一次请求时,资产按照上述开发过程中所述进行编译和缓存,并且帮助程序中使用的清单名称被更改为包含 MD5 哈希。

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

此模式使用更多内存,性能比默认值差,不推荐使用。

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

cap deploy

或(取决于您的设置)

cap production deploy

一切就绪。如果您仍然不使用它,我强烈建议您检查一下。

【讨论】:

那么您认为官方指南中的语言与我一致吗?我看过那个指南,我不太确定它是否意味着我上面的建议,你怎么看?这是我的问题。 是的,你说的基本一样。我建议你不要打开实时编译。【参考方案7】:

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

【讨论】:

以上是关于Rails 生产环境中的 config.assets.compile=true,为啥不呢?的主要内容,如果未能解决你的问题,请参考以下文章

将 Rails 应用程序更改为生产环境

rails控制台在生产环境中挂起

Mailform 在本地工作,但不在生产环境中(Heroku、Rails)

在 Rails 4 生产环境中找不到资产的 404 错误

Rails:在生产环境中配置记录器以使用 Papertrail

Rails 应用程序在生产环境中不提供 JS 和 SCSS 资产