😔

【Rust】YewとAxumの連携

2025/01/03に公開

Yewで作ったWebアプリケーションをAxumで作ったWebサーバーで公開する

Yewは、「Webアプリケーションフレームワーク」です。

https://yew.rs/ja/

一方Axumは、「Webアプリケーションフレームワーク」です。

https://github.com/tokio-rs/axum

🤔🤔🤔

二者の区別

そもそもWeb技術には、表裏の別があります。ブラウザーに表出して見える箇所、つまるところ画面を形作るものを「front end」と、通信など、ブラウザーからは見えない裏側を「back end」と称されています。

front endの例は比較的明確で、JavaScriptTypeScriptWebAssemblyといった言語が代表的です。論うまでもないと思っていましたが、HTMLCSSもこれに該当するようです。
対してback endは、あらゆる言語によって行われています。個人的に親近なものは、PythonFlaskです。

Yewfront endです。主に、HTMLの埋め込みCSSの設定といった、基本的な画面構成を実装します。ただし、画面の動きは他のものに委ねています。
今ホームページを読んでいて初めて知りましたが、yew_routerというものを使えばback endらしい実装もできるようです紛らわしいですね。

反対にAxumback endです。主に、HTTPが云云という箇所を実装します。基本的に画面には関与しません。

Yewを使う意義

Yewは、「WebAssemlyの利用を簡略化するもの」としても使い得ます。

本記事では特に述べませんが、WebAssemlyを使うには幾つもの手順を踏む必要があります。そうしたあらゆる手順を

trunk serve

というコマンド一つで代替できると言えば、まるで融通利くもののように聞こえましょうか。この利点を応用できれば、WebAssemlyに親しむ機会も作りやすくなろうと考えた次第であります。本記事では、その応用先としてAxumを選定しています。

本題

私事ですが、以前投稿した記事にてYewを使ったアプリケーションを作りました。本記事では、アプリケーションの具体的な作り方はこれを述べてございません。拙作を流用せられても構いませんので、何らかのアプリケーションをあらかじめご用意ください。

また、試行の上で次の記事を拝見し、参考にさせて頂きました。

https://zenn.dev/scirexs/articles/bcf695494632dc

準備

Yewアプリケーションを実行すると、フォルダー内にdistというフォルダーが自動生成されます。この中に、あらかじめ用意するindex.htmlファイルと、生成された.jsファイル、.wasmファイルが存在するはずです。このdistフォルダーをそのまま移植するなどして流用します。

実装

  1. package作成

    with_yewの名前で作成します。

    package作成
    cargo new with_yew
    

    with_yewフォルダーが生成されるので、今回はdistフォルダーをこの中に移植します。

  2. crate追加

    Cargo.toml
    [dependencies]
    axum = { version = "0.8.1", features = ["http2"] }
    tokio = { version = "1.42.0", features = ["full"] }
    tower-http = { version = "0.6.2", features = ["fs", "trace"] }
    

    コマンドで追加する場合は次のようにします。

    crate追加
    cargo add axum --features http2
    cargo add tokio --features full
    cargo add tower-http --features fs --features trace
    
  3. ソースコード記述

    with_yew/src/main.rsに次の通り記述します。

    main.rs
    use tower_http::{services::ServeDir, trace::TraceLayer};
    use axum::Router;
    use tokio::net::TcpListener;
    
    #[tokio::main]
    async fn main() {
        const STATIC_DIR: &str = "./dist";
    
        let serve_dir: ServeDir = ServeDir::new(STATIC_DIR);
    
        let app: Router = Router::new().nest_service("/dist", serve_dir);
    
        let listener: TcpListener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
    
        axum::serve(listener, app.layer(TraceLayer::new_for_http())).await.unwrap();
    }
    
    要点

    殆ど参考記事の通りなので敢えて述べるようなことはありません。一部、サンプルプログラムを参考に変更した箇所もありますが、一箇所注意点があります。

    nest_service("/dist", serve_dir)にて、移植したフォルダー名を基に"/dist"と指定しています。私の試した限りでは、斯くしなければ動きませんでした。

    次に、.htmlファイルを修正します。私の場合は、distフォルダー内に次のようなファイルが存在します。

    PS C:\\with_yew> ls .\dist\
    
        Directory: C:\\with_yew\dist
    
    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    -a---      2023/12/11()     2:26        1478457 bmi_calculator-c3e78f12e3a455f2_bg.wasm
    -a---      2023/12/11()     2:26          25420 bmi_calculator-c3e78f12e3a455f2.js
    -a---      2025/01/03()     6:21           1445 index.html
    

    修正するのは、(更新日が新しい通り)index.htmlです。参考記事のおっしゃるように、.jsファイルと.wasmファイルの指定を変えなければなりませんでした。./フォルダー名/ファイル名の型式にすることで、正しく動作します。

    index.html(抜粋)
    <link rel="preload" href="./dist/bmi_calculator-c3e78f12e3a455f2_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
    <link rel="modulepreload" href="./dist/bmi_calculator-c3e78f12e3a455f2.js">
    <script type="module">import init from './dist/bmi_calculator-c3e78f12e3a455f2.js';init('./dist/bmi_calculator-c3e78f12e3a455f2_bg.wasm');</script>
    
  4. 実行

    移植元はYewですが、今作成したものはYewではないので、trunk serveは使いません。

    実行
    cargo run
    

    ブラウザーでhttp://127.0.0.1:8080/distに接続すると、Yewで作成したアプリケーションがその通り表示されるはずです。

    証明書などは使用していないのでprotocolhttpIP addressport番号は、TcpListener::bind("127.0.0.1:8080")としたので127.0.0.1:8080directory部はnest_service("/dist", serve_dir)としたので/distとなります。

Yewで生成したWebAssembly製アプリケーションが、以上のように移植し得ることを確認しました。但し、移植の自動化については確認していません。また、Yewは依然として開発途上のため、インターネットへ公開するような運用を推奨していない⋯と、どこかで読んだ記憶があります。セキュリティー上、斯様に移植してよいのかは疑問です。

Discussion