Skip to content

Instantly share code, notes, and snippets.

@andyjeffries
Last active December 18, 2015 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andyjeffries/5806113 to your computer and use it in GitHub Desktop.
Save andyjeffries/5806113 to your computer and use it in GitHub Desktop.

Asset Compilation Options

The Problem

The problem at the moment stems from the fact that the frontend assets are developed in this style:

.foo {
  background: url(../img/bar.png);   /* Sometimes ../images/ */
}

but Rails expects them to be like this:

.foo {
  background: image-url("bar.png");
}

The reason is that Rails contains an "Asset Pipeline" and assets (images, css, js, fonts) go through a compilation stage when deploying for production use (and this is handled dynamically in development mode). So an asset named img/bar.png will be converted in to a URL like http://host3.my-asset-host.com/assets/bar-892389032abcd8367928.png.

This enables Apache/whatever to set a really long expiry time (1 year is common) on all image/*, text/css and text/javascript files because if the content changes then the hash on the end of the converted URL will be completely different.

As things stand we have the current options:

  1. Develop things in the frontend framework as they are, but it breaks Rails :-(

  2. Develop things in the frontend as they are, but then override each rule that is "broken" (from Rails point of view) with a Rails-style declaration

  3. After bower-installing the assets in to Rails, "fix" each 'broken' declaration so that it works, causing this step to be repeated after each bower-install

These are the simple options. There are two other options.

The Simple Option

We could combine all CSS files that are bowerised (forming a mega-package) and likewise for all JS and host them all on http://(staticwhich|cloudfront|cloudfiles)/v1.0.1/assets/mega.css, including images, fonts, etc and the combined mega packages would only use absolute URLs to that paths within that asset host (no ../).

Each application would then set a asset prefix for including CSS/JS from the asset host that includes the version number they are tested against. Each application is then also allowed one single HTTP request for each of application-IDENTIFIER/HASH.css and application-IDENTIFIER/HASH.js, but these should also be pushed to the asset host.

This means that all assets can use long expiries (as they have either a vX.Y.Z string or an IDENTIFIER/HASH in the URL), there are no relative paths to break things and things are much simpler for application developers.

In fact: if absolute URLs are used to the asset host instead of url(../*) then this goes away anyway...?

The SASS Variable Option

Instead of using relative paths to assets within the CSS files, declare a SASS variable at the top for the asset folder in use, such as:

$imageFolder: "../img/" !default;

.foo {
  background: url("#{$imageFolder}bar.png");
}

This would be set to /assets/ for Rails applications in the application.css.scss before any other includes, taking in to account that all assets are available under /assets, abusing the fact that Rails assets are compiled once with a -IDENTIFIER/HASH suffix and one without.

They lose the ability to have long cache expiry times as they no longer have a unique identifier in the URL.

The Pseudo-Asset Pipeline Helper Option

Each developer could define a function like this within their SCSS files:

@function image-url($value){
  @return url("../img/#{$value}");
}

However, the problem is that this overrides Rails functionality (which is run after sass compilation). So this would somehow need to be inserted for non-Rails projects in a way that doesn't break Rails…

Haven't yet had any ideas on how to achieve this...

@danielepolencic
Copy link

@marrs
Copy link

marrs commented Jun 19, 2013

image-url() looks good with the caveat that things break if someone forgets to use it. We could abstract the call to image-url() providing we can detect rails as a predicate. This may be possible depending on how rails compiles the sass files.

The other option I see is to put a step in front of rails in the compile pipeline that replaces all relative URLS with absolute URLs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment