Last active
March 5, 2018 12:16
-
-
Save manuelmeurer/2214445 to your computer and use it in GitHub Desktop.
How to compile custom Sass stylesheets during runtime
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# lib/store_stylesheet.rb | |
class StoreStylesheet | |
def initialize(store) | |
@store = store | |
end | |
# The path of the compiled stylesheet, i.e. stores/id_timestamp.css | |
def stylesheet_file | |
filename = [ | |
@store.id, | |
@store.updated_at.to_s(:number) | |
].join('_') | |
File.join \ | |
'stores', | |
"#{filename}.css" | |
end | |
# The path of the uncompiled Sass file, i.e. /path/to/app/app/assets/stylesheets/stores/id_timestamp.css.scss | |
def sass_file_path | |
Rails.root.join('app', 'assets', 'stylesheets', "#{self.stylesheet_file}.scss") | |
end | |
# The styles which are rendered through app/views/stores/styles.scss.erb | |
# You can supply local variables which can be accessed in the style view. | |
def styles | |
StoresController.new.render_to_string 'styles', | |
formats: [:scss], | |
layout: false, | |
locals: { store: @store } | |
end | |
# Check if this stylesheet has been compiled or needs to be recompiled | |
def compiled? | |
if Rails.application.config.assets.compile | |
# If assets are compiled dynamically, check if the Sass file exists and is not empty | |
File.exists?(self.sass_file_path) && !File.zero?(self.sass_file_path) | |
else | |
# Otherwise check if the digested file is registered as an asset | |
Rails.application.config.assets.digests[self.stylesheet_file].present? | |
end | |
end | |
def compile | |
# Compile app/views/stores/styles.scss.erb into app/assets/stylesheets/stores/id-timestamp.css.scss | |
File.open(self.sass_file_path, 'w') { |f| f.write(self.styles) } | |
# Create and register digested file only if assets are not compiled dynamically | |
unless Rails.application.config.assets.compile | |
# Use Sprockets::Environment instead of Sprockets::Index to find the dynamically created asset. | |
# Rails.application.assets might be a Sprockets::Index (in production) or a Sprockets::Environment (in development) | |
# We need to access the Sprockets::Environment to find the file that was just compiled. Sprockets::Index caches everything and wouldn't find this file. | |
# TODO: Is there an easier way to access the Sprockets::Environment? | |
env = Rails.application.assets.is_a?(Sprockets::Index) ? Rails.application.assets.instance_variable_get('@environment') : Rails.application.assets | |
# Compile asset | |
Sprockets::StaticCompiler.new( | |
env, | |
File.join(Rails.public_path, Rails.application.config.assets.prefix), | |
[self.stylesheet_file], | |
digest: true, | |
manifest: false | |
).compile | |
# Register digested file as an asset | |
Rails.application.config.assets.digests[self.stylesheet_file] = env[self.stylesheet_file].digest_path | |
end | |
# Delete old files | |
Dir[self.sass_file_path.sub(/\d+.css.scss$/, '*')].each do |file| | |
File.delete file unless file == self.sass_file_path.to_s | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/views/layouts/stores.html.haml | |
# This could be in the application layout or somewhere else instead, depending on your app. | |
-# Compile the stylesheet if necessary | |
- store_stylesheet = StoreStylesheet.new(@store) | |
- store_stylesheet.compile unless store_stylesheet.compiled? | |
-# At this point you can access your compiled stylesheet. | |
-# You can either render it directly on the page or reference it via stylesheet_link_tag | |
-# The latter can only be done if you're serving assets directly via your app. | |
-# If you use the AssetSync gem or similar to upload your assets to S3, you should render it inline because it hasn't been uploaded. | |
-# Render on page: | |
-# Again, use Sprockets::Environment instead of Sprockets::Index to find the dynamically created asset. | |
- env = Rails.application.assets.is_a?(Sprockets::Index) ? Rails.application.assets.instance_variable_get('@environment') : Rails.application.assets | |
= env[store_stylesheet.stylesheet_file].to_s.html_safe | |
-# Reference: | |
= stylesheet_link_tag store_stylesheet.stylesheet_file |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/views/stores/styles.scss.erb | |
# Use Sass and ERB in here (local variables can be supplied by StoreStylesheet#styles) | |
@import "compass/css3"; | |
@import "fancy-buttons"; | |
$gray: #ccc; | |
.store { | |
background-color: $gray; | |
&[data-id="<%= store.id %>"] { | |
background-color: <%= store.background_color %>; | |
button { | |
@include fancy-button(<%= store.button_color %>, 16px, 0.5em); | |
} | |
} | |
} |
This method doesn't work anymore (probably with Sprockets > 2.0). This worked for me: http://matteodepalo.github.io/blog/2013/01/31/how-to-create-custom-stylesheets-dynamically-with-rails-and-sass/
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See here for the blog post: http://www.krautcomputing.com/blog/2012/03/27/how-to-compile-custom-sass-stylesheets-dynamically-during-runtime/