#ssr #react #web #actix-web #javascript-engine #actix #server-side-render

ssr_rs

使用 V8 引擎进行服务器端渲染,解析和评估 JavaScript 代码

18 个不稳定版本 (3 个重大更改)

新版本 0.5.8 2024 年 8 月 18 日
0.5.7 2024 年 7 月 26 日
0.5.5 2024 年 6 月 27 日
0.4.0 2024 年 3 月 9 日
0.2.3 2021 年 5 月 23 日

#1122 in Web 编程

Download history 14/week @ 2024-04-28 97/week @ 2024-05-05 21/week @ 2024-05-12 194/week @ 2024-05-19 2/week @ 2024-05-26 257/week @ 2024-06-02 75/week @ 2024-06-09 99/week @ 2024-06-16 222/week @ 2024-06-23 78/week @ 2024-06-30 270/week @ 2024-07-07 33/week @ 2024-07-14 256/week @ 2024-07-21 112/week @ 2024-07-28 65/week @ 2024-08-11

每月下载量 435
tuono_lib 中使用

自定义许可协议

39KB
260

🚀 Rust 服务器端渲染

API codecov

该软件包旨在以最简单和最轻量级的方式启用 Rust 服务器上的服务器端渲染。

它使用 V8 JavaScript 引擎的嵌入版本(rusty_v8)来解析和评估构建的捆绑文件,并返回一个包含渲染 HTML 的字符串。

[!注意] 此项目是 tuono 的基础;一个内置 SSR 的全栈 React 框架。

目前它与 ViteWebpackRspackReact 18Svelte 4 一起工作 - 检查 examples/ 文件夹。

在此查看基准测试结果。

入门

将此添加到您的 Cargo.toml

cargo add ssr_rs

示例

要渲染捆绑的 React 项目到字符串,应用程序应执行以下调用。

use ssr_rs::Ssr;
use std::fs::read_to_string;

fn main() {
    Ssr::create_platform();

    let source = read_to_string("./path/to/build.js").unwrap();

    let mut js = Ssr::new(&source, "entryPoint").unwrap();

    let html = js.render_to_string(None).unwrap();
    
    assert_eq!(html, "<!doctype html><html>...</html>".to_string());
}

什么是 "entryPoint"?

entryPoint 可以是

  • 返回具有一个或多个属性的对象的函数,这些属性是函数,当调用时返回渲染结果
  • 具有一个或多个属性的对象本身,这些属性是函数,当调用时返回渲染结果

如果捆绑的 JS 是 IIFE 或普通对象,则 entryPoint 是空字符串。

// IIFE example | bundle.js -> See vite-react example
(() => ({ renderToStringFn: (props) => "<html></html>" }))() // The entryPoint is an empty string
// Plain object example | bundle.js 
({renderToStringFn: (props) => "<html></html>"}); // The entryPoint is an empty string
// IIFE variable example | bundle.js -> See webpack-react example
var SSR = (() => ({renderToStringFn: (props) => "<html></html>"}))() // SSR is the entry point
// Variable example | bundle.js -> See webpack-react example
var SSR = {renderToStringFn: (props) => "<html></html>"}; // SSR is the entry point

导出结果由打包器直接管理。

带有初始属性的示例

use ssr_rs::Ssr;
use std::fs::read_to_string;

fn main() {
    Ssr::create_platform();

    let props = r##"{
        "params": [
            "hello",
            "ciao",
            "こんにちは"
        ]
    }"##;

    let source = read_to_string("./path/to/build.js").unwrap();

    let mut js = Ssr::new(&source, "entryPoint").unwrap();

    let html = js.render_to_string(Some(&props)).unwrap();

    assert_eq!(html, "<!doctype html><html>...</html>".to_string());
}

带有 actix-web 的示例

不同 Web 框架的示例可在 示例 文件夹中找到。

尽管V8引擎允许从不同的线程访问相同的isolate,但这在此crate中被禁止,原因有两个

  1. rusty_v8库尚未实现V8 Locker API。从不同的线程访问Ssr结构体会导致V8引擎panic。
  2. 渲染HTML不需要在多个线程间共享状态。

由于上述原因,并行计算是一个更好的选择。以下是actix-web的配置

use actix_web::{get, http::StatusCode, App, HttpResponse, HttpServer};
use std::cell::RefCell;
use std::fs::read_to_string;

use ssr_rs::Ssr;

thread_local! {
    static SSR: RefCell<Ssr<'static, 'static>> = RefCell::new(
            Ssr::from(
                read_to_string("./client/dist/ssr/index.js").unwrap(),
                "SSR"
                ).unwrap()
            )
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {

    Ssr::create_platform();

    HttpServer::new(|| {
        App::new()
            .service(index)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

#[get("/")]
async fn index() -> HttpResponse {
    let result = SSR.with(|ssr| ssr.borrow_mut().render_to_string(None).unwrap());

    HttpResponse::build(StatusCode::OK)
        .content_type("text/html; charset=utf-8")
        .body(result)
}

贡献

任何帮助或建议都将受到赞赏。

已知的待办事项

  • 添加与其他Rust后端框架的示例
  • 添加与其他前端框架(例如vue、quik、solid)的示例
  • 添加基准测试设置以测试与Deno和Bun的对比
  • 探索对V8快照的支持
  • 探索将JS编译成WASM(例如javy

许可证

本项目采用MIT许可证 - 请参阅LICENSE_MITLICENSE_APACHE文件以获取更多信息。


依赖关系

~65MB
~1.5M SLoC