【问题标题】:Sprockets Best Practice for big projects大型项目的 Sprockets 最佳实践
【发布时间】:2012-05-12 02:56:35
【问题描述】:

几个月来,我一直在与其他大学生一起参与一个 RoR 项目。我负责前端和资产部分,我发现自己想知道如何以最佳方式使用 Sprockets

拥有资产管道的目的是提高页面加载时间方面的性能。 Rails 生成应用程序的方式是将所有样式表和 javascript 放入两个压缩文件中。

但是,当应用程序的数量和复杂性增加时,恕我直言,这是一个坏主意,因为一体式文件的大小会增加,并且可能会出现重叠的 CSS 规则或查找元素但不查找元素的脚本的问题找到它,使页面崩溃的整个 javascript 部分。

注意:我知道,如果团队之间有良好的编码规则和约定,这些问题的发生可以减少,但不会降至 0。

到目前为止,我对这些断言是否正确?

如果是肯定的,那么什么是处理大型项目的好方法,而不提供对页面范围无用的大量规则或脚本,又不会失去发送给客户的少量资产的好处?

我目前的方法是定义一组一体式文件,每个应用程序的“上下文区域”一个。所以基本上我尝试发送 2+2 个文件。

但是如何处理这样的情况:

有一个非常简单的资源索引视图,其中只有条目列表,每个条目都链接到各自的节目。相反,这个节目一点也不简单,它有很多 CSS3 规则和 javascript。

使用我的方法,索引操作将有很多未使用的代码。你如何处理你的大项目?

您更重视页面获得的资源还是性能?

另一个困扰我的是如何处理部分。在面向对象的设计中,每个部分都应该(?)包含它需要在加载的任何地方正常工作所需的所有内容。但是,如果我在视图和部分视图中为同一资产调用 javascript_include_tag,这将导致重复包含。

我的所有这些想法都有意义还是我错过了什么?或者可能是从错误的角度看待问题?你能给我一些链接或开源项目来看看吗?您对此事有何看法?

感谢和抱歉这个冗长的问题。

【问题讨论】:

    标签: ruby-on-rails performance optimization asset-pipeline sprockets


    【解决方案1】:

    从最佳实践开始(一级代码):

    有两个文件,预编译(缩小/压缩),服务于服务器压缩和遥远的未来标头。作为标头的结果,这些文件将在第一次请求时由客户端浏览器缓存,并用于之后的所有页面,直到缓存过期或被清除。

    文件也可能被透明代理缓存; ISP 使用这些来为他们的客户加速网络。这将进一步减少请求。

    所以从性能的角度来看,只有第一个请求是昂贵的。

    管理部分(二级代码)

    在具有管理部分的站点中,将其分离成一对单独的文件是很常见的。管理员可能会使用 jquery-ui,而公共站点则不会。在这种情况下,这是最好的折衷方案 - 您不想为每个公共请求提供一个完全未使用的库。

    Rails 管道指南提到了如何设置。

    页面代码(第三层)

    第三层是针对特定页面的 js 和 css(您的问题)。

    在这种情况下,您将不得不在性能/维护方面进行调用。如果你有很多代码,你想分离出所有这些都必须添加到资产管道预编译数组中。如果有很多或代码很小,这很痛苦。

    需要(或想要)这样做可能是向程序员发出的信号,表明 CSS 的整体设计可以改进。如果您必须为特定页面添加大量额外规则,那么您可能没有像您可能那样使用 CASCADE(CSS 中的 C)。 :-)

    面向对象的 CSS 是解决这个问题的一种方法。作为一个门徒,它是关于定义可以在任何地方使用的可重用 CSS 块。如果这样做了,那么从性能(包括所有页面的规则)或维护的角度来看,少量的页面特定规则就不会成为问题。

    如果您必须为页面创建一个单独的文件,那么遵循这些文件的管道最佳实践至少不会牺牲文件的可缓存性。

    我在项目中所做的是提供一些帮助程序,允许视图为主应用程序布局堆叠文件和代码。这样做的好处是我可以控制生成的代码出现在哪里,而不是出现在页面中间,如果将文件包含在部分视图中,就会发生这种情况。 (这对页面渲染性能非常不利,因为中间页面文件包含块渲染)

    我这样做:

    application_helper.rb

    def deferred_javascript(&block)
      @deferred_javascript ||= []
    
      if block_given?
        @deferred_javascript << capture(&block)
      end
    
      @deferred_javascript
    end
    
    def deferred_javascript_files
        @javascript_includes ||= []
    end
    
    def deferred_css_files
        @stylesheet_includes ||= []
    end
    

    然后在一个视图中:

    <% deferred_javascript_files << 'extras/public_form' %>
    <% deferred_css_files << 'extras/public_form' %>
    

    或者,如果它是单行的,我可以使用带有 deferred_javascript 帮助器的块。 (我很少使用这个)。

    public_form 文件是此表单(jquery-ui、formtastic)所需内容的清单,而其他任何页面都不需要。

    注意:以这种方式使用的任何文件都必须添加到预编译数组中:

    config.assets.precompile += ['extras/public_form.css', 'extras/public_form.js']
    

    这很容易忘记,因为我的方法在没有的开发模式下工作,但在生产中部署时会失败!

    最后在应用程序布局中,在 CSS 的顶部(在 head 标签中):

    <%= stylesheet_link_tag('application', :media => 'all' ) -%>
    <%= stylesheet_link_tag(deferred_css_files) if deferred_css_files.any? %>
    

    在布局的底部(在结束 body 标记之前)用于 JS:

    <%= javascript_tag do %>
      $(document).ready(function() {
    <%= raw deferred_javascript.join("\n") %>
      });
    <%- end unless deferred_javascript.blank? -%>
    <%= javascript_include_tag 'application' %>  
    <%= javascript_include_tag(deferred_javascript_files) if deferred_javascript_files.any? %>
    

    此行添加主清单,以及任何视图清单和代码。

    我所概述的内容确保任何添加视图的文件都是管道的一部分,并且与主文件具有相同的缓存机会。

    总结一下:

    将所有内容放在主清单中几乎总是正确的做法,但是当特定于页面的代码非常大时,可以将其移动到单独的文件中并按照我的概述提供。您将不得不对哪种方法更好的性能进行调用 - 不是在每一页上都有额外的代码,或者在一个页面上没有额外的文件请求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-07
      • 2014-12-19
      • 2023-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-29
      • 2015-03-25
      相关资源
      最近更新 更多