Skip to content

Instantly share code, notes, and snippets.

@ilpoldo
Created March 9, 2010 14:18
Show Gist options
  • Select an option

  • Save ilpoldo/326616 to your computer and use it in GitHub Desktop.

Select an option

Save ilpoldo/326616 to your computer and use it in GitHub Desktop.
metal-based asset packagers
require 'jsmin'
require 'fileutils'
require 'benchmark'
module JavascriptMinifier
class NotFound < StandardError; end
class Responder
@asset_folder = "#{Rails.root}/public/javascripts"
@cache_folder = "#{Rails.root}/tmp/asset_cache"
@cached = []
def self.asset_folder=(path)
@asset_folder = path
end
def self.cache_folder=(path)
@cache_folder = path
end
def self.call(env)
bundle = Array(env["PATH_INFO"].match(/^\/javascripts\/(.*).js/))[1]
case Rails.env
when 'production'
#TODO: deal with etag headers/cachebusters
if @cached.include? bundle
@cache_server.call(env)
else
prepare bundle
@cache_server.call(env)
end
else
serve files_for(bundle)
end
rescue NotFound
[404, {"Content-Type" => "text/html"}, ["Not Found"]]
end
# Loads asset files inside the <bundle_name> folder in order:
# 1.javascripts contained in <bundle_name>/base
# 2.javascripts contained in <bundle_name>/pugins
# 3.javascripts contained in the <bundle_name> folder
def self.files_for(bundle)
raise NotFound unless File.exists? File.join(@asset_folder, bundle)
assets = []
Dir.chdir File.join(@asset_folder, bundle) do
assets += Dir.glob('base/*.js')
assets += Dir.glob('plugins/*.js')
assets += Dir.glob('*.js')
assets.map! {|p| File.expand_path p}
end
assets
end
# Reads each asset file in order and sends back the content
def self.serve(assets)
content = ""
assets.each do |f|
content << File.read(f)
end
[200, {"Content-Type" => "text/javascript", "Content-Length" => "#{content.bytesize}"}, [content]]
end
# Compresses the javascript and instantiates the rack server to serve the cached copy
def self.prepare(bundle)
cache_file = File.join(@cache_folder, 'javascripts', "#{bundle}.js")
@cache_server ||= cache_server
script = files_for(bundle).inject('') do |s, f|
s << File.read(f)
end
File.open(cache_file, "w") { |f| f.puts JSMin.minify(script) }
@cached << bundle
end
def self.cache_server
FileUtils.mkdir_p File.join(@cache_folder, 'javascripts')
rack_file = Rack::File.new(@cache_folder)
lambda do |env|
code, header, body = rack_file.call(env)
[code, header.merge('Content-Type' => 'text/javascript'), body]
end
end
end
def self.call(env)
response = nil
js_runtime = Benchmark.ms {response = Responder.call(env)}
Rails.logger.debug("Completed #{response.first} in %.1fms" % js_runtime)
response
end
end
# Allow the metal piece to run in isolation
require(File.dirname(__FILE__) + "/../../config/environment") unless defined?(Rails)
require 'fileutils'
Sass::Plugin.options[:check_for_updates] = false
module SassCompiler
class Responder
class NotFound < StandardError; end
class CompileError < StandardError; end
@asset_folder = "#{Rails.root}/public/stylesheets"
@cache_folder = "#{Rails.root}/tmp/asset_cache"
@cached = []
def self.asset_folder=(path)
@asset_folder = path
end
def self.cache_folder=(path)
@cache_folder = path
end
def self.call(env)
asset = Array(env["PATH_INFO"].match(/^\/stylesheets\/(.*).css/))[1]
if Rails.env != 'development' and @cached.include? asset
@cache_server.call(env)
else
sass_compile asset
@cache_server.call(env)
end
rescue NotFound
[404, {"Content-Type" => "text/html"}, ["Not Found"]]
rescue CompileError => e
[500, {"Content-Type" => "text/plain"}, [e.inspect]]
end
# Renders the sass files in the cache and instances an app to serve them
def self.sass_compile(asset_name)
asset = File.join(@asset_folder, "#{asset_name}.scss")
raise NotFound unless File.exists? asset
@cache_server ||= cache_server
css = File.join(@cache_folder, 'stylesheets', "#{asset_name}.css")
File.delete(css) if File.exists?(css)
begin
render_style = Rails.env == 'development' ? :nested : :compressed
sass = Sass::Files.tree_for asset, :cache => true,
:cache_location => File.join(@cache_folder, '.sass_cache'),
:template_location => @asset_folder,
:load_paths => compass_paths,
:css_filename => css,
:filename => asset,
:style => render_style
File.open(css, 'w') {|f| f << sass.render}
# rescue Exception => e
# raise CompileError(e)
end
@cached << asset_name
end
# Ensures a cache folder exists and instantiates the app to serve it.
def self.cache_server
FileUtils.makedirs File.join(@cache_folder, 'stylesheets')
Rack::File.new(@cache_folder)
end
def self.compass_paths
Compass::Frameworks::ALL.map {|framework| framework.stylesheets_directory if File.exists?(framework.stylesheets_directory)}
rescue NameError
[]
end
end
def self.call(env)
response = nil
sass_runtime = Benchmark.ms {response = Responder.call(env)}
Rails.logger.debug("Completed #{response.first} in %.1fms" % sass_runtime)
response
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment