rustsveltekitwebview2tauri

Tauri window opens fine on macOS but hangs with blank window on Windows (no logs after #2)


I’m developing a desktop app with Rust + Tauri (v2.5) + SvelteKit.

On macOS my command for opening a new settings window works perfectly. On Windows however, the app freezes when building the window: I see log #1 and #2, but never #3 or #4. The window appears, but it is blank white and the whole app becomes unresponsive.

Here is the relevant Rust code:

#[tauri::command]
pub fn open_settings_window(app: AppHandle) -> tauri::Result<()> {   
    if let Some(win) = app.get_webview_window("settings") {
        win.set_focus()?;
        win.show()?;
        return Ok(());
    }
    
    println!("#1");
    
    let webview_url = WebviewUrl::App("settings".into());
    let mut builder = WebviewWindowBuilder::new(
        &app,
        "settings",
        webview_url,
    )
    .title("Settings")
    .resizable(false)
    .maximizable(false)
    .minimizable(false)
    .decorations(true)
    .inner_size(800.0, 600.0)
    .center();

    #[cfg(target_os = "macos")]
    {
        builder = builder.title_bar_style(TitleBarStyle::Overlay)
    }   
    
    println!("#2");
    if let Ok(win) = builder.build() {
        println!("#3");
        let _ = win.show();
    }
    println!("#4");    

    Ok(())
}

And on the SvelteKit side I call it like this:

import { invoke } from "@tauri-apps/api/core";

export async function openSettingsWindow() {
    await invoke("open_settings_window");
}

// Button
<button on:click={openSettingsWindow}>Open Settings</button>

Problem:

Question:

Environment:

Here's my directory tree

├── +layout.svelte
├── +layout.ts
├── +page.svelte
└── settings
    ├── +layout.svelte
    ├── +layout.ts
    └── +page.svelte

PS: I have also tried /settings and /settings/index.html but neither of them works.

Edit (package.json):

{
  "name": "myUIApp",
  "version": "0.1.0",
  "description": "",
  "type": "module",
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "preview": "vite preview",
    "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
    "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
    "tauri": "tauri"
  },
  "license": "MIT",
  "dependencies": {
    "@iconify-icons/heroicons-solid": "^1.2.6",
    "@iconify-icons/mdi": "^1.2.48",
    "@tailwindcss/vite": "^4.1.3",
    "@tauri-apps/api": "^2.5.0",
    "@tauri-apps/plugin-dialog": "^2.2.2",
    "@tauri-apps/plugin-opener": "^2",
    "@tauri-apps/plugin-os": "~2",
    "@tauri-apps/plugin-shell": "^2.3.0",
    "echarts": "^5.6.0",
    "echarts-stat": "^1.2.0",
    "plotly.js-dist": "^3.0.3",
    "plotly.js-dist-min": "^3.0.3",
    "svelte-i18n": "^4.0.1",
    "svelte-tiny-virtual-list": "^3.0.0"
  },
  "devDependencies": {
    "@iconify-json/heroicons": "^1.2.2",
    "@iconify-json/mdi": "^1.2.3",
    "@iconify-json/tabler": "^1.2.19",
    "@iconify/svelte": "^5.0.0",
    "@sveltejs/adapter-static": "^3.0.8",
    "@sveltejs/kit": "^2.9.0",
    "@sveltejs/vite-plugin-svelte": "^5.0.0",
    "@tailwindcss/postcss": "^4.1.3",
    "@tauri-apps/cli": "^2",
    "autoprefixer": "^10.4.21",
    "postcss": "^8.5.4",
    "svelte": "^5.0.0",
    "svelte-check": "^4.0.0",
    "svelte-preprocess": "^6.0.3",
    "tailwindcss": "^4.1.8",
    "typescript": "~5.6.2",
    "vite": "^6.0.3"
  }
}

Solution

  • According to the docs of WebviewWindowBuilder::new:

    Known issues

    On Windows, this function deadlocks when used in a synchronous command and event handlers, see the Webview2 issue. You should use async commands and separate threads when creating windows.

    Their suggested code is

    tauri::Builder::default()
      .setup(|app| {
        let handle = app.handle().clone();
        std::thread::spawn(move || {
          let webview_window = tauri::WebviewWindowBuilder::new(&handle, "label", tauri::WebviewUrl::App("index.html".into()))
            .build()
            .unwrap();
        });
        Ok(())
      });
    

    or

    #[tauri::command]
    async fn create_window(app: tauri::AppHandle) {
      let webview_window = tauri::WebviewWindowBuilder::new(&app, "label", tauri::WebviewUrl::App("index.html".into()))
        .build()
        .unwrap();
    }