Project

skybolt

0.0
The project is in a healthy, maintained state
Reads the render-map.json generated by @skybolt/vite-plugin and outputs optimized HTML tags with intelligent caching via Service Workers.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies
 Project Readme

Skybolt Ruby

Ruby adapter for Skybolt - High-performance asset caching for multi-page applications.

Installation

Add to your Gemfile:

gem "skybolt"

Then run:

bundle install

Prerequisites

  1. Install and configure the Vite plugin: npm install @skybolt/vite-plugin
  2. Build your project: npm run build
  3. Ensure render-map.json is generated in your build output

Usage

require "skybolt"

sb = Skybolt::Renderer.new(
  "public/dist/.skybolt/render-map.json",
  cookies: request.cookies
)
<!DOCTYPE html>
<html>
<head>
    <%= raw sb.css("src/css/critical.css") %>
    <%= raw sb.launch_script %>
    <%= raw sb.css("src/css/main.css") %>
</head>
<body>
    <h1>Hello Skybolt!</h1>
    <%= raw sb.script("src/js/app.js") %>
</body>
</html>

API

Skybolt::Renderer.new(render_map_path, cookies: nil, cdn_url: nil)

Create a new Skybolt renderer.

  • render_map_path - Path to render-map.json generated by Vite plugin
  • cookies: - Cookie hash (defaults to nil)
  • cdn_url: - Optional CDN URL prefix (e.g., 'https://cdn.example.com')
# Basic usage
sb = Skybolt::Renderer.new(
  "public/dist/.skybolt/render-map.json",
  cookies: request.cookies
)

# With CDN
sb = Skybolt::Renderer.new(
  "public/dist/.skybolt/render-map.json",
  cookies: request.cookies,
  cdn_url: "https://cdn.example.com"
)

css(entry, async: false) -> String

Render CSS asset.

  • First visit: Inlines CSS with caching attributes
  • Repeat visit: Outputs <link> tag (Service Worker serves from cache)

When async: is true, CSS loads non-blocking:

  • First visit: Uses media="print" trick, swaps to all on load
  • Repeat visit: Uses <link rel="preload"> with onload
# Blocking (default) - for critical CSS
sb.css("src/css/critical.css")

# Non-blocking - for non-critical CSS
sb.css("src/css/main.css", async: true)

script(entry, is_module: true) -> String

Render JavaScript asset.

  • First visit: Inlines JS with caching attributes
  • Repeat visit: Outputs <script> tag (Service Worker serves from cache)
# ES module (default)
sb.script("src/js/app.js")

# Classic script
sb.script("src/js/legacy.js", is_module: false)

launch_script -> String

Render the Skybolt client launcher. Call once in <head> before other assets.

<head>
    <%= raw sb.launch_script %>
</head>

asset_url(entry) -> String?

Get the URL for an asset (for manual use cases).

url = sb.asset_url("src/css/main.css")
# "/assets/main-Pw3rT8vL.css"

asset_hash(entry) -> String?

Get the content hash for an asset.

hash = sb.asset_hash("src/css/main.css")
# "Pw3rT8vL"

preload(entry, as_type:, type: nil, crossorigin: nil, fetchpriority: nil) -> String

Render preload link for critical resources like fonts and images.

# Preload hero image with high priority
sb.preload("images/hero.jpg", as_type: "image", fetchpriority: "high")

# Preload font
sb.preload("fonts/inter.woff2", as_type: "font", type: "font/woff2", crossorigin: "anonymous")

# Preload a Vite-built asset (resolved from render-map)
sb.preload("src/css/main.css", as_type: "style")

Parameters:

  • entry - Source file path or direct URL
  • as_type: - Resource type ('image', 'font', 'style', 'script', 'fetch')
  • type: - MIME type (e.g., 'font/woff2', 'image/webp')
  • crossorigin: - Crossorigin attribute ('anonymous', 'use-credentials')
  • fetchpriority: - Fetch priority ('high', 'low', 'auto')

Service Worker Setup

The Service Worker must be served from your domain root. Configure your web server:

Nginx:

location = /skybolt-sw.js {
    alias /path/to/public/dist/skybolt-sw.js;
}

Apache (.htaccess):

RewriteRule ^skybolt-sw\.js$ public/dist/skybolt-sw.js [L]

Framework Integration

Rails

# app/helpers/skybolt_helper.rb
module SkyboltHelper
  def skybolt
    @skybolt ||= Skybolt::Renderer.new(
      Rails.root.join("public/dist/.skybolt/render-map.json").to_s,
      cookies: cookies.to_h
    )
  end
end
<%# app/views/layouts/application.html.erb %>
<!DOCTYPE html>
<html>
<head>
    <%= raw skybolt.css("app/assets/stylesheets/critical.css") %>
    <%= raw skybolt.launch_script %>
    <%= raw skybolt.css("app/assets/stylesheets/application.css") %>
</head>
<body>
    <%= yield %>
    <%= raw skybolt.script("app/javascript/application.js") %>
</body>
</html>

Sinatra

require "sinatra"
require "skybolt"

helpers do
  def skybolt
    @skybolt ||= Skybolt::Renderer.new(
      "public/dist/.skybolt/render-map.json",
      cookies: request.cookies
    )
  end
end

get "/" do
  erb :index
end
<%# views/index.erb %>
<!DOCTYPE html>
<html>
<head>
    <%= raw skybolt.css("src/css/critical.css") %>
    <%= raw skybolt.launch_script %>
    <%= raw skybolt.css("src/css/main.css") %>
</head>
<body>
    <h1>Hello Skybolt!</h1>
    <%= raw skybolt.script("src/js/app.js") %>
</body>
</html>

Hanami

# app/actions/home/index.rb
module MyApp
  module Actions
    module Home
      class Index < MyApp::Action
        def handle(request, response)
          sb = Skybolt::Renderer.new(
            "public/dist/.skybolt/render-map.json",
            cookies: request.cookies
          )
          response.render(view, sb: sb)
        end
      end
    end
  end
end

Requirements

  • Ruby 3.0+
  • Vite with @skybolt/vite-plugin

License

MIT