nuxt / devtools

Unleash Nuxt Developer Experience
https://devtools.nuxt.com
MIT License
2.85k stars 153 forks source link

fix: DevTools cannot be showed in Chrome and Firefox on Nuxt v4 #698

Closed pan93412 closed 1 month ago

pan93412 commented 1 month ago

🐛 The bug

I am using the nightly version of Nuxt (4.0.0-28693174.8aefb554). I found Nuxt DevTools (no matter the nightly or @nuxt/devtools@1.3.9) does not work on Chrome 126 and Firefox 129.0b6 (Attachment 2). Notably, it works on Safari 17.5 (Attachment 1). It used to work on Nuxt v3.

image image

When adding breakpoints to the code related to Nuxt DevTools, I found Firefox (and Chrome) indeed ran import("./view/client") but setupDevToolsClient was never called, as the Attachment 3 shown. Safari ran as expected (Attachment 4). Not sure why.

https://github.com/user-attachments/assets/df0c3b68-3e77-4791-ba55-f837bfe0efb5

https://github.com/user-attachments/assets/0ad4a9cd-7570-4cb4-b62f-df250b996a32

🛠ī¸ To reproduce

https://github.com/pan93412/nuxt-4-devtools-regression

🌈 Expected behavior

The Nuxt DevTools should be able to show on Chrome, Firefox, and Safari.

ℹī¸ Additional context

I am using macOS 14.5 (23F79) if this matters.

pan93412 commented 1 month ago

Upgraded to the latest nightly (4.0.0-28693174.8aefb554) and this is still reproducible. The import() is unresolvable. Ref: https://t.me/c/1066867565/1855779

https://github.com/user-attachments/assets/0f9c20a6-367a-48dd-a2ba-a0953dc1a797

telegram-cloud-photo-size-5-6125390261027717374-y

pan93412 commented 1 month ago

After bisecting the Nuxt version, I found this issue started with the Nuxt commit 8f95cac3: https://github.com/nuxt/nuxt/compare/5f819ab8..8f95cac3 (https://github.com/nuxt/nuxt/pull/27702). In other words, it worked in the previous Nightly version, 5f819ab8.

Unfortunately, the 8f95cac3 commit is about upgrading Nitro and h3. I may need to investigate further what caused the DevTools to break.

pan93412 commented 1 month ago

Continue bisecting. After bisecting https://github.com/nuxt/nuxt/pull/27702, I confirmed this regression happened in the commit nuxt/nuxt@3245849 (#27702).

Note that even I set experimental.serverAppConfig: true in nuxt.config.ts, the DevTools is still not shown up.


After the comparison of the code in nuxt/nuxt@3245849 (#27702), I can confirm there is a unresolvable Promise in this snippets:

import { defuFn } from 'defu'

const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)}

/** client **/
// Vite - webpack is handled directly in #app/config
if (import.meta.dev && !import.meta.nitro && import.meta.hot) {
  console.log("A0")  // -- reachable
  const { updateAppConfig } = await import('#app/config')
  console.log("A1")  // -- unreachable
  import.meta.hot.accept((newModule) => {
    updateAppConfig(newModule.default)
  })
}
/** client-end **/

await import('#app/config') is also an unresolvable promise.

Rolling back await import('#app/config') to the original ES import behavior fixes up the DevTools (not what the commit originally what to do though đŸ˜ĸ):

import { updateAppConfig } from '#app/config'
import { defuFn } from 'defu'

const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)}

/** client **/
// Vite - webpack is handled directly in #app/config
if (import.meta.dev && !import.meta.nitro && import.meta.hot) {
  console.log("A0")  // -- reachable
  // const { updateAppConfig } = await import('#app/config')
  console.log("A1")  // -- reachable, DevTools can show up then!
  import.meta.hot.accept((newModule) => {
    updateAppConfig(newModule.default)
  })
}
/** client-end **/
pan93412 commented 1 month ago

After the final investigation, I can conclude this bug is a due to the circular import.

#app/config contains this import ^1:

import { reactive } from 'vue'
import { klona } from 'klona'
import type { AppConfig } from 'nuxt/schema'
import { useNuxtApp } from './nuxt'
// @ts-expect-error virtual file
import __appConfig from '#build/app.config.mjs'  // oops

#build/app.config.mjs is basically the content I mentioned above ^2:

import { defuFn } from 'defu'

const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)}

/** client **/
// Vite - webpack is handled directly in #app/config
if (import.meta.dev && !import.meta.nitro && import.meta.hot) {
  const { updateAppConfig } = await import('#app/config')  // oops
  import.meta.hot.accept((newModule) => {
    updateAppConfig(newModule.default)
  })
}
/** client-end **/

@danielroe Would you like to take a look with this issue? I can open a PR to revert the await import('#app/config') to import { updateAppConfig } from '#app/config'.

danielroe commented 1 month ago

Thank you @pan93412 - that would be very helpful 🙏