Depurar NUI en FiveM: nui_devtools, errores de consola y callbacks fallidos

Depura una NUI en FiveM: abre herramientas de desarrollador de Chromium con nui_devtools, lee errores de Uncaught TypeError, corrige una búsqueda fallida a https://resource/cb y prueba la UI en un navegador.

Tu NUI se abre como un panel en blanco, un botón no hace nada, o el cursor aparece y no hay pantalla. Generalmente no hay error de Lua, porque la falla está en la página web. Necesitas la consola del navegador, y FiveM tiene una. Esta guía cubre cómo abrirla, cómo leer sus errores y cómo probar tu UI sin el juego.

Abre las herramientas: nui_devtools

NUI es una página de Chromium dentro del juego. Presiona F8 para abrir la consola de FiveM y ejecuta:

text
nui_devtools

Se abre una ventana de herramientas de desarrollador para la capa NUI, como la que conoces de un navegador. Usa estas pestañas:

  • Console: Errores de JavaScript y tus propias líneas de console.log.
  • Network: cada solicitud que hace la página, incluyendo los callbacks a Lua.
  • Elements: el HTML y CSS en vivo. Úsalo para ver si tu elemento existe, cuán grande es y si está oculto.
  • Sources: establece puntos de quiebre en tu script.

Cuidado: si nui_devtools está disponible depende de tus configuraciones y de la compilación del cliente que ejecutes. Si el comando no hace nada, verifica que tu cliente de juego esté actualizado, y prueba la UI en un navegador normal como se muestra a continuación.

Si tu UI es visible solo después de un SendNUIMessage, abre las herramientas de desarrollador primero y dispara la acción después, para que veas los mensajes que llegan.

Lee los errores de la consola

Los errores en la pestaña Console muestran el archivo y la línea de tu script. Los que verás con más frecuencia:

text
Uncaught TypeError: Cannot read properties of undefined (reading 'items')

Tu código leyó .items en algo que es undefined. En NUI esto casi siempre viene del mensaje:

js
window.addEventListener('message', (event) => {
  const { action, data } = event.data
  if (action === 'open') {
    render(data.items)   // data is undefined
  }
})

Verifica qué realmente envió Lua. Imprime todo el mensaje primero:

js
window.addEventListener('message', (event) => {
  console.log('NUI message', JSON.stringify(event.data))
})

Luego compáralo con la llamada de Lua:

lua
SendNUIMessage({ action = 'open', data = { items = items } })

Las claves deben coincidir exactamente, incluyendo mayúsculas. Un campo establecido a nil en Lua falta del mensaje, por lo que es undefined en JavaScript.

Otros errores comunes:

Mensaje de consola Causa usual
Uncaught ReferenceError: x is not defined Un archivo de script no se cargó, o un typo en un nombre
Uncaught SyntaxError Un archivo de script roto, o una salida de bundler con la ruta incorrecta
Failed to load resource: 404 Un archivo no está listado en files en el fxmanifest, o la ruta es incorrecta
Uncaught (in promise) TypeError: Failed to fetch Una solicitud de callback falló, véase a continuación

Si la pestaña Network muestra un 404 para tu JS, CSS o imágenes, añade cada archivo que carga la página a files en el manifest, y apunta ui_page al HTML correcto:

lua
ui_page 'web/index.html'

files {
  'web/index.html',
  'web/**/*',
}

Para una compilación de Vite o React, usa la carpeta de salida, véase FiveM NUI with React and Vite.

Búsqueda fallida a https://resource/cb

NUI envía mensajes a Lua con una solicitud a https://<nombre de recurso>/<nombre de callback>:

js
fetch(`https://${GetParentResourceName()}/close`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({}),
})

En la pestaña Network una solicitud fallida se muestra en rojo:

text
POST https://my_script/close net::ERR_FAILED

Verifica estos en orden:

  1. El callback no está registrado. El nombre después de la barra debe coincidir con un RegisterNUICallback en el cliente, exactamente:
lua
RegisterNUICallback('close', function(data, cb)
    SetNuiFocus(false, false)
    cb('ok')
end)
  1. El nombre del recurso es incorrecto. El host en la URL es el nombre de la carpeta del recurso. Si renombraste la carpeta, un https://old_name/close codificado falla. Usa GetParentResourceName() en la página, como arriba, para que el nombre siga la carpeta.
  2. El callback nunca responde. Siempre llama a cb(...), incluso con cb('ok'). Un controlador que retorna sin llamarla deja la solicitud pendiente, y la página puede esperar para siempre.
  3. El controlador de Lua genera un error antes de cb. Verifica la consola F8 por un error de script en el mismo momento. Un error antes de cb significa que la respuesta nunca se envía.
  4. El recurso no se está ejecutando. Los callbacks viven mientras el script del cliente que los registró se está ejecutando.

Enfoque y el cursor

Si la UI se muestra pero no se puede hacer clic, o el mouse permanece atrapado después de cerrar, el problema es SetNuiFocus, no la página. Véase NUI focus stuck cursor.

Prueba la UI en un navegador normal

Depurar en el juego es lento. La mayoría de una NUI se puede probar en un navegador, con la recarga en vivo de tu editor.

Abre index.html a través de un servidor local, o ejecuta npm run dev para un proyecto de Vite. Luego simula las dos cosas que el juego normalmente proporciona.

Primero, un GetParentResourceName falso, y callbacks que no fallan:

js
if (!window.GetParentResourceName) {
  window.GetParentResourceName = () => 'my_script'
  window.fetch = async (url, options) => {
    console.log('NUI callback', url, options && options.body)
    return { ok: true, json: async () => ({}) }
  }
}

Segundo, envía los mensajes que Lua enviaría. Desde la consola del navegador, o un botón solo de desarrollo:

js
window.postMessage({ action: 'open', data: { items: [{ name: 'water', count: 3 }] } }, '*')

Esto llama tu listener de message exactamente como lo hace SendNUIMessage. Puedes diseñar, corregir la disposición y verificar el manejo de datos en el navegador, y mantener el juego para la verificación final del enfoque, datos reales y callbacks reales.

Consejo: elimina los stubs de la compilación de producción, o envuélvelos para que solo se ejecuten cuando la página se abre fuera del juego, como arriba con el if en GetParentResourceName.

Lista de verificación

Síntoma Solución
NUI en blanco Abre nui_devtools, lee las pestañas Console y Network
nui_devtools no hace nada Actualiza el cliente y verifica tus configuraciones; prueba en un navegador normal
Uncaught TypeError ... of undefined Registra event.data y coincide con las claves enviadas por SendNUIMessage
404 para un archivo Listalo en files y verifica ui_page
POST https://resource/name falla Registra el callback con RegisterNUICallback y usa exactamente el mismo nombre
Nombre de recurso incorrecto en la URL Usa GetParentResourceName()
El botón funciona, nada sucede en Lua Asegúrate de que el callback llame a cb('ok')
Cursor atrapado después de cerrar Llama a SetNuiFocus(false, false)

Respuestas rápidas

¿Cómo abro las herramientas de desarrollador para una NUI en FiveM?

Abre la consola F8 en el juego y ejecuta nui_devtools. Se abre una ventana de herramientas de desarrollador de Chromium para la capa NUI. La disponibilidad puede depender de tus configuraciones y compilación del cliente.

¿Por qué falla mi callback de NUI?

La solicitud a https://resource_name/callback no llegó a Lua. El callback no está registrado con RegisterNUICallback, el nombre del recurso en la URL es incorrecto, o el callback nunca responde con cb.

¿Puedo probar mi NUI sin iniciar el juego?

Sí. Abre la página en un navegador normal o ejecuta el servidor dev de Vite, envía mensajes falsos con window.postMessage, y simula los callbacks. Solo el juego real te da enfoque, datos reales y callbacks reales.

Scripts que evitan este problema

Mic PhoneUn móvil plegable que se abre en tablet y llega al móvil real del jugador.Ver script →Arcade MachinesSiete juegos arcade jugables en máquinas reales, con clasificaciones y apuestas.Ver script →CCTV Security CamerasCámaras colocables, una tablet con vista múltiple en vivo y fotos como prueba.Ver script →

Sigue leyendo