Server-Side Rendering
Inertia Rust supports server-side rendering. Enabling SSR gives your website better SEO, since the very first page will be server-side rendered. Thereafter, they’ll be ordinary SPA pages.
Note: Node.js must be available in order to run the Inertia SSR server.
Enabling SSR is a very simple task. However, you must make few changes in your code so that the Node.js process is correctly iniitialized and killed — otherwise, the Node.js process would be left running, stopping further servers from running on the port it occupies.
First of all, enable SSR in your Inertia configs:
// src/config/inertia.rs
use super::vite::initialize_vite;
use inertia_rust::{
template_resolvers::ViteHBSTemplateResolver, Inertia, InertiaConfig, InertiaError,
- InertiaVersion,
+ InertiaVersion, SsrClient
};
use std::io;
pub async fn initialize_inertia() -> Result<Inertia, io::Error> {
let vite = initialize_vite().await;
let version = vite.get_hash().unwrap_or("development").to_string();
let dev_mode = *vite.mode() == ViteMode::Development;
let resolver = ViteHBSTemplateResolver::builder()
.set_vite(vite)
.set_template_path("www/root.hbs") // the path to your root handlebars template
.set_dev_mode(dev_mode)
.build()
.map_err(InertiaError::to_io_error)?;
Inertia::new(
InertiaConfig::builder()
.set_url("http://localhost:3000")
.set_version(InertiaVersion::Literal(version))
.set_template_resolver(Box::new(resolver))
+ .enable_ssr()
+ // `set_ssr_client` is optional. If not set, `SsrClient::default()` will be used,
+ // which is is "127.0.0.1:13714"
+ .set_ssr_client(SsrClient::new("127.0.0.1", 1000))
.build(),
)
}
// src/main.rs
use std::sync::{Arc, OnceLock};
use actix_web::{dev::Path, web::Data, App, HttpServer};
use config::inertia::initialize_inertia;
mod config;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenvy::dotenv().ok();
env_logger::init();
// starts a Inertia manager instance.
let inertia = initialize_inertia().await?;
let inertia = Data::new(inertia);
+ let inertia_clone = inertia.clone();
- HttpServer::new(move || App::new().app_data(inertia.clone()))
- .bind(("127.0.0.1", 3000))?
- .run()
- .await
+ let server = HttpServer::new(move || App::new().app_data(inertia_clone.clone()))
+ .bind(("127.0.0.1", 3000))?;
+ // Starts a Node.js child process that runs the Inertia's server-side rendering server.
+ // It must be started after the server initialization to ensure that the http server won't
+ // panic and shutdown without killing the Node.Js process.
+ let node = inertia.start_node_server("path/to/your/ssr.js".into())?;
+
+ let server = server.run().await;
+ let _ = node.kill().await;+
+
+ return server;
}
Indeed, you can replace let _ = node.kill().await;
with std::mem::drop(node.kill())
, but .await
ing on it
guarantees that the process has been killed before shutting down.
Inertia always inserts a view data property isSsr
(or even is_ssr
), which is a boolean value representing
if the page has been server-side rendered or not.
You might use it on your app.tsx
to conditionally hydrate or create your front-end according to the
response being or not SSRendered.
Add the following meta tag on your root template’s head
element:
<meta name="ssr" content="{{ view_data.is_ssr }}">
Then, in your app.ts|js|tsx|jsx
file, add the follow condition:
import "./app.scss";
import { createInertiaApp } from "@inertiajs/react";
import { createRoot, hydrateRoot } from "react-dom/client";
createInertiaApp({
// ...
setup({ el, App, props }) {
const isSSR = document.head
.querySelector("meta[name='ssr']")?
.getAttribute("content") === "true" ?? false;
if (isSSR) {
hydrateRoot(el, <App {...props} />);
return;
}
createRoot(el).render(<App {...props} />);
},
});