Отладка FiveM NUI: nui_devtools, ошибки консоли и неудачные обратные вызовы

Отладьте FiveM NUI: откройте Chromium devtools с nui_devtools, прочитайте ошибки Uncaught TypeError, исправьте неудачную выборку в https://resource/cb и протестируйте пользовательский интерфейс в браузере.

Ваш NUI открывается как пустая панель, кнопка ничего не делает, или появляется курсор, но экран не следует. Обычно нет ошибки Lua, потому что проблема на веб-странице. Вам нужна консоль браузера, и у FiveM она есть. Это руководство объясняет, как её открыть, как читать её ошибки и как протестировать ваш пользовательский интерфейс без игры.

Откройте devtools: nui_devtools

NUI — это страница Chromium внутри игры. Нажмите F8, чтобы открыть консоль FiveM и запустите:

text
nui_devtools

Окно devtools откроется для слоя NUI, как то, что вы знаете из браузера. Используйте эти вкладки:

  • Console: ошибки JavaScript и ваши собственные строки console.log.
  • Network: каждый запрос, который делает страница, включая обратные вызовы к Lua.
  • Elements: живой HTML и CSS. Используйте его, чтобы увидеть, существует ли ваш элемент, насколько он большой и скрыт ли он.
  • Sources: устанавливайте точки разрыва в вашем скрипте.

Внимание: доступность nui_devtools зависит от ваших настроек и версии клиента, которую вы запускаете. Если команда ничего не делает, убедитесь, что ваш игровой клиент обновлён, и протестируйте пользовательский интерфейс в обычном браузере, как показано ниже.

Если ваш пользовательский интерфейс видимый только после SendNUIMessage, откройте devtools сначала и запустите действие потом, чтобы вы видели прибывающие сообщения.

Прочитайте ошибки консоли

Ошибки на вкладке Console показывают файл и строку вашего скрипта. Те, которые вы будете видеть чаще всего:

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

Ваш код прочитал .items на чём-то, что undefined. В NUI это почти всегда исходит от сообщения:

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

Проверьте, что действительно отправила Lua. Сначала распечатайте всё сообщение:

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

Затем сравните это с вызовом Lua:

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

Ключи должны совпадать ровно, включая регистр. Поле, установленное в nil в Lua, отсутствует в сообщении, поэтому оно undefined в JavaScript.

Другие частые ошибки:

Сообщение консоли Обычная причина
Uncaught ReferenceError: x is not defined Файл скрипта не загрузился, или опечатка в имени
Uncaught SyntaxError Сломанный файл скрипта, или выходные данные бандлера с неправильным путём
Failed to load resource: 404 Файл не указан в files в fxmanifest, или путь неправильный
Uncaught (in promise) TypeError: Failed to fetch Запрос обратного вызова не удался, смотрите ниже

Если на вкладке Network показано 404 для вашего JS, CSS или изображений, добавьте каждый файл, загружаемый страницей, в files в манифесте и укажите ui_page на правильный HTML:

lua
ui_page 'web/index.html'

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

Для сборки Vite или React используйте папку вывода, смотрите FiveM NUI с React и Vite.

Неудачная выборка в https://resource/cb

NUI отправляет сообщения Lua с запросом в https://<resource name>/<callback name>:

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

На вкладке Network неудачный запрос показан красным:

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

Проверьте эти пункты по порядку:

  1. Обратный вызов не зарегистрирован. Имя после слеша должно совпадать с RegisterNUICallback на клиенте, ровно:
lua
RegisterNUICallback('close', function(data, cb)
    SetNuiFocus(false, false)
    cb('ok')
end)
  1. Имя ресурса неправильное. Хост в URL — это имя папки ресурса. Если вы переименовали папку, жёстко закодированный https://old_name/close не работает. Используйте GetParentResourceName() на странице, как выше, чтобы имя следовало за папкой.
  2. Обратный вызов никогда не ответит. Всегда вызывайте cb(...), даже с cb('ok'). Обработчик, который возвращается без вызова, оставляет запрос в ожидании, и страница может ждать вечно.
  3. Обработчик Lua ошибается до cb. Проверьте консоль F8 на ошибку скрипта в тот же момент. Ошибка до cb означает, что ответ никогда не отправляется.
  4. Ресурс не запущен. Обратные вызовы существуют так долго, как клиентский скрипт, который их зарегистрировал.

Фокус и курсор

Если пользовательский интерфейс показан, но его не удаётся щёлкнуть, или мышь зависает после закрытия, проблема в SetNuiFocus, а не на странице. Смотрите NUI focus stuck cursor.

Протестируйте пользовательский интерфейс в обычном браузере

Отладка в игре медленная. Большую часть NUI можно протестировать в браузере с живой перезагрузкой вашего редактора.

Откройте index.html через локальный сервер или запустите npm run dev для проекта Vite. Затем заглушите две вещи, которые игра обычно предоставляет.

Сначала, поддельный GetParentResourceName и обратные вызовы, которые не могут не пройти:

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

Во-вторых, отправляйте сообщения, которые отправила бы Lua. Из консоли браузера или кнопки только для разработки:

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

Это вызывает ваш слушатель message ровно так же, как SendNUIMessage. Вы можете проектировать, исправлять макет и проверять обработку данных в браузере, и держать игру для финальной проверки фокуса, реальных данных и реальных обратных вызовов.

Совет: удалите заглушки из выпускной сборки или оберните их так, чтобы они запускались только при открытии страницы вне игры, как выше с if на GetParentResourceName.

Контрольный список

Симптом Решение
Пустой NUI Откройте nui_devtools, прочитайте вкладки Console и Network
nui_devtools ничего не делает Обновите клиент и проверьте ваши настройки; протестируйте в обычном браузере
Uncaught TypeError ... of undefined Зарегистрируйте event.data и совпадите ключи, отправленные SendNUIMessage
404 для файла Указайте его в files и проверьте ui_page
POST https://resource/name не работает Зарегистрируйте обратный вызов с RegisterNUICallback и используйте точное имя
Неправильное имя ресурса в URL Используйте GetParentResourceName()
Кнопка работает, ничего не происходит в Lua Убедитесь, что обратный вызов вызывает cb('ok')
Курсор зависает после закрытия Вызовите SetNuiFocus(false, false)

Короткие ответы

Как открыть devtools для FiveM NUI?

Откройте консоль F8 в игре и запустите nui_devtools. Окно Chromium devtools откроется для слоя NUI. Доступность может зависеть от ваших настроек и версии клиента.

Почему мой обратный вызов NUI не работает?

Запрос к https://resource_name/callback не достиг Lua. Обратный вызов не зарегистрирован с помощью RegisterNUICallback, имя ресурса в URL неправильное, или обратный вызов никогда не ответит с cb.

Могу ли я протестировать мой NUI без запуска игры?

Да. Откройте страницу в обычном браузере или запустите dev сервер Vite, отправляйте фальшивые сообщения с window.postMessage и заглушите обратные вызовы. Только реальная игра даёт вам фокус, реальные данные и реальные обратные вызовы.

Скрипты без этой проблемы

Mic PhoneСкладной телефон, который раскладывается в планшет и работает и на настоящем телефоне игрока.Смотреть скрипт →Arcade MachinesСемь аркадных игр в настоящих автоматах, с таблицами рекордов и ставками.Смотреть скрипт →CCTV Security CamerasУстанавливаемые камеры, планшет с мультиэкраном в реальном времени и распечатанные фото-улики.Смотреть скрипт →

Читайте также