Introduction
There's this category of web framework called "static-site generators", or "SSGs" for short. We, as developers, use them because it's easier than the alternative: writing a regular server, then launching it, mirroring the contents using some arcane wget
incantation, and shutting it back down afterward.
But while SSGs eliminate this particular hassle, they come with their own: they require you to organize everything their own persnickety way; they don't follow common web-development practices; you have to write special plugins for them if you want to use any templating library or database adapter or whatever else that would "just work" anywhere else. It's almost less work to use wget
.
rackstatic
cuts this Gordian knot. Using rackstatic
, you can develop your static website in, say, Sinatra, or any other Rack-compatible web framework (yes, even Rails, if you really really want.) And it's just as easy as using an SSG.
Here's the deal:
$ gem install rackstatic
$ cd your_rack_app/
$ rackstatic dist/
A static mirror-copy of your website will now exist under your_rack_app/dist/
.
If your repo is laid out such that your application files (config.ru
et al) exist under your_repo/app/
, you can build from above it to keep things clean and separate:
$ gem install rackstatic
$ cd your_repo/
$ rackstatic dist/
This will use the app in your_repo/app/
to build your_repo/dist/
.
How does it work?
rackstatic
uses the mock Rack session functionality of rack-test. Except, not so much for testing 😀. Instead, the response bodies returned in each mock request are written to disk, then spidered (using nokogiri for parsing) to find more URLs to request.
What about static files?
Some files aren't linked anywhere: robots.txt
, crossdomain.xml
, favicon.ico
, and so forth. A regular spidering-based mirroring process would miss these.
To prevent this, rackstatic
will attempt to request anything it sees under your_rack_app/public/
(e.g. your_rack_app/public/robots.txt
⇒ GET /robots.txt
), as if they had been linked to. You can change what subdirectory of your app is looked under using the -s
switch:
$ rackstatic -s static/ dist/
Recommendedations
You should add rackstatic
to your Gemfile. Then, when you pull down your app from its repo, building it is as simple as:
$ bundle install
$ bundle exec rackstatic dist/
You can also add a deploy task to your Rakefile that calls rackstatic
. Rather than messing with shell commands, try the Rack::StaticBuilder
API:
task :deploy => [:build]
task :build do
require 'rack/static-builder'
begin
Rack::StaticBuilder.new(:app_dir => 'app/', :dest_dir => 'dist/').build!
rescue Rack::StaticBuilder::BuildError
fail "one or more resources returned a non-2XX status"
end
end