El arranque, del main a la primera pintura
Qué ocurre exactamente entre el doble clic y la interfaz visible: el binario, el builder, el gancho de inicialización, la creación de la ventana, la webview y el momento en que el frontend puede empezar a hablar.
La secuencia
Los dos grupos ocurren a la vez, no uno detrás de otro, y de ahí sale la única sutileza del arranque.
Un esqueleto, para anclar la secuencia
No hace falta entender cada línea todavía —la fase II las desmonta— pero verlas juntas ordena el resto:
// src-tauri/src/lib.rs#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() { tauri::Builder::default() // paso 2: los plugins y los comandos se registran ANTES de que exista nada .plugin(tauri_plugin_opener::init()) .invoke_handler(tauri::generate_handler![saludar]) // paso 4: aquí la app ya existe y las ventanas declaradas también .setup(|app| { // abrir la base de datos, arrancar tareas, tocar la ventana Ok(()) }) // paso 3 y 5: el contexto se incrusta al compilar; run entra en el bucle .run(tauri::generate_context!()) .expect("error al arrancar la aplicación");}// src-tauri/src/main.rs — tres líneas, y no crecen nunca#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]fn main() { app_lib::run()}Ese atributo de la primera línea del main merece una nota, porque su ausencia produce un fallo muy visible: en Windows, sin él, la aplicación abre una ventana de consola negra detrás de la tuya en la versión de producción.
La carrera, y cómo se resuelve
Como el frontend arranca en paralelo con el core, hay un momento en que la webview ya está ejecutando JavaScript y el setup del core todavía no ha terminado. Si tu primera pantalla llama a un comando que necesita algo que setup está preparando —la base de datos, por ejemplo— ese comando puede llegar antes de tiempo.
Hay tres formas de tratarlo, y solo dos son buenas:
Bien · el comando espera. El estado se registra como algo que puede no estar listo todavía, y el comando espera a que lo esté. Es la solución limpia y la que escala.
Bien · el core avisa. El setup termina emitiendo un evento, y el frontend muestra una pantalla de carga hasta recibirlo. Tiene la ventaja de que el usuario ve algo desde el primer momento.
Mal · el frontend espera un rato. Un temporizador de trescientos milisegundos «por si acaso». Funciona en tu máquina y falla en la del usuario con el disco lento. Es el fallo intermitente clásico, y es el más caro de diagnosticar meses después.
Lo que existe en cada momento
Una tabla para consultar cuando algo «no está disponible todavía»:
| momento | ya existe | todavía no |
|---|---|---|
| Antes del builder | nada de Tauri | todo |
| Durante el builder | el registro de comandos, plugins y estado | la app, las ventanas, el manejador |
En setup |
la app, el manejador, las ventanas declaradas, el estado registrado | el bucle de eventos, cualquier interacción |
| En un comando | todo | — |
| En un evento del bucle | todo, y la ventana puede estar cerrándose | — |
La fila que más se consulta es la tercera: en setup ya tienes el manejador de la aplicación, y con él el acceso a las ventanas, al estado y a los plugins. Es el sitio donde se hace casi toda la inicialización real.