Saltar al contenido

create-tauri-app y el esqueleto

Crear el proyecto, entender qué te pregunta el asistente y por qué, y leer el esqueleto generado línea por línea antes de tocar nada.

Crear el proyecto

Hay tres formas de invocar al asistente, según lo que tengas instalado:

Shell
bun create tauri-app        # con bunnpm create tauri-app@latest # con npmcargo install create-tauri-app && cargo create-tauri-app  # sin Node

La tercera es interesante por lo que revela: se puede tener un proyecto de Tauri sin Node instalado, si el frontend no lo necesita. El asistente ofrece plantillas de HTML puro y de frameworks de Rust que compilan a WebAssembly. No es lo habitual, pero conviene saber que el framework no exige un ecosistema de JavaScript.

Lo que te pregunta, y qué contestar

El esqueleto, leído

Tres ficheros llevan todo lo interesante. Ábrelos en este orden.

src-tauri/src/lib.rs — la aplicación:

Rust
// Un comando: una función normal con un atributo. Lo único que la distingue// de cualquier otra función de Rust es que el frontend puede pedirla.#[tauri::command]fn greet(name: &str) -> String {    format!("Hola, {name}! Has sido saludado desde Rust!")}#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {    tauri::Builder::default()        .plugin(tauri_plugin_opener::init())        // Registrar. Un comando sin registrar no existe para el frontend.        .invoke_handler(tauri::generate_handler![greet])        .run(tauri::generate_context!())        .expect("error al arrancar la aplicación");}

Cinco cosas que ya sabes ver, después del nivel 4:

  • greet es una función corriente. El atributo la marca como invocable, nada más.
  • generate_handler! es el registro. Es el paso que más se olvida, y el nivel 19 explica cómo dejar de poder olvidarlo.
  • El plugin(...) de la plantilla registra el plugin que abre enlaces en el navegador del sistema. Es el ejemplo de plugin más pequeño que existe.
  • generate_context! incrusta la configuración, los iconos y el manifiesto de permisos en el binario. Nivel 4.2, paso 3.
  • No hay setup todavía. Lo habrá en cuanto haya algo que inicializar.

src-tauri/tauri.conf.json — la configuración:

JSON
{  "productName": "mi-app",  "version": "0.1.0",  "identifier": "dev.tudominio.mi-app",  "build": {    "beforeDevCommand": "bun run dev",    "devUrl": "http://localhost:1420",    "beforeBuildCommand": "bun run build",    "frontendDist": "../dist"  },  "app": {    "windows": [{ "title": "mi-app", "width": 800, "height": 600 }],    "security": { "csp": null }  },  "bundle": { "active": true, "targets": "all", "icon": ["icons/icon.png"] }}

La sección build es el pegamento entre los dos proyectos y explica cómo funcionan los dos modos: en desarrollo, Tauri ejecuta beforeDevCommand y apunta la webview a devUrl; al compilar, ejecuta beforeBuildCommand y empaqueta lo que haya en frontendDist. Toda la diferencia entre dev y build del nivel 10 está en esas cuatro claves.

Fíjate también en security.csp: null. La plantilla viene con la política de contenido desactivada para que nada moleste mientras aprendes. Eso hay que cambiarlo antes de publicar nada, y es el nivel 31.

src/main.js — el frontend:

JS
import { invoke } from "@tauri-apps/api/core";// Toda la superficie del puente, en una línea: un nombre y unos argumentos.const saludo = await invoke("greet", { name: "mundo" });

Nada más. El nombre del comando es una cadena, los argumentos un objeto, y el resultado una promesa. La fase III desmonta lo que ocurre entre esa línea y la función de Rust.

Los nombres, que no coinciden

Un detalle que sorprende a todo el mundo la primera vez: la función de Rust se llama greet y recibe name, y el frontend la invoca con { name: ... }. Coincide porque el ejemplo es de una sola palabra. En cuanto el argumento se llame file_path en Rust, el frontend tendrá que enviarlo como filePath: el puente convierte entre la convención de Rust y la de JavaScript. El nivel 14 lo trata, y es una de las causas más frecuentes de «mi comando no recibe los argumentos».