2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TauriでWindowsアプリを作ってみた

Last updated at Posted at 2025-05-25

1. やったこと

Tauri(Rust + React)でWindowsアプリを作成する為
Tauriの基本的な書き方を学びました

2. 技術選定

2-1. やりたいこと

以下を実施するツールを作ろうとしています
・今回作成するツールはWindows PCで利用したい
・ローカルストレージにある多数の画像ファイルをユーザーが眺めながら選択したい
・選んだ画像にコメントを記入していきたい

上記を踏まえて以下のような条件で選定します
・ローカルストレージのファイルを多数扱うのでネイティブアプリが良さそう
・どうせ覚えるならクロスプラットフォームなフレームワークが良い
・画像を選択したり色々するのだとリッチなGUIを作りたくなりそう
・別途ランタイムのインストールが必要になったりしないものが良い

2-2. 選択肢

以下を候補に考えました
・C++(WinAPI)
・.NET MAUI
・PyQt/PySide
・Electron
・Fyne
・Flutter
・ReactNative
・Tauri

2-3. 選定結果と選定理由

最終的にTauriを選定しました
Electron, Flutter, React-Nativeも候補に残してましたが

・Rustを書いてみたい
・Reactで書けてTailwindが使えるのが嬉しい
・ビルドがexeまたはmsiになって配布が容易

というのが決め手でTauriにしました

3. 開発環境を構築する

3-1. Node.jsをインストールする

フロントエンドをviteで扱う為にnodeが要ります
今回はWindows環境で開発するので公式のインストーラーを使います
https://nodejs.org/ja/download

3-2. Rustをインストールする

Rustもインストーラがあります
https://www.rust-lang.org/ja/tools/install

3-3. Visual Studioをインストールする

公式ページからインストーラーを入手します
https://visualstudio.microsoft.com/ja/free-developer-offers/

以上で準備完了です

4. アプリ作成手順

実際に作っていきましょう
現代的なフレームワークなので動くものが簡単に作成できます

4-1. プロジェクトの作成

プロジェクト作成

プロジェクトを作成します

powershell
npm create tauri-app

上記を実行すると、プロジェクト名をどうするか、フロントエンドを何で書くか(React, Vueなど)、バンドラを何にするか(npm, yarn, bunなど)などを聞かれます。今回はtauri-app, React, npmでやろうと思います

開発モードで起動

ReactやVueのように、開発モードで起動することが出来ます
作成された初期プロジェクトがそのままで動くようになっていて、以下コマンドで起動してGUIビューが表示されます

powershell
cd tauri-app
npm install
npm run tauri dev

しかもこの状態でホットリロードに対応しているので、フロントエンド部分を書き換えると表示に即時反映されます。開発エクスペリエンス良すぎて驚きます

実行ファイルにビルドする

以下でexeファイルがビルドされます

powershell
npm run tauri build

/tauri-app/src-tauri/target/release/tauri-app.exe として実行ファイルが作成されて、同梱ファイルが必要ない場合はこれだけで動きます。同梱がある場合は/tauri-app/src-tauri/target/release/bundle/内にインストーラーがビルドされるので、これを配布することができます

4-2. ディレクトリ構造

プロジェクトディレクトリは以下のようになります

フロントエンド

/src/以下にフロントエンドのファイルが作成されます
最初にmain.tsxが呼ばれます

/src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

main.tsxで呼ばれたApp.tsxで表示されている内容が書かれています

/src/App.tsx
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import { invoke } from "@tauri-apps/api/core";
import "./App.css";

function App() {
  const [greetMsg, setGreetMsg] = useState("");
  const [name, setName] = useState("");

  async function greet() {
    // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
    setGreetMsg(await invoke("greet", { name }));
  }

  return (
    <main className="container">
      <h1>Welcome to Tauri + React</h1>

      <div className="row">
        <a href="https://vitejs.dev" target="_blank">
          <img src="/vite.svg" className="logo vite" alt="Vite logo" />
        </a>
        <a href="https://tauri.app" target="_blank">
          <img src="/tauri.svg" className="logo tauri" alt="Tauri logo" />
        </a>
        <a href="https://reactjs.org" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <p>Click on the Tauri, Vite, and React logos to learn more.</p>

      <form
        className="row"
        onSubmit={(e) => {
          e.preventDefault();
          greet();
        }}
      >
        <input
          id="greet-input"
          onChange={(e) => setName(e.currentTarget.value)}
          placeholder="Enter a name..."
        />
        <button type="submit">Greet</button>
      </form>
      <p>{greetMsg}</p>
    </main>
  );
}

export default App;

ほぼReactそのままの書き方になっていて
Reactを知っていればすんなり読めると思います

一般的なReactと異なるのは3行目の
import { invoke } from "@tauri-apps/api/core";
の部分で、この1行でtauriバックエンドの関数を呼び出せるようになっています

バックエンド

/src-tauri/src/にバックエンドのコードがあります

main.rsでは2つの処理が書かれていて
2行目でリリースビルド時にコンソールウィンドウを表示しないように指示しており
4行目でlib.rsのrun()を実行します

/src-tauri/src/main.rs
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

fn main() {
    tauri_app_lib::run()
}

/src-tauri/src/lib.rsでは、main.rsから呼ばれてTauriの基本機能部分をまかなうrun()と、フロントエンドからinvokeで呼ばれるバックエンド関数が定義されます

関数をinvokeから使えるようにするには、#[tauri::command]が付けてあって、かつrun()で.invoke_handler(tauri::generate_handler![greet])のように登録されている必要があり、明示的に指示する設計になっています

/src-tauri/src/lib.rs
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

4-3. 簡単な変更

バックエンドに関数を追加

/src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

#[tauri::command]
fn greet_jp(name: &str) -> String {
    format!("こんにちは、{}さん!Rustからご挨拶します!", name)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet, greet_jp])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

フロントエンドを書き換える

invokeしている関数をgreet_jpに変更します

/src/App.tsx
  async function greet() {
    // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
    setGreetMsg(await invoke("greet_jp", { name }));
  }

4-4. 画面の縦横幅を変更する

デフォルトの画面幅を設定する

/src-tauri/tauri.conf.jsonで画面サイズを変更できます

/src-tauri/tauri.conf.json
"app": {
"windows": [
  {
    "title": "tauri-app",
    "width": 800,
    "height": 300
  }

動的に変更する

appWindow.setSizeで動的に変更できます

tsx
import { appWindow } from "@tauri-apps/api/window";

function ResizeButton() {
  return (
    <button
      onClick={() =>
        appWindow.setSize({ width: 1024, height: 768 })
      }
    >
      サイズを1024x768に変更
    </button>
  );
}

4-5. 画面遷移する

Reactと同様にreact-router-domで画面遷移することができます
この場合、コンポーネントが置き換わるのでstateはクリアされます

routingを設定する

/src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import App1 from "./App1";
import App2 from "./App2";
import "./App.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App1 />} />
        <Route path="/app2" element={<App2 />} />
      </Routes>
    </BrowserRouter>
  </React.StrictMode>,
);

navigateを設定する

/src/App1.tsx
import { useNavigate } from "react-router-dom";
import "./App.css";

export default function App() {
    const navigate = useNavigate();

    function goToApp2() {
        navigate("/app2");
    }

    return (
        <main className="container">
            <h1>App1</h1>
            <p>Click to another view.</p>
            <button onClick={goToApp2}>App2へ移動</button>
        </main>
    );
}
/src/App2.tsx
import { useNavigate } from "react-router-dom";
import "./App.css";

export default function App() {
    const navigate = useNavigate();

    function goToApp1() {
        navigate("/");
    }

    return (
        <main className="container">
            <h1>App2</h1>
            <p>Click to another view.</p>
            <button onClick={goToApp1}>App1へ移動</button>
        </main>
    );
}

できました

4-6. Tailwindを使う

Tailwindも使えます
Viteでレンダリングするのでその辺で上手くやってくれるようです

以下の手順が上手くいきました
https://tailwindcss.com/docs/installation/using-vite

terminal
npm install tailwindcss @tailwindcss/vite
/src/App.css
@import "tailwindcss";
/src/App.tsx
import "./App.css";
export default function App() {
  return (
    <main className="container">
      <h1 className="text-red-500 text-5xl">Welcome to Tauri + React</h1>
    </main>
  );
}

5. まとめ

全体にかなり好感触です

・とりあえず動くところまでがすごく簡単
・Tauriプロジェクトの設計がキレイで分かりやすい
・開発モードのホットリロードが快適
・やっぱりReactで書けるのは嬉しい
・TypeScriptで書けるのも嬉しい
・Tailwindも使えちゃう
・Win配布ファイルがexe, msiだけなのが嬉しい
・モバイル版もビルドできる

レッツトライ

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?