Open2

Rust , Workers-rs + React + tailwindcss 構成の試作

knaka Tech-Blogknaka Tech-Blog

概要

  • 前回の、 workers-rs + d1構成等の続編になります。
  • React 追加し、fullstack 構成に変更するメモです。

[ 公開 2025/06/25 ]


関連

https://developers.cloudflare.com/workers/languages/rust/?utm_source=chatgpt.com

https://github.com/cloudflare/workers-rs


環境

  • Rust: cargo 1.83.0
  • workers-rs
  • react 19
  • react-dom 19
  • esbuild

書いたコード

https://github.com/kuc-arc-f/workers-rs-2ex/tree/main/rs-react5


  • dev-start
npm run dev
  • react-build (別 window)
npm run build

  • rs-react5/wrangler.toml
  • assetsは、jsファイルの読込設定できました。パス変更は できるはず。
name = "workers-rs-2"
main = "build/worker/shim.mjs"
compatibility_date = "2023-03-22"

assets = { directory = "./public/" }

[build]
command = "cargo install -q worker-build && worker-build --release"

rs-react5/Cargo.toml

https://github.com/kuc-arc-f/workers-rs-2ex/blob/main/rs-react5/Cargo.toml

[package]
name = "workers-rs-2"
version = "0.1.0"
edition = "2021"

# https://github.com/rustwasm/wasm-pack/issues/1247
[package.metadata.wasm-pack.profile.release]
wasm-opt = false

[lib]
crate-type = ["cdylib"]

[dependencies]
worker = { version = "0.6.0", features = ["d1"] }
serde = { version = "1.0.188", features = ["derive"] }

[dev-dependencies]
tokio = { version = "1", features = ["full"] }

[profile.release]
lto = true
strip = true
codegen-units = 1

  • rs-react5/src/lib.rs

https://github.com/kuc-arc-f/workers-rs-2ex/blob/main/rs-react5/src/lib.rs

  • handle_get: SSR
  • tailwindcss 今回は CDN読込です。
#[event(fetch)]
async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
    Router::new()
        .get_async("/foo", handle_get)
        .post_async("/bar", handle_post)
        .delete_async("/baz", handle_delete)
        .run(req, env)
        .await
}

pub async fn handle_get(_: Request, _ctx: RouteContext<()>) -> worker::Result<Response> {
    // HTML文字列を生成  
    let html = format!(
      "<!DOCTYPE html>
      <html>
        <head>
          <meta charset=\"utf-8\">
          <meta name='viewport' content='width=device-width, initial-scale=1.0' />
          <title>My Page</title>
          <script src='https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4'></script>
        </head>
        <body>
          <div id='app'></div>
          <script type='module' src='/client.js'></script>
        </body>
      </html>"
    );
    // Response::from_html を使うとヘッダー付きで便利
    let mut response = Response::from_html(html)?;
    // 必要に応じてヘッダーをカスタム可能
    response.headers_mut()
        .set("Content-Type", "text/html; charset=utf-8")?;
    Ok(response)
}

  • rs-react5/src/client.tsx
  • React画面

https://github.com/kuc-arc-f/workers-rs-2ex/blob/main/rs-react5/src/client.tsx

import ReactDOM from 'react-dom/client'
import React from 'react'; 

function App() {
  return (
  <div>
    <h1 className="text-3xl font-bold text-blue-600">hello!</h1>
    <hr />
    <span>welcome , Rust axum +  React</span>
  </div>
  );
}
ReactDOM.createRoot(document.getElementById('app')).render(
    <App />
)
console.log('createRoot')

  • deploy
  • デプロイできました。
npm run deploy

knaka Tech-Blogknaka Tech-Blog

D1 Database , Rust Workers-rs + React 作例

  • 前回の、workers-rs 続編なります。
  • Rustの場合、生成AI 失敗 多めで難航しました。。
  • CRUD的な例です。
  • 操作の面では、サーバーレスでは。速く感じます。バック側は100% Rustらしいです。

環境

  • Rust: cargo 1.83.0
  • workers-rs
  • react 19
  • react-dom 19
  • esbuild

書いたコード

https://github.com/kuc-arc-f/workers-rs-2ex/tree/main/rs-react12_d1


  • dev-start
npm run dev

` react-build (別 window)

npm run build

  • rs-react12_d1/Cargo.toml
[package]
name = "workers-rs-2"
version = "0.1.0"
edition = "2021"

# https://github.com/rustwasm/wasm-pack/issues/1247
[package.metadata.wasm-pack.profile.release]
wasm-opt = false

[lib]
crate-type = ["cdylib"]

[dependencies]
worker = { version = "0.6.0", features = ["d1"] }
serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.140"

[dev-dependencies]
tokio = { version = "1", features = ["full"] }

[profile.release]
lto = true
strip = true
codegen-units = 1```

  • ルーティング , main関数
  • rs-react12_d1/src/lib.rs

https://github.com/kuc-arc-f/workers-rs-2ex/blob/main/rs-react12_d1/src/lib.rs

#[event(fetch)]
async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
    //todo_handlers , test_handlers
    Router::new()
        .get_async("/api/todos/list", handlers::test_handlers::handle_list_todos)
        .post_async("/api/todos/create", handlers::todo_handlers::handle_create_todo)
        .post_async("/api/todos/delete", handlers::todo_handlers::handle_delete_todo)
        .post_async("/api/todos/update", handlers::todo_handlers::handle_update_todo)
        .get_async("/api/todo13/list", handlers::todo13_handlers::handle_list_todos)
        .post_async("/api/todo13/create", handlers::todo13_handlers::handle_create_todo)
        .post_async("/api/todo13/delete", handlers::todo13_handlers::handle_delete_todo)
        .post_async("/api/todo13/update", handlers::todo13_handlers::handle_update_todo)
        .get_async("/api/todo16/list", handlers::todo16_handlers::handle_list_todos)
        .post_async("/api/todo16/create", handlers::todo16_handlers::handle_create_todo)
        .post_async("/api/todo16/delete", handlers::todo16_handlers::handle_delete_todo)
        .post_async("/api/todo16/update", handlers::todo16_handlers::handle_update_todo)

        .get_async("/foo", handle_get) 
        .get_async("/todo", handle_get) 
        .get_async("/todo13", handle_get) 
        .get_async("/todo16", handle_get) 
        .post_async("/bar", handle_post)
        .delete_async("/baz", handle_delete)
        .run(req, env)
        .await
}

  • handler , API実装
  • rs-react12_d1/src/handlers/todo16_handlers.rs

https://github.com/kuc-arc-f/workers-rs-2ex/blob/main/rs-react12_d1/src/handlers/todo16_handlers.rs


  • React
  • rs-react12_d1/src-ts/client/Todo16.tsx