Déboguer FiveM NUI : nui_devtools, erreurs de console et rappels échoués

Déboguer une NUI FiveM : ouvrez les outils de développement Chromium avec nui_devtools, lisez les erreurs Uncaught TypeError, corrigez une récupération échouée vers https://resource/cb et testez l'interface utilisateur dans un navigateur.

Votre NUI s'ouvre en tant que panneau vide, un bouton ne fait rien, ou le curseur apparaît et aucun écran ne suit. Il y a généralement aucune erreur Lua, car la faute est dans la page web. Vous avez besoin de la console du navigateur, et FiveM en a une. Ce guide couvre comment l'ouvrir, comment lire ses erreurs et comment tester votre interface utilisateur sans le jeu.

Ouvrir les outils de développement : nui_devtools

NUI est une page Chromium à l'intérieur du jeu. Appuyez sur F8 pour ouvrir la console FiveM et exécutez :

text
nui_devtools

Une fenêtre d'outils de développement s'ouvre pour la couche NUI, comme celle que vous connaissez d'un navigateur. Utilisez ces onglets :

  • Console : erreurs JavaScript et vos propres lignes console.log.
  • Network : chaque demande que la page effectue, y compris les rappels à Lua.
  • Elements : le HTML et CSS en direct. Utilisez-le pour voir si votre élément existe, sa taille et s'il est masqué.
  • Sources : définissez des points d'arrêt dans votre script.

Attention : que nui_devtools soit disponible dépend de vos paramètres et de la build client que vous exécutez. Si la commande ne fait rien, vérifiez que le client de votre jeu est à jour, et testez l'interface utilisateur dans un navigateur normal comme indiqué ci-dessous.

Si votre interface utilisateur n'est visible que après un SendNUIMessage, ouvrez d'abord les outils de développement et déclenchez l'action après, afin que vous voyiez les messages qui arrivent.

Lire les erreurs de la console

Les erreurs dans l'onglet Console montrent le fichier et la ligne de votre script. Celles que vous verrez le plus :

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

Votre code a lu .items sur quelque chose qui est undefined. Dans NUI, cela provient presque toujours du message :

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

Vérifiez ce que Lua a vraiment envoyé. Imprimez d'abord le message entier :

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

Ensuite, comparez-le à l'appel Lua :

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

Les clés doivent correspondre exactement, y compris la casse. Un champ défini à nil en Lua est absent du message, donc il est undefined en JavaScript.

Autres erreurs courantes :

Message de la console Cause habituelle
Uncaught ReferenceError: x is not defined Un fichier de script ne s'est pas chargé, ou une faute de frappe dans un nom
Uncaught SyntaxError Un fichier de script cassé, ou une sortie bundler avec le mauvais chemin
Failed to load resource: 404 Un fichier n'est pas listé dans files dans le fxmanifest, ou le chemin est incorrect
Uncaught (in promise) TypeError: Failed to fetch Une demande de rappel a échoué, voir ci-dessous

Si l'onglet Réseau affiche un 404 pour votre JS, CSS ou images, ajoutez chaque fichier que la page charge à files dans le manifeste, et pointez ui_page vers le bon HTML :

lua
ui_page 'web/index.html'

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

Pour une build Vite ou React, utilisez le dossier de sortie, voir FiveM NUI with React and Vite.

Récupération échouée vers https://resource/cb

NUI envoie des messages à Lua avec une demande à https://<resource name>/<callback name> :

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

Dans l'onglet Réseau, une demande échouée s'affiche en rouge :

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

Vérifiez ceci dans l'ordre :

  1. Le rappel n'est pas enregistré. Le nom après la barre oblique doit correspondre à un RegisterNUICallback sur le client, exactement :
lua
RegisterNUICallback('close', function(data, cb)
    SetNuiFocus(false, false)
    cb('ok')
end)
  1. Le nom de ressource est incorrect. Le hôte dans l'URL est le nom du dossier de ressource. Si vous avez renommé le dossier, un https://old_name/close codé en dur échoue. Utilisez GetParentResourceName() dans la page, comme ci-dessus, afin que le nom suive le dossier.
  2. Le rappel ne répond jamais. Appelez toujours cb(...), même avec cb('ok'). Un gestionnaire qui retourne sans l'appeler laisse la demande en attente, et la page peut attendre indéfiniment.
  3. Le gestionnaire Lua erreur avant cb. Vérifiez la console F8 pour une erreur de script au même moment. Une erreur avant cb signifie que la réponse n'est jamais envoyée.
  4. La ressource n'est pas en cours d'exécution. Les rappels vivent aussi longtemps que le script client qui les a enregistrés.

Focus et le curseur

Si l'interface utilisateur s'affiche mais ne peut pas être cliquée, ou si la souris reste coincée après la fermeture, le problème est SetNuiFocus, pas la page. Voir NUI focus stuck cursor.

Testez l'interface utilisateur dans un navigateur normal

Le débogage en jeu est lent. La plupart d'une NUI peut être testée dans un navigateur, avec le rechargement en direct de votre éditeur.

Ouvrez index.html via un serveur local, ou exécutez npm run dev pour un projet Vite. Ensuite, effectuez une stub des deux choses que le jeu fournit normalement.

Premièrement, un faux GetParentResourceName, et des rappels qui ne échouent pas :

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 () => ({}) }
  }
}

Deuxièmement, envoyez les messages que Lua enverrait. Depuis la console du navigateur, ou un bouton dev uniquement :

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

Cela appelle votre écouteur message exactement comme SendNUIMessage le fait. Vous pouvez concevoir, corriger la mise en page et vérifier la manipulation des données dans le navigateur, et conserver le jeu pour la vérification finale du focus, des données réelles et des vrais rappels.

Astuce : supprimez les stubs de la build de production, ou enveloppez-les pour qu'ils ne s'exécutent que lorsque la page est ouverte en dehors du jeu, comme ci-dessus avec le if sur GetParentResourceName.

Liste de contrôle

Symptôme Correction
NUI vierge Ouvrez nui_devtools, lisez les onglets Console et Réseau
nui_devtools ne fait rien Mettez à jour le client et vérifiez vos paramètres ; testez dans un navigateur normal
Uncaught TypeError ... of undefined Connectez event.data et faites correspondre les clés envoyées par SendNUIMessage
404 pour un fichier Le lister dans files et vérifier ui_page
POST https://resource/name échoue Enregistrer le rappel avec RegisterNUICallback et utiliser le nom exact
Nom de ressource incorrect dans l'URL Utiliser GetParentResourceName()
Le bouton fonctionne, rien ne se passe dans Lua S'assurer que le rappel appelle cb('ok')
Curseur coincé après la fermeture Appeler SetNuiFocus(false, false)

Réponses rapides

Comment ouvrir les outils de développement pour une NUI FiveM ?

Ouvrez la console F8 en jeu et exécutez nui_devtools. Une fenêtre d'outils de développement Chromium s'ouvre pour la couche NUI. La disponibilité peut dépendre de vos paramètres et de votre build client.

Pourquoi mon rappel NUI échoue-t-il ?

La demande à https://resource_name/callback n'a pas atteint Lua. Le rappel n'est pas enregistré avec RegisterNUICallback, le nom de ressource dans l'URL est incorrect, ou le rappel ne répond jamais avec cb.

Puis-je tester mon NUI sans démarrer le jeu ?

Oui. Ouvrez la page dans un navigateur normal ou exécutez le serveur de développement Vite, envoyez des messages faux avec window.postMessage, et effectuez une stub des rappels. Seul le vrai jeu vous donne le focus, les données réelles et les vrais rappels.

Des scripts sans ce problème

Mic PhoneUn téléphone pliable qui se déplie en tablette et se prolonge jusqu’au vrai téléphone du joueur.Voir le script →Arcade MachinesSept jeux d’arcade jouables dans de vraies bornes, avec classements et paris.Voir le script →CCTV Security CamerasDes caméras à placer, une tablette multi-vues en direct et des photos imprimées comme preuves.Voir le script →

À lire aussi