How do I use Sprockets with Sinatra without a rackup file?

rack, sinatra, sprockets

Solution

I ended up doing it by writing a custom middleware with some of the functionality from `Rack::URLMap`. It looks roughly like this:

require "sprockets"
require "sinatra/base"

class SprocketsMiddleware
  attr_reader :app, :prefix, :sprockets

  def initialize(app, prefix)
    @app = app
    @prefix = prefix
    @sprockets = Sprockets::Environment.new

    yield sprockets if block_given?
  end

  def call(env)
    path_info = env["PATH_INFO"]
    if path_info =~ prefix
      env["PATH_INFO"].sub!(prefix, "")
      sprockets.call(env)
    else
      app.call(env)
    end
  ensure
    env["PATH_INFO"] = path_info
  end
end

class App < Sinatra::Base
  use SprocketsMiddleware, %r{/assets} do |env|
    env.append_path "assets/css"
    env.append_path "assets/js"
  end
end

App.run!

Problem

I'm writing a library that has an embedded Sinatra app launched via Thor. I want to mount instances of `Sprockets::Environment` at `/css` and `/js` and have the main app mapped to `/`. This would be easy using `Rack::URLMap` in a `config.ru` file, but in this case there isn't one because I'm starting the Sinatra app programmatically with `Sinatra::Application.run!`. How can I achieve this?

Original source