让Rails的资产流水线更快

86 阅读4分钟

我们都知道,对于一个相当大的Rails应用来说,前端是相当充实的,资产预编译,更重要的是--开发模式的改变远非瞬息之间。

我们所指的前端是那种大量使用sass、sass库(Compass、Bourbon等)和转置的JavaScript语言(如旧的CoffeeScript、ES6等)的前端。

用libsass替换Ruby Sass

在Sass方面,相当长一段时间以来,有一个纯C/C++实现的Sass CSS预编译器:libsass 。显然,用C/C++实现意味着它的运行速度应该比Ruby的实现快上好几个数量级。

我们所需要的是一个使用它的 gem:进入sassc-rails,它是sass-rails gem 的一个直接替换。

在现实世界中,与vanilla gem相比,sassc-rails 的速度如何?(直接从他们的repo中获得的基准测试)

# Using sassc-rails
[1] pry(main)> Benchmark.bm { |bm| bm.report { Rails.application.assets["application.css"] } }
       user     system      total        real
   1.720000   0.170000   1.890000 (  1.936867)

# Using sass-rails
 [1] pry(main)> Benchmark.bm { |bm| bm.report { Rails.application.assets["application.css"] } }
       user     system      total        real
  7.820000   0.250000   8.070000 (  8.106347)

不是真正的数量级快,但4.5倍的速度也不差。

唯一的问题是,它不能完全与通常的sass gem如Compass等一起工作,也就是说,在生产中使用它之前,要确保它能毫无问题地编译你的scss文件。

为了帮助解决这个问题,你可以查看Sass Compatibility网站,并在不同的分支中安装该宝石后运行你的应用程序,以测试情况。

Compass中场休息

让我头疼的是,Compass根本无法与sassc-rails

另外,从另一个角度看,Compass似乎,嗯,有点死了。

我想我要把我那些仍然使用Compass的前端迁移到Bourbon,也许还有autoprefixer-rails

用mini_racer取代JS转写/简化/等等。

therubyracer的问题是,它使用libv8 ~> 3.16.14.0 版本 ("用于发布 v8 运行库和头文件的源码和二进制形式的 gem"),而 mini_racer使用~> 5.1 ,正如人们所期望的,它比前者快得多。

从他们的资源库中得到一些快速的基准测试。

$ ruby bench_uglify.rb

Benching with MiniRacer
MiniRacer minify discourse_app.js 13813.36ms
MiniRacer minify discourse_app_minified.js 18271.19ms
MiniRacer minify discourse_app.js twice (2 threads) 13587.21ms

Benching with therubyracer
MiniRacer minify discourse_app.js 151467.164ms
MiniRacer minify discourse_app_minified.js 158172.097ms
MiniRacer minify discourse_app.js twice (2 threads) - DOES NOT FINISH

Killed: 9

在这里,我们谈论的是10倍的改进,也就是非常好的收益,因此是一个数量级的速度。在兼容性方面,这似乎是一个很好的替代品,也就是说,到目前为止,在我把它加入Gemfile的应用程序中,没有任何问题。

替代mini-racer以获得最佳性能

Sprockets使用ExecJS,它 "选择最好的运行时间来评估你的JavaScript",这意味着如果你不介意安装一个额外的依赖,你可以直接使用Node.js 6.x,以获得最大的性能。

由于我通过在本地预编译来部署我的资产,我只是通过brewbrew install node 安装了Node.js 6.2.0,并在一个2K行的CoffeeScript JS文件上运行time rake assets:clobber assets:precompile 。不多说了,下面是结果。

node.js 6.2.0

rake assets:clobber assets:precompile 7.30s user 1.27s system 102% cpu 8.358 total

mini-racer与libv8 5.x

rake assets:clobber assets:precompile 14.96s user 1.20s system 101% cpu 15.943 total

这又是一个2倍的速度提升!另外,我还用10K行的CoffeeScript试了一下,在这种情况下,mini-racer甚至没有完成。

感谢@attilagyorffy指出了这一点。

我应该在生产中使用这些吗?

在一个设置中,资产被预先编译在本地,然后上传到实际的虚拟机上,这不是一个大问题,也就是说,如果出现问题,只需恢复到原始的宝石。

到目前为止,Mini-racer看起来坚如磐石,而sassc-rails仍有一些库的问题,也就是说,还没有准备好在所有的使用情况下进行生产。

如果你不介意安装node.js,并希望获得最大的性能,那么你完全可以这样做,因为它与ExecJs的工作是完美的。

在最佳情况下,你可以将两者整合到你的Gemfile中,你将在部署过程中得到相当好的提升,更重要的是:在开发过程中(当然是在有大量资产的应用中)。