crystal-inertia v0.1.1
crystal-inertia
Inertia.js integration for Crystal (experimental)
This shard simplifies the integration of Inertia.js with Crystal applications, encouraging convention over configuration and without dependencies on external libraries or frameworks.
[!WARNING] This project is experimental and not all the features defined by Inertia.js protocol have been implemented.
Sharing this for others to explore and perhaps continue to develop it.
Features
- Not tied to any framework, just plain
HTTP::Server::Context
. - Flexible templating rendering options, allowing to use any library, like ECR.
Usage
Setup your own renderer
For the non-Inertia requests, is necessary to render an HTML response. You can implement your own by including Inertia::Renderer
module and implementing the render
method:
class MyRenderer
include Inertia::Renderer
def render(inertia : Inertia, context : HTTP::Server::Context, locals)
# Extract the page data (already JSON-encoded)
page_data = HTML.escape(locals[:page])
# Set content type and write HTML response
context.response.content_type = "text/html"
context.response << <<-HTML
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<script src="/assets/app.js"></script>
</head>
<body>
<div id="app" data-page='#{page_data}'></div>
</body>
</html>
HTML
end
end
Now you can use this renderer in your Inertia instance:
inertia = Inertia.new(version: "1.0.0", renderer: MyRenderer.new)
Connect Inertia to your HTTP Server
Inertia.js requires that certain types of requests are handled differently than normal applications. Eg. Redirection after PUT, PATCH or DELETE requires 303 (See Other) instead of regular 301 or 302 status codes.
In order to do that, this project provides an HTTP handler that can be added to your server middleware stack:
inertia = Inertia.new(version: "1.0.0", renderer: MyRenderer.new)
server = HTTP::Server.new([
HTTP::ErrorHandler.new,
HTTP::LogHandler.new,
inertia.http_handler,
])
server.bind_tcp("0.0.0.0", 3000)
server.listen
Note that this handler must be before your application handler, so it can process the responses sent by it.
A minimal example
The following example shows a naive implementation of the routing for an application:
inertia = Inertia.new(version: "1.0.0", renderer: MyRenderer.new)
handlers = [
HTTP::LogHandler.new,
# to serve files from `public` directory
HTTP::StaticFileHandler.new("public", directory_listing: false),
inertia.http_handler,
]
server = HTTP::Server.new(handlers) do |context|
case context.request.path
when "/"
next inertia.render(
context,
component: "Home",
props: { title: "Home" }
)
when "/about"
next inertia.render(
context,
component: "About",
props: {
title: "About",
user: {
id: 1,
name: "John Doe",
email: "john@example.com"
}
}
)
end
end
server.bind_tcp("0.0.0.0", 8080)
server.listen
It now remains for you to implement in the frontend stack of your choice (React, Vue, Svelte), the necessary logic. Refer to Inertia.js' client-side documentation for more information.
Missing features
A lot:
- Share data on all requests.
- Partial reloads (Eg. only, except, lazy)
- Deferred props
- Merging props
If you're interested in implementing one of those features, please open an issue to discuss it, so others see it to either collaborate with you or to avoid duplication of effort.
License
Licensed under the Apache License, Version 2.0. You may obtain a copy of the license here.
crystal-inertia
- 0
- 0
- 0
- 1
- 0
- 3 days ago
- May 29, 2025
Apache License 2.0
Tue, 03 Jun 2025 16:17:17 GMT