Fresco
An application framework for Ruby that compiles to a static binary via Spinel. Two modes from the same source tree:
- Dev: CRuby with auto-reload —
bin/dev. - Release: a single static binary, no Ruby on the host —
bin/releaseproducesbuild/app.
A build-time DSL (routes, schema, models, migrations) is captured under
CRuby and codegen'd into generated/. The generated tree is what Spinel
AOT-compiles for release; CRuby loads the same tree for dev.
For a runnable tour of the framework, see afomera/fresco-example.
Install
gem install fresco
Or in a Gemfile:
gem "fresco"
Requires Ruby >= 3.0 for the dev loop. The release binary has no Ruby
runtime dependency on the host machine.
Installing Spinel
fresco dev runs under CRuby and does not need Spinel. fresco
release shells out to a spinel binary to AOT-compile your app, so you
need Spinel installed before you ship a build.
Spinel doesn't ship a prebuilt binary today — clone and build it from source:
# Pick a checkout location. We'll symlink the resulting binary into your
# Fresco app, so anywhere on disk is fine.
git clone https://github.com/matz/spinel.git
cd spinel
make deps # fetch and build Spinel's vendored dependencies
make all # build the spinel binary
That produces a spinel executable in the repo root. fresco release
looks for it in this order:
./spinelin the Fresco app directory (symlink or copy)./vendor/spinel/bin/spinelspinelon$PATH
The simplest setup is a symlink at the app root:
cd path/to/your-fresco-app
ln -s /absolute/path/to/spinel/spinel ./spinel
.gitignore the symlink — the binary is per-machine.
macOS Postgres note
If your app uses the Postgres adapter, fresco release auto-detects
Homebrew's keg-only libpq (/opt/homebrew/opt/libpq,
/usr/local/opt/libpq) and Postgres.app, and prepends their
include/ and lib/ to CPATH / LIBRARY_PATH so Spinel's compile of
the libpq shim resolves libpq-fe.h and -lpq without manual export.
SQLite builds need no extra setup.
Quick start
fresco new bookshelf
cd bookshelf
bundle install
bin/dev
Open http://localhost:3030/.
To build a release binary:
ln -s /path/to/spinel/spinel ./spinel
bin/release
./build/app
Commands
fresco new <name> Scaffold a new app in ./<name>/
fresco build Regenerate generated/* from config + app/
fresco dev Run the CRuby dev loop (build + watch + serve)
fresco release Build a Spinel-compiled binary at ./build/app
The scaffolded app's bin/dev, bin/build, and bin/release are thin
wrappers around bundle exec fresco <subcommand>.
fresco new flags
--fresco-path <dir> Pin the generated Gemfile to a path-installed
fresco (useful when co-developing fresco itself).
App layout
A Fresco app generated by fresco new looks like:
app/
action.rb # base class
actions/ # request handlers
models/ # build-time model declarations
views/ # ERB templates (compiled at build time)
config/
app.rb # framework config
database.rb # adapter + DSN (omit for no DB)
routes.rb # route table
db/
schema.rb # table declarations
migrations/ # versioned SQL migrations
bin/
dev, build, release # wrappers for `bundle exec fresco …`
app.rb # Spinel entry point
generated/ and build/ are produced by the toolchain and should be
gitignored.
How dev and release stay in sync
Both modes load the same generated/ tree. fresco dev re-runs the
build step on file changes; fresco release runs it once and hands the
result to Spinel. There is no separate "production codepath" to drift —
if a route works in dev, it works in the compiled binary (modulo Spinel's
Ruby subset, which rubocop_spinel lints for at build time when present
in your Gemfile).
Development of the gem itself
bundle install
bundle exec rake build # → pkg/fresco-<version>.gem
bundle exec rake install # build + install locally
bundle exec rake release # tag + push to rubygems.org
When iterating on fresco alongside an app, scaffold the app against
your working copy:
fresco new myapp --fresco-path ../fresco
License
MIT.