该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-07-17
本文提到的typo版本是目前最新的5.0.3.98.1,theme_support版本是1.3.0。在typo中,我们看到了很好很花哨的换肤机制,而theme_support则是从typo中抽取出来的一个plugin,以供其他程序进行换肤操作。
通常,我们会将程序的图片,css等与皮肤相关的文件放在网站的public目录下,在view中直接引用即可。但是从上图我们可以看到,typo将新皮肤的所有相关文件都存放在theme目录下的各个子目录下。那么typo是如何引用这些文件的呢?下面,我们随便打开某一个皮肤下面的layout文件,例如theme/typographic/layouts下面的default.html.erb文件,可以看到如下代码: <%= stylesheet_link_tag '/stylesheets/theme/style.css', :media => 'all' %> 你仔细搜查一下程序,绝对发现不了/stylesheets/theme目录,乱引用?当然不是,我们可以在routes.rb中发现如下的route信息: get.with_options(:controller => 'theme', :filename => /.*/, :conditions => {:method => :get}) do |theme| theme.connect 'stylesheets/theme/:filename', :action => 'stylesheets' theme.connect 'javascripts/theme/:filename', :action => 'javascript' theme.connect 'images/theme/:filename', :action => 'images' end 很经典的route配置,原来在typo中,所有对css,javascript,image的引用,不是通过直接引用public目录下的文件,而是通过一个传统的controller:ThemeController来完成的。至于ThemeContorller具体代码,这里不详细谈,因为不是本文的重点,无非就是根据当前选择的皮肤(在admin界面选择的),到相应的皮肤目录(比如:theme/typographic)下,将各个文件找到,然后通过send_file的方式发送到客户端浏览器。那执行完一次action后,controller到底应该执行怎么样的render操作呢?(通过上图,我们看到不同的view文件,在各自的theme子目录下) class ApplicationController < ActionController::Base ...... def setup_themer # Ick! self.view_paths = ::ActionController::Base.view_paths.dup.unshift("#{RAILS_ROOT}/themes/#{this_blog.theme}/views") end end 大致讲下,setup_themer方法的作用是根据目前皮肤配置(this_blog.theme),将controller的view_paths设置为某一个皮肤的目录(比如:theme/typographic/views),这样,在执行render操作的时候,将使用皮肤目录下的view,layout等等(还记得前面提到的layout中引用css的方法么?重要!)。并且,将setup_themer方法设置为需要换肤的contorller的before_filter。于是,当我们执行程序的时候,就可以达到动态换肤的目的。
前面我讲了,这种机制会存在一个严重的性能问题,是怎么来的呢?在传统方式下,我们将css,images,js都放在public目录下,view进行引用的时候,在web服务器层面,就完成了文件的引用,发送操作。但是在typo这种机制下,每引用一个css,图片,js,web服务器会将请求route到rails,通过rails的ThemeController来处理请求,返回文件。这都还算小事,在一次request,response周期,这样一个额外操作往往占用不了多大的百分比。但是,我们知道ThemeController是rails中一个普通的Controller,它也继承自ApplicationController。通常,我们会将很多程序通用逻辑放在ApplicationController中来做,比如:验证用户合法性,处理本地化等等,而这些操作,大部分都是访问数据库。也就是说,我们通过ThemeController,仅仅想得到一个css或者图片文件,但是ApplicationController仍然会初始化,执行相应的操作(重复,无用的操作)。这就是性能问题的根源。口说无凭,下面的数据揭示了一切:
目前,我找到三个解决方案处理这个性能问题。 1. 在ApplicationController中,执行某些业务逻辑的时候,判断一下controller,如果是ThemeController,则跳过。这样做的好处是不用变动typo中换肤方法的使用,仍然将皮肤放在theme目录下即可。但是,这样做似乎“侵入性”太强,仅仅为了一个皮肤,修改业务逻辑,实在有些得不偿失,因此,这种方案不是一个很好的方案。 2. 要想不影响已有的业务逻辑解决这个性能问题,我们则需要手动做一些修改。将某一个皮肤放到theme目录下以后,我们收到将css,image,js拷贝到public的相应目录下。比如:将theme/typographic/stylesheets下的所有css文件拷贝到public/stylesheets/typographic目录下,然后,手动将皮肤中所有对css的引用修改为引用public下面相应的目录,比如:我将前面提到的default.html.erb中对css的引用修改为如下所示: <%= stylesheet_link_tag 'typographic/style.css', :media => 'all' %> 然后,将关于theme的roues信息全部删除,让web server为我们完成这个工作。这样,既能解决性能问题,还不影响业务逻辑。只不过,需要不少的手动工作(要将皮肤中所有关于css,js,images的引用修改到public目录下)。 3. 一劳永逸,按照第二种方法重写theme_support plugin。。。
2008.7.17 23:30 星期四 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-07-18
晕,很简单的一点点东西竟然让你写出这么大一篇来
|
|
返回顶楼 | |
发表时间:2008-07-18
没办法,人笨,只能把别人觉得简单的东西详细记录下来。
不过,你要把图片去掉,似乎也不怎么“大”,是不是应该放“贴图区”去阿?呵呵 |
|
返回顶楼 | |
发表时间:2008-07-18
好像目前对于rails中的换肤,我所看到的只有theme_support插件,我用了它,感觉比没有是慢一些,不爽.
不过我想对于网站换肤,如果只有想改一下网站总体色调什么的,那么只需要引用不同的css样式文件即可啊,没有必要搞得这么麻烦. |
|
返回顶楼 | |
发表时间:2008-07-18
crazy!
<%= stylesheet_link_tag 'style.css', :theme =>:auto %> or <%= stylesheet_link_tag_with_theme 'style.css' %> enhance stylesheet_link_tag helper. are they enough? |
|
返回顶楼 | |
发表时间:2008-07-18
liusong,我没搞懂你什么意思~能详细点么?
|
|
返回顶楼 | |
发表时间:2008-07-18
woody_420420 told me:
Each theme has an individual layout file, and it operates views_path to switch between them. so, no need to rewrite/enhance stylesheet_include_tag helper. di, could you introduce views_path for us? sorry, can't input Chinese. |
|
返回顶楼 | |
发表时间:2008-07-18
是的。typo这个机制其实还是不错的。关键问题就是css,images,js引用问题。
不过你说的“stylesheet_link_tag_with_theme”也不错,我们可以自己写一个,然后在每一个皮肤的layout中使用,就不用每次都"../../public/..."了。 enjoy ubuntu~~:) |
|
返回顶楼 | |
发表时间:2008-07-18
woody_420420 写道 liusong,我没搞懂你什么意思~能详细点么?
二大爷说话就素这个样子,你搞啊搞啊滴就明白鸟。 |
|
返回顶楼 | |
发表时间:2009-02-17
不错,学习了,但好像typo-5.2仍然没有改变啊
看来typo团队没有看楼主的帖子 |
|
返回顶楼 | |