Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sass generation time in rails is much longer than on command line #67

Closed
tmeasday opened this issue Oct 18, 2011 · 14 comments
Closed

Sass generation time in rails is much longer than on command line #67

tmeasday opened this issue Oct 18, 2011 · 14 comments

Comments

@tmeasday
Copy link

My SASS is taking up to a few minutes on some machines to generate CSS files.

I've set up a new rails project with just the css files for reproduction:
https://github.com/tmeasday/sass_rails_slowness

On my machine, running:
time sass --compass app/assets/stylesheets/screen.css.scss > /dev/null
Takes ~6s

Changing a scss file and running:
time curl http://sass-rails-slowness.dev/assets/screen.css > /dev/null
Takes ~20s

I'm running ruby-1.9.2p290 through rbenv.

On my colleague's machine the times are 23s and 40s.

Any ideas?

@tmeasday
Copy link
Author

Further investigation:

I wrote a little test script that runs the Sass::Engine in more or less the same way that sass-rails does, but hardwired to a single file.

So it does this:

puts Benchmark.measure { out << engine.render }

Running it directly (with a rails environment) via rails runner gives benchmarks of:

9.300000   0.100000   9.400000 (  9.404537)

(I'm guessing the extra few seconds can be attributed to rails doing things like whiny_nils and other stuff I'm not aware of).

I then hardwired sass-rails to call this rather than actually doing work; so I changed template_handlers.rb line 94 from

def evaluate(scope, locals, &block)
  Sass::Engine.new(data, sass_options(scope)).render
end

To:

 def evaluate(scope, locals, &block)
    require '/Users/tom/Development/Percolate/sass_rails_slowness/script/tester'
    SassTester.render
 end

So that the exact same code path is run. When I run it via rake assets:precompile:primary, it reports:

16.640000   0.130000  16.770000 ( 16.752122)

So it's taking around 2x as long, with the same rails environment, running the exact same code. I can't for the life of me figure out what's going on here??

@olivierlacan
Copy link
Contributor

This is a continuation of the behavior I presented in #36, except without errors displaying in the console anymore.

Still no news on this? It's been more than 4 months now.

@Papipo
Copy link

Papipo commented Dec 16, 2011

I think I am hitting this same issue in my app right now. Extremely high compilation times each time I touch any of my stylesheets.

@tmeasday
Copy link
Author

@Papipo, if you haven't seen it, have a look at this gist.

I outlined some steps in there that we took to work around this problem. We've managed to get compilation times down to something more acceptable, so at least we can develop! A lot of the things we did are common sense in terms of getting the output CSS file down in size, which I think is desired anyway.

@scottdavis
Copy link

This isn't so much a problem with sass as it is a problem with the resolver in sprockets being slow im really starting to dislike Hike

@tmeasday
Copy link
Author

Well, I am not sure about that. Because in my investigations above, I was using the same SassEngine with the same load paths and it was still taking twice as long. More information about the above, SassTester.render does more or less this:

module SassTester
  def self.render
    engine= Sass::Engine.new(HARDWIRED_FILE,
      :load_paths=>PATHS_TO_RAILS_STYLES_AND_COMPASS,...)

    puts Benchmark.measure { out << engine.render }
  end
end

As you can see, whether calling it from the bowels of rails or directly through a script, the load paths should be the same.

Of course I'm not 100% on top of how all this works, so there could be more to it that I don't get.

@scottdavis
Copy link

Right, but in sass-rails sass asks sprockets to find the file first and only until that search is exhausted does it search its own load path. Sprockets uses a gem called Hike to find dependent files. And we have noticed especially on the compass end of things that having a very large import stack makes HIke choke and it slows down a lot. For some more insight checkout this issue in this compass Compass/compass#516

This could also be a GC issue because when your running sass with rails your memory space is also going to be filled with rails if you want to verify this run some call graphs and you should see your process getting stuck in the Hike resolver or in the GC we have seen both appear in that thread above

@tmeasday
Copy link
Author

Ahh, right. Thanks Scott, that makes sense then. Probably this bug can be closed then.

@scottdavis
Copy link

I would actually leave it open and probe the sprockets guys to why the resolver is so slow. It is becoming a real issue in projects with large @imports

@Papipo
Copy link

Papipo commented Dec 24, 2011

In my case is not about the size of the imports, in fact my app is faster if I import compass and blueprint entirely instead of their separate parts. The problem is having lots of dirs on the assets_path because of gems that add stuff there.

@s1kx
Copy link

s1kx commented Jul 5, 2012

I have the same issue with just only zurb/foundation 3.0.1 (that uses compass-rails) in my Rails 3.2.6 project.

Everytime I change anything in an @import'ed file (to use mixins):

Compiled application.css  (7092ms)  (pid 19786)

@xdite
Copy link

xdite commented Jul 9, 2012

because foundation @import a lot of @base, and @base import whole @Compass. so it will be ultra slow ...

@knoopx
Copy link

knoopx commented Mar 4, 2013

Here is my take on this:

sass (3.2.6)
sass-rails (3.2.6)
compass (0.12.2)
compass-rails (1.0.3)
sprockets (2.2.2)
hike (1.2.1)

A request just after modifying application.css.sass generates the following profiling report: http://d.pr/f/MWfo
wich as you can see there's something really weird going on with Dir.open

Tried to debug that and then got this: https://gist.github.com/knoopx/5082439

It looks like everything is working properly (except some dup lookups) but I personally think that sprockets/sass integration is broken by design. @import directive should not delegate the lookup to sprockets or sprockets should be smart enough to figure an optimum lookup path.

Here are some design flaws that I suspect that are the culpable of our current performance issues:

  • For every @import directive we lookup both file and _file (Sass partial) through sprockets == 2x time

  • On a Sass file modification, something somehow flushes Sprockets/Hike lookup cache, causing it to re-glob all the load paths (including the gem-vendored ones, which hypothetically should never change)

  • Sprockets tries to locate Sass files on every gem-vendored javascript, stylesheet and image folders?¿?

  • Hike is not smart enough to skip already looked up directories or Hike::Index#entries memoization is not
    properly working. The above output was generated using this:

      @entries[key] ||= begin
        p "Hike::Index#entries(#{path})"
        Pathname.new(path).entries.reject { |entry| entry.to_s =~ /^\.|~$|^\#.*\#$/ }.sort
      end
    

@voondo
Copy link

voondo commented Jul 31, 2014

Are there any news about this issue ?

@josh josh closed this as completed Nov 24, 2014
@rails rails locked and limited conversation to collaborators Nov 24, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants