{"id":29198158,"url":"https://github.com/valerioageno/ssr-rs","last_synced_at":"2025-07-02T08:41:21.532Z","repository":{"id":43634855,"uuid":"360981565","full_name":"Valerioageno/ssr-rs","owner":"Valerioageno","description":"Server side rendering on rust servers using the v8 engine for parse and evaluate the javascript code.","archived":false,"fork":false,"pushed_at":"2025-05-09T16:00:51.000Z","size":5584,"stargazers_count":198,"open_issues_count":1,"forks_count":15,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-06-28T13:39:45.176Z","etag":null,"topics":["actix-web","javascript","react","reactjs","render","rust","rust-servers","rust-ssr","server-side-rendering","ssr","v8-engine"],"latest_commit_sha":null,"homepage":"https://docs.rs/ssr_rs","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Valerioageno.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE_APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-23T19:06:47.000Z","updated_at":"2025-06-27T19:37:18.000Z","dependencies_parsed_at":"2023-12-31T11:26:01.496Z","dependency_job_id":"3f63e481-b788-4714-9e11-b1fe0db10b46","html_url":"https://github.com/Valerioageno/ssr-rs","commit_stats":{"total_commits":67,"total_committers":4,"mean_commits":16.75,"dds":0.07462686567164178,"last_synced_commit":"09a13e0efa8ab01ed8c398b239c32dfe7ca35cff"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/Valerioageno/ssr-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Valerioageno%2Fssr-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Valerioageno%2Fssr-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Valerioageno%2Fssr-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Valerioageno%2Fssr-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Valerioageno","download_url":"https://codeload.github.com/Valerioageno/ssr-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Valerioageno%2Fssr-rs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263106035,"owners_count":23414773,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actix-web","javascript","react","reactjs","render","rust","rust-servers","rust-ssr","server-side-rendering","ssr","v8-engine"],"created_at":"2025-07-02T08:41:20.862Z","updated_at":"2025-07-02T08:41:21.510Z","avatar_url":"https://github.com/Valerioageno.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🚀 Rust server side rendering\n\n[![API](https://docs.rs/ssr_rs/badge.svg)](https://docs.rs/ssr_rs)\n[![codecov](https://codecov.io/gh/Valerioageno/ssr-rs/branch/main/graph/badge.svg?token=O0CZIZAR7X)](https://codecov.io/gh/Valerioageno/ssr-rs)\n\nThe crate aims to enable server side rendering on rust servers in the simplest and lightest way possible.\n\nIt uses an embedded version of the [V8](https://v8.dev/) javascript engine (\u003ca href=\"https://github.com/denoland/rusty_v8\" target=\"_blank\"\u003erusty_v8\u003c/a\u003e) to parse and evaluate a built bundle file and return a string with the rendered html.\n\u003e [!NOTE]\n\u003e  This project is the backbone of [tuono](https://github.com/Valerioageno/tuono); a fullstack react framework with built in SSR.\n\nCurrently it works with [Vite](https://vitejs.dev/), [Webpack](https://webpack.js.org/), [Rspack](https://www.rspack.dev/), [React 18](https://react.dev/) and [Svelte 4](https://svelte.dev/) - Check the `examples/` folder.\n\n\u003e Check \u003ca href=\"https://github.com/Valerioageno/ssr-rs/blob/main/benches\"\u003ehere\u003c/a\u003e the benchmark results.\n\n## Getting started\n\nAdd this to your `Cargo.toml`:\n\n```bash\ncargo add ssr_rs\n```\n\n## Example\n\nTo render to string a bundled react project the application should perform the following\ncalls.\n\n```rust\nuse ssr_rs::Ssr;\nuse std::fs::read_to_string;\n\nfn main() {\n    Ssr::create_platform();\n\n    let source = read_to_string(\"./path/to/build.js\").unwrap();\n\n    let mut js = Ssr::new(\u0026source, \"entryPoint\").unwrap();\n\n    let html = js.render_to_string(None).unwrap();\n    \n    assert_eq!(html, \"\u003c!doctype html\u003e\u003chtml\u003e...\u003c/html\u003e\".to_string());\n}\n```\n\n## What is the \"entryPoint\"?\n\nThe `entryPoint` could be either:\n- the function that returns an object with one or more properties that are functions that when called return the rendered result \n- the object itself with one or more properties that are functions that when called return the rendered result\n\nIn case the bundled JS is an IIFE or the plain object the `entryPoint` is an empty string.\n\n```javascript\n// IIFE example | bundle.js -\u003e See vite-react example\n(() =\u003e ({ renderToStringFn: (props) =\u003e \"\u003chtml\u003e\u003c/html\u003e\" }))() // The entryPoint is an empty string\n```\n\n```javascript\n// Plain object example | bundle.js \n({renderToStringFn: (props) =\u003e \"\u003chtml\u003e\u003c/html\u003e\"}); // The entryPoint is an empty string\n```\n\n```javascript\n// IIFE variable example | bundle.js -\u003e See webpack-react example\nvar SSR = (() =\u003e ({renderToStringFn: (props) =\u003e \"\u003chtml\u003e\u003c/html\u003e\"}))() // SSR is the entry point\n```\n\n```javascript\n// Variable example | bundle.js -\u003e See webpack-react example\nvar SSR = {renderToStringFn: (props) =\u003e \"\u003chtml\u003e\u003c/html\u003e\"}; // SSR is the entry point\n```\n\n\u003e The export results are managed by the bundler directly.\n\n## Example with initial props\n\n```rust\nuse ssr_rs::Ssr;\nuse std::fs::read_to_string;\n\nfn main() {\n    Ssr::create_platform();\n\n    let props = r##\"{\n        \"params\": [\n            \"hello\",\n            \"ciao\",\n            \"こんにちは\"\n        ]\n    }\"##;\n\n    let source = read_to_string(\"./path/to/build.js\").unwrap();\n\n    let mut js = Ssr::new(\u0026source, \"entryPoint\").unwrap();\n\n    let html = js.render_to_string(Some(\u0026props)).unwrap();\n\n    assert_eq!(html, \"\u003c!doctype html\u003e\u003chtml\u003e...\u003c/html\u003e\".to_string());\n}\n```\n\n## Example with actix-web\n\n\u003e Examples with different web frameworks are available in the \u003ca href=\"https://github.com/Valerioageno/ssr-rs/blob/main/examples\" target=\"_blank\"\u003eexamples\u003c/a\u003e folder.\n\nEven though the V8 engine allows accessing the same `isolate` from different threads that is forbidden by this crate for two reasons:\n\n1. rusty_v8 library have not implemented yet the V8 Locker API. Accessing Ssr struct from a different thread will make the V8 engine to panic.\n2. Rendering HTML does not need shared state across threads.\n\nFor the reasons above parallel computation is a better choice. Following actix-web setup:\n\n```rust\nuse actix_web::{get, http::StatusCode, App, HttpResponse, HttpServer};\nuse std::cell::RefCell;\nuse std::fs::read_to_string;\n\nuse ssr_rs::Ssr;\n\nthread_local! {\n    static SSR: RefCell\u003cSsr\u003c'static, 'static\u003e\u003e = RefCell::new(\n            Ssr::from(\n                read_to_string(\"./client/dist/ssr/index.js\").unwrap(),\n                \"SSR\"\n                ).unwrap()\n            )\n}\n\n#[actix_web::main]\nasync fn main() -\u003e std::io::Result\u003c()\u003e {\n\n    Ssr::create_platform();\n\n    HttpServer::new(|| {\n        App::new()\n            .service(index)\n    })\n    .bind(\"127.0.0.1:8080\")?\n    .run()\n    .await\n}\n\n#[get(\"/\")]\nasync fn index() -\u003e HttpResponse {\n    let result = SSR.with(|ssr| ssr.borrow_mut().render_to_string(None).unwrap());\n\n    HttpResponse::build(StatusCode::OK)\n        .content_type(\"text/html; charset=utf-8\")\n        .body(result)\n}\n```\n\n## Contributing\n\nAny helps or suggestions will be appreciated.\n\nKnown TODOs: \n- Add examples with other rust backend frameworks\n- Add examples with other frontend frameworks (i.e. vue, quik, solid)\n- Add benchmark setup to test against Deno and Bun\n- Explore support for V8 snapshots\n- Explore js copilation to WASM (i.e. [javy](https://github.com/bytecodealliance/javy))\n\n## License\n\nThis project is licensed under the MIT License - see the \u003ca href=\"https://github.com/Valerioageno/ssr-rs/blob/main/LICENSE_MIT\"\u003eLICENSE_MIT\u003c/a\u003e || \u003ca href=\"https://github.com/Valerioageno/ssr-rs/blob/main/LICENSE_APACHE\"\u003eLICENSE_APACHE\u003c/a\u003e file for more information.\n\n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/Valerioageno/ssr-rs/main/logo.png\"\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalerioageno%2Fssr-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvalerioageno%2Fssr-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalerioageno%2Fssr-rs/lists"}