Compass / compass-rails

compass rails integration
MIT License
591 stars 276 forks source link

Only first sprite is compiled on initial asset compilation in Rails 4 #94

Closed agrobbin closed 10 years ago

agrobbin commented 11 years ago

This is one of the weirdest bugs I've ever run into, and unfortunately I can't seem to track down the exact line that is causing the problem, but here goes the explanation.

We have an application that is using Rails 4.0 and the newly released 2.0.alpha.0 version of compass-rails. Everything seems to be working great, including spriting, except for one problem. On initial asset compilation (when the sprite map images and the tmp/cache/assets folder don't exist), only the first sprite image is sourced correctly in the compiled css.

For example, if you have 2 sprited folders, app/assets/images/sprite1 and app/assets/images/sprite2, and the first sprite that you request (in, say, app/assets/stylesheets/a.css.scss) is sprite1, the asset_url generations for that sprite is done correctly as url(/assets/sprite1-s1234567890.png). However, when sprite2 is requested, the asset_url is generated as url(/sprite2-s1234567890.png).

Now, if you change a stylesheet and force assets to recompile themselves (by refreshing the page perhaps), then all sprite URLs are generated correctly. So this only appears to a problem when you are first compiling assets the first time.

We can get around this by only having 1 sprite map instead of multiple, but the problem was definitely a weird one to debug.

I hope this is clear!

geniou commented 11 years ago

I have a very similar weird behavior/bug, with only one sprite: the first time the sprite is generated the path in the CSS points to url(/sprite-s8f1db3ceda.png) - after this its always correct: url(/assets/sprite-s8f1db3ceda.png)

I can easy reproduce this:

  1. deleting the sprite and the tmp/cache/ folder
  2. make a change to a stylesheet file
  3. sprite url is incorrect
  4. make another change to a stylesheet file
  5. sprite url is correct

It would not bother me, if it would not brake the tests, because they are always generating the sprite for the first time and so failing be requesting the sprite on the wrong location.

Has anybody an idea?

scottdavis commented 11 years ago

I haven't had time to finish looking into this but if someone wants to look into it and send a pull request ill look into it.

Sent from my iPhone

On Aug 20, 2013, at 11:37 AM, Nils notifications@github.com wrote:

I have a very similar weird behavior/bug, with only one sprite: the first time the sprite is generated the path in the CSS points to url(/sprite-s8f1db3ceda.png) - after this its always correct: url(/assets/sprite-s8f1db3ceda.png)

I can easy reproduce this:

  1. deleting the sprite and the tmp/cache/ folder
  2. make a change to a stylesheet file
  3. sprite url is incorrect
  4. make another change to a stylesheet file
  5. sprite url is correct

It would not bother me, if it would not brake the tests, because they are always generating the sprite for the first time and so failing be requesting the sprite on the wrong location.

Has anybody an idea?

— Reply to this email directly or view it on GitHub.

xaph commented 11 years ago

I've the same problem.

I'm using these versions:

Rails 4.0.0 compass-rails (rails4 branch) c86e7fd9c2605c80816a2f64a3fb8b7c3a09e494 compass 0.12.2

My images folder is at public/images When i create a sprite from public/images/leagues/ folder it creates leagues-s10d7ea8375.png sprite but it gives me url: url(/leagues-s10d7ea8375.png)

I couldn't get any correct output :(

DonSchado commented 11 years ago

we have the same problem @geniou mentions. I can also reproduce this in development and the specs are failing on travis because the url is wrong. Any workarounds for this?

geniou commented 11 years ago

@DonSchado a workaround we use is to check in the sprite - if the sprite is there the CSS files are generated properly and travis is working fine. It's not nice - but it's working for now.

xaph commented 11 years ago

@geniou I made all the things you said but I still can't get correct sprite url. What should I do? Should I use generated sprite with overriding url? Or do you have another solution?

geniou commented 11 years ago

@xaph strange! So the URL in the sprite always without the /assets - even the second time?

xaph commented 11 years ago

@geniou yes I couldn't create a sprite url with /assets/ prefix :(

fourseven commented 11 years ago

I'm looking into this now, the first time the sprite is made the call to assets_digest_path(path) returns nil, where as on future invocations it returns the cached and digested version https://github.com/rails/sprockets-rails/blob/18026870bb5fde945802674fb5b88be976ff6b94/lib/sprockets/rails/helper.rb#L40. So for some reason sprockets doesn't know about the spritesheet until it's invoked for a second time. Why, I'm not yet sure.

fourseven commented 11 years ago

More digging - I found that the cache was not finding the generated spritesheet but resetting the Hike::Index that sprockets uses then fixes it. I then found the on_sprite_saved function - https://github.com/Compass/compass-rails/blob/aea69635f6000bbc7180f7fdd0ce216f904db30d/lib/compass-rails/railties/4_0.rb#L36-L83 - which was doing exactly that. It's not being called on my system though.

fourseven commented 11 years ago

Alright the problem appears to be around the sprockets context, which is initialized when the spritesheet is compiled and has an internal @trail variable which is actually a caching Hike::Index. Since it's cached and used before the sprite is written the newly generated spritesheet not found on first load.

The cache-busting method that is in the railties file does not apply to development mode, because Rails.application.config.assets.digest (one of the conditionals) is usually false - and there's not enough access to the context there anyway. I've done the following on a branch which fixes the problem, replacing this with the following:

def generated_image_url(path, only_path = nil)
  options[:sprockets][:environment].send(:trail).instance_variable_get(:@entries).delete(File.join(Rails.root, Compass.configuration.generated_images_dir))
  asset_url(path)
end

I really don't like it, but is the only place that I could get access to the sprockets_context and bust that cache. Open to better ideas.

scottdavis commented 11 years ago

@fourseven I don't know if there is going to be a "better idea" unless sprockets finally adds support for this. We have bugged them in the past but it seems to fall on def ears. Getting access to the context seems to be the bane of my existence.

fourseven commented 11 years ago

Okay, thanks for that @scottdavis, in that case I'll setup a pull request shortly - I know exactly what you mean by it being a P.I.T.A.

DonSchado commented 11 years ago

:+1:

arctarus commented 11 years ago

I had the same problem. Anybody knows when will be this issue solved?

Thanks!

john-griffin commented 11 years ago

@fourseven's fork works great here.

arctarus commented 11 years ago

I installed that fork in my application but it generate routes like /assets/userstats-scaa1654a4b-342aedfbf21efe3bf16a1aaeb3cba753.png instead of /assets/userstats-scaa1654a4b.png

You have any idea what could be the problem?

Thanks very much @john-griffin.

john-griffin commented 11 years ago

@arctarus yes we get long asset paths but it's loaded via normal sprite helpers. As the image url is not referenced directly I don't see a problem.

arctarus commented 11 years ago

Sorry @john-griffin but the problem is not the long path. What I mean is when I use the sprites generator in my scss like:

@import "headernav/*.png";
@include all-headernav-sprites;

What I get is:

.headernav-sprite, .headernav-home, .headernav-route, .headernav-settings, .headernav-users {
   background: url(/assets/headernav-s822f4351c6-3171f45112439a44e4c2d5806dc9a7fb.png) no-repeat;
}

As you can see the url is /assets/headernav-s822f4351c6-3171f45112439a44e4c2d5806dc9a7fb.png whereas it should be is /assets/headernav-s822f4351c6.png so I can't see the sprites in the page.

I don't understand why is added the second part -3171f45112439a44e4c2d5806dc9a7fb in the path, I have to change some configuration params o something like that?

Thanks very much @john-griffin!

agrobbin commented 10 years ago

We still seem to be running into this issue even after upgrading to compass-rails 1.1.1.

craigmcnamara commented 10 years ago

This is addressed in pull #112 and discussed in #100.

If someone having the problem verifies this patch I'll cut and release a new gem.

craigmcnamara commented 10 years ago

Has this been an issue in older versions of Rails?

craigmcnamara commented 10 years ago

I merged this in and cut a gem because it seems like the problem is widespread and I couldn't see any harm in my rails 4 apps.

Gem 1.1.2 is out.

agrobbin commented 10 years ago

So far this seems to be fixed, thanks @craigmcnamara !

geniou commented 10 years ago

Its working for us - thank a lot!

jgillman commented 10 years ago

@arctarus I'm having the same issue as you. The compiled CSS points to a file named (for example) sprite-s822f4351c6-3171f45112439a44e4c2d5806dc9a7fb.png but the name of the actual file is sprite-s822f4351c6.png so the request 404s.

I'm currently using a 2.0.0.pre ab84a09c0b.

vincentwoo commented 10 years ago

@craigmcnamara, I'm still seeing this problem on the latest compass-rails (1.1.7).

The first set of sprites on a page refer to the correct path: /assets/factory/utilities-s1bdc40f9fd.png, for instance.

However, any other sprites on the page lack the /assets path: /factory/flags-sdd3071a5cf.png

Other relevant gem versions we're on:

rails (4.0.4)
sass (3.2.19)
sass-rails (4.0.3)
sprockets (2.11.0)
sprockets-rails (2.0.1)

Edit:

Additionally, this only occurs when the sprites are generated for the first time. If I leave the compiled sprites in the filesystem, clear out tmp/cache, and restart my server, the newly generated CSS points at the correct location.

cc @bsturdivan

alexkravets commented 9 years ago

Issue still exists in

compass-rails (2.0.0)
rails (4.1.7)
dmeremyanin commented 9 years ago

190 fixes that behaviour, but it has not been reviewed yet.