tailwindlabs / headlessui

Completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS.
https://headlessui.com
MIT License
26.13k stars 1.08k forks source link

HeadlessUI is not working with Nuxt 3 #982

Closed bayramorhan closed 2 years ago

bayramorhan commented 2 years ago

What package within Headless UI are you using?

@headlessui/vue

What version of that package are you using?

"devDependencies": {
    "autoprefixer": "^10.4.0",
    "nuxt3": "latest",
    "postcss": "^8.4.4",
    "tailwindcss": "^2.2.19"
  },
  "dependencies": {
    "@headlessui/vue": "^1.4.2",
    "@heroicons/vue": "^1.0.5",
    "@tailwindcss/forms": "^0.3.4"
  }

Describe your issue

It works fine with development but when I build nuxt (nuxi build) and start (yarn start) it gives error. I've tried to import headless ui component from @headlessui/vue/dist/index.js instead of @headlessui/vue but its still same.

TypeError: Cannot read property 'buttonRef' of undefined
    at setup (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2622:15)
    at callWithErrorHandling (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:7158:22)
    at setupStatefulComponent (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:6874:29)
    at setupComponent (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:6855:11)
    at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9757:17)
    at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9863:22)
    at renderVNodeChildren (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9878:9)
    at renderElementVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9929:17)
    at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9860:17)
    at renderVNodeChildren (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9878:9)
[Vue warn]: inject() can only be used inside setup() or functional components.
TypeError: Cannot read property 'menuState' of undefined
    at Proxy.render$1 (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2522:17)
    at renderComponentRoot (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:2015:44)
    at renderComponentSubTree (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9828:51)
    at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9773:16)
    at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9863:22)
    at renderVNodeChildren (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9878:9)
    at renderElementVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9929:17)
    at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9860:17)
    at renderVNodeChildren (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9878:9)
    at renderElementVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9929:17)
[Vue warn]: inject() can only be used inside setup() or functional components.
[Vue warn]: Unhandled error during execution of watcher callback
TypeError: Cannot read property 'itemsRef' of undefined
    at ReactiveEffect.fn (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2685:24)
    at ReactiveEffect.run (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\reactivity\dist\reactivity.cjs.js:164:29)
    at ComputedRefImpl.get value [as value] (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\reactivity\dist\reactivity.cjs.js:1075:39)
    at D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2336:26
    at callWithErrorHandling (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6615:22)
    at callWithAsyncErrorHandling (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6624:21)
    at ReactiveEffect.getter [as fn] (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6970:24)
    at ReactiveEffect.run (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\reactivity\dist\reactivity.cjs.js:164:29)
    at doWatch (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:7078:16)
    at Object.watchEffect (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6890:12)
[Vue warn]: inject() can only be used inside setup() or functional components.
TypeError: Cannot read property 'menuState' of undefined
    at Proxy.render$1 (D:\projects\headless-test\nuxt3-app\.output\server\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:2656:17)
    at renderComponentRoot (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:2015:44)
    at renderComponentSubTree (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9828:51)
    at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9773:16)
    at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9863:22)
    at renderComponentSubTree (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9828:13)
    at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9773:16)
    at renderVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9863:22)
    at renderComponentSubTree (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9780:9)
    at renderComponentVNode (file:///D:/projects/headless-test/nuxt3-app/.output/server/chunks/index.mjs:9773:16)
bencehusi commented 2 years ago

+1 on this one.

akdenizbengisu commented 2 years ago

+1

cgrlcr commented 2 years ago

+1

vanling commented 2 years ago

It works for me with the following package.json/versions.

Can you share your .vue script where you import and call what you need.

{
  "private": true,
  "scripts": {
    "dev": "nuxi dev",
    "build": "nuxi build",
    "start": "node .output/server/index.mjs"
  },
  "devDependencies": {
    "@headlessui/vue": "^1.4.2",
    "@iconify/json": "^1.1.434",
    "@nuxtjs/eslint-config-typescript": "^7.0.2",
    "@pinia/nuxt": "^0.1.5",
    "@tailwindcss/aspect-ratio": "^0.3.0",
    "@tailwindcss/forms": "^0.3.4",
    "@vueuse/core": "^7.1.2",
    "autoprefixer": "^10.4.0",
    "nuxt3": "latest",
    "pinia": "^2.0.4",
    "postcss": "^8.3.11",
    "tailwindcss": "^2.2.19",
    "unplugin-icons": "^0.12.18"
  },
  "pnpm": {
    "overrides": {
      "@nuxt/kit": "npm:@nuxt/kit-edge@latest",
      "@nuxt/kit-edge": "latest"
    }
  },

}
bayramorhan commented 2 years ago

Are you trying in development mode or production mode with built files (.output) ?

import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue';

export default {
  layout: 'individual-main',
  components: {
    Menu,
    MenuButton,
    MenuItem,
    MenuItems,
  },
  setup() {...
vanling commented 2 years ago

I have it working in both, dev and production build. I didn't try to use them in pages directly, I create components with headlessui parts in it. (should not make a difference) let me test this right now

bayramorhan commented 2 years ago

I have it working in both, dev and production build. I didn't try to use them in pages directly, I create components with headlessui parts in it. (should not make a difference) let me test this right now

Thank you for your response. I also tried with this nuxt 3 starter but I 've got same error.

https://github.com/productdevbook/nuxt3-app?ref=bestofvue.com

vanling commented 2 years ago

Is your default "open" state true? for example let isOpen = ref(true); ?

vanling commented 2 years ago

I got the same errors now with the Menu components. On page and also when its wrapped in a component. Only in the server on SSR.

[Vue warn]: provide() can only be used inside setup().
[Vue warn]: provide() can only be used inside setup().
[Vue warn]: inject() can only be used inside setup() or functional components.
TypeError: Cannot read properties of undefined (reading 'buttonRef')

We need to make a small reproduction i think

vanling commented 2 years ago

Reproduction

https://codesandbox.io/s/angry-orla-qf02s?file=/pages/index.vue

Opening a new terminal and running npm run build && PORT=4000 node .output/server/index.mjs\

EDIT:

CodeSandbox is to complicated for this simple test

created: https://github.com/vanling/nuxt3-issue-reproduction/ It doesn't get more basic then this npm i && npm run build && npm run start open localhost:3000 and check terminal for errors in server

misaon commented 2 years ago

+1

weleo commented 2 years ago

Adding to this issue as a reminder because there is more than one issue with HeadlessUI x Nuxt 3.

I am getting the following error in Safari using the Disclosure component in a production environment:

TypeError: null is not an object (evaluating 't.insertBefore').  

The component also doesn't work in other browsers, but it shows no error messages in the console. Hoping to use HeadlessUI in Nuxt 3 sometime in the future 🤞

RobinMalfait commented 2 years ago

Hey! Thank you for your bug report! Much appreciated! 🙏

This should be fixed, and will be available in the next release.

You can already try it using:

Blakeinstein commented 2 years ago

@headlessui/vue@insiders

This throws an error with the webpack bundler. Webpack support is important as nuxt3's vite implementation doesnt resolves dynamic assets via props properly.

To reproduce, in vaning's repro https://github.com/vanling/nuxt3-issue-reproduction/, in nuxt.config.ts set

export default defineNuxtConfig({
  ...,
  vite: false
});

Here is the error.

✔ Server Compiled successfully in 2.03s                                                    23:36:20
✔ Client Compiled successfully in 2.15s                                                    23:36:20
✔ Client Compiled successfully in 242.09ms                                                 23:36:20
✔ Nitro built in 319 ms                                                                    23:36:20
✔ Server Compiled successfully in 81.98ms                                                  23:36:21
(node:132991) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)

 ERROR  [worker] Cannot use import statement outside a module                              23:36:50

  import{defineComponent as X,ref as A,provide as Oo,inject as To,onMounted as st,onUnmounted as Co,computed as w,nextTick as L,watchEffect as pt,toRaw as dt,watch as Ro}from"vue";import{h as so,cloneVNode as po}from"vue";function S(t,n,...a){if(t in n){let o=n[t];return typeof o=="function"?o(...a):o}let e=new Error(`Tried to handle "${t}" but there is no handler defined. Only defined handlers are: ${Object.keys(n).map(o=>`"${o}"`).join(", ")}.`);throw Error.captureStackTrace&&Error.captureStackTrace(e,S),e}function g({visible:t=!0,features:n=0,...a}){if(t||n&2&&a.props.static)return ye(a);if(n&1){let e=a.props.unmount??!0?0:1;return S(e,{[0](){return null},[1](){return ye({...a,props:{...a.props,hidden:!0,style:{display:"none"}}})}})}return ye(a)}function ye({props:t,attrs:n,slots:a,slot:e,name:o}){let{as:r,...u}=D(t,["unmount","static"]),p=a.default?.(e);if(r==="template"){if(Object.keys(u).length>0||Object.keys(n).length>0){let[l,...i]=p??[];if(!fo(l)||i.length>0)throw new Error(['Passing props on "template"!',"",`The current component <${o} /> is rendering a "template".`,"However we need to passthrough the following props:",Object.keys(u).concat(Object.keys(n)).map(s=>`  - ${s}`).join(`
  ^^^^^^

  SyntaxError: Cannot use import statement outside a module
  at Object.compileFunction (node:vm:352:18)
  at wrapSafe (node:internal/modules/cjs/loader:1031:15)
  at Module._compile (node:internal/modules/cjs/loader:1065:27)
  at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
  at Module.load (node:internal/modules/cjs/loader:981:32)
  at Function.Module._load (node:internal/modules/cjs/loader:822:12)
  at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:190:29)
  at ModuleJob.run (node:internal/modules/esm/module_job:185:25)
  at async Promise.all (index 0)
  at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
Raymonf commented 2 years ago

Hello! It doesn't seem to work with Vite, either, after compilation:

(base) raymonf@Raymonf-MBP frontend % yarn start      
yarn run v1.22.17
warning ../../../../package.json: No license field
$ node .output/server/index.mjs
Listening on http://localhost:3000/
Named export 'Menu' not found. The requested module '@headlessui/vue' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@headlessui/vue';
const { Menu, TransitionRoot, MenuItems, MenuItem, MenuButton } = pkg;

  at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)  
  at async ModuleJob.run (node:internal/modules/esm/module_job:181:5)  
  at async Promise.all (index 0)  
  at async ESMLoader.import (node:internal/modules/esm/loader:281:24)  
  at async file://./.output/server/chunks/app/render.mjs:527:24  
  at async renderMiddleware (file://./.output/server/chunks/app/render.mjs:575:20)  
  at async handle (file://./.output/server/node_modules/h3/dist/index.mjs:601:19)
Named export 'Menu' not found. The requested module '@headlessui/vue' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@headlessui/vue';
const { Menu, TransitionRoot, MenuItems, MenuItem, MenuButton } = pkg;

  at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)  
  at async ModuleJob.run (node:internal/modules/esm/module_job:181:5)  
  at async Promise.all (index 0)  
  at async ESMLoader.import (node:internal/modules/esm/loader:281:24)  
  at async file://./.output/server/chunks/app/render.mjs:527:24  
  at async renderMiddleware (file://./.output/server/chunks/app/render.mjs:575:20)  
  at async handle (file://./.output/server/node_modules/h3/dist/index.mjs:601:19)
Blakeinstein commented 2 years ago

Hello! It doesn't seem to work with Vite, either, after compilation:

Strange, the repro when using the insider build was working with the vite bundler, but not webpack

Raymonf commented 2 years ago

@Blakeinstein I actually tried it anyways, and for some reason my site did load without problems even though this error was spat out. SSR seemed to be correct, too, with the client not complaining during hydration. I'm not really sure what's happening. 😅

Blakeinstein commented 2 years ago

@Blakeinstein I actually tried it anyways, and for some reason my site did load without problems even though this error was spat out. SSR seemed to be correct, too, with the client not complaining during hydration. I'm not really sure what's happening. sweat_smile

I am myself now getting the same error? I changed the import statement to be

import * as headlessui from '@headlessui/vue'

const { Popover, PopoverButton, PopoverPanel } = headlessui

and now am getting the type: module error as i got in webpack.

@RobinMalfait I think its a bit too early to close this issue.

misaon commented 2 years ago

Do you transpile @headlessui/vue package in nuxt.config ?

https://v3.nuxtjs.org/concepts/esm/#transpiling-libraries

Blakeinstein commented 2 years ago

Do you transpile @headlessui/vue package in nuxt.config ?

v3.nuxtjs.org/concepts/esm/#transpiling-libraries

Can confirm this works. But not sure if this is a fix or a workaround.

misaon commented 2 years ago

Do you transpile @headlessui/vue package in nuxt.config ? v3.nuxtjs.org/concepts/esm/#transpiling-libraries

Can confirm this works. But not sure if this is a fix or a workaround.

it's definitely a workaround, HeadlessUi needs to work so that it can be imported natively into Nuxt 3 without build bugs. but for now it is enough for us.

RobinMalfait commented 2 years ago

Did a few improvements and it fixes the important parts, it's a proper type: module and all cjs files are using .cjs instead of `.js.

You can already try it using npm install @headlessui/vue@insiders or yarn add @headlessui/vue@insiders.


Creating a new Nuxt 3 app and loading Headless UI gives me the expected output without console warnings.

image

@Blakeinstein When I pull down the repro you provided, and bump to the latest insiders version I linked above then I do get the correct output:

image

The terminal correctly outputs the following information:

image

However, it looks like there is a server side rendering Nuxt bug once you load the page:

image

After some digging, @thecrypticace found that Nuxt loads 2 versions of Vue which results in these errors because they check if the same instance of Vue is used. But you should get this warning for any external library that depends on Vue, I think.

image


Can somebody verify the latest insiders build?

Blakeinstein commented 2 years ago

Can somebody verify the latest insiders build?

Can confirm that it is fixed, both on vite and on webpack. Apart from said errors warnings. Much thanks!

RobinMalfait commented 2 years ago

Thanks for testing, @Blakeinstein!

Going to close this issue, if somebody still has an issue, please open a new issue with a reproduction. Also make sure that for now you have to use the insiders build.

NidMo commented 2 years ago

感谢您的测试,@Blakeinstein!

打算关闭这个问题,如果有人仍然有问题,请打开一个带有复制的新问题。还要确保现在您必须使用insiders构建。

this problem is nuxt3 bug? how can i use headlessUI in nuxt3? install headlessUI@insiders?

Blakeinstein commented 2 years ago

this problem is nuxt3 bug? how can i use headlessUI in nuxt3? install headlessUI@insiders?

npm install @headlessui/vue@insiders or yarn add @headlessui/vue@insiders.

Thats it

oliviermills commented 2 years ago

Solution (workaround) tldr;

  1. Use the insiders version of @headless ui: npm install @headlessui/vue@insiders or yarn add @headlessui/vue@insiders

  2. Add the library for transpiling during build in nuxt.config.ts|js:

    
    import { defineNuxtConfig } from 'nuxt3'

export default defineNuxtConfig({ build: { transpile: ['@headlessui/vue'] } })


3. build, then nuxi preview, and voilà. Works.
Blakeinstein commented 2 years ago
2. Add the library for transpiling during build in `nuxt.config.ts|js`

I am using it in prod without adding this package to transpile

benoitdemaegdt commented 2 years ago

Hey there 👋

I'm currently facing very similar issue using headlessui with Nuxt3.

Until version 3.0.0-27447229.20f3171 of Nuxt, everything was working fine 👌

Then I tried to update latest Nuxt version (current version is 3.0.0-27457855.7c0b914) and :

When looking at logs, it seems that errors and warns are coming from headlessui

TypeError: Cannot read properties of undefined (reading 'button')
    at setup (/.output/server/node_modules/@headlessui/vue/dist/headlessui.esm.js:4:46368)
[Vue warn]: Component PopoverButton  is missing template or render function.
TypeError: Cannot read properties of undefined (reading 'panel')
at setup (/.output/server/node_modules/@headlessui/vue/dist/headlessui.esm.js:4:49526)
[Vue warn]: Component PopoverPanel  is missing template or render function.

I also tried to use @headlessui/vue@insiders with no significant change. Anyone facing similar issue with latest nuxt 3 releases ?

benoitdemaegdt commented 2 years ago

These errors are probably coming from Nuxt.

See this github issue : https://github.com/nuxt/nuxt.js/issues/13500 And this one : https://github.com/nuxt/nuxt.js/issues/12996

Blakeinstein commented 2 years ago

When looking at logs, it seems that errors and warns are coming from headlessui

The thing is, its most likely another error in your code. Those errors can be ignored, but nuxt doesnt report the errors properly making some headlessui events (like expanding popovers) break. I faced this in a particular instance but I cannot recall what error I had, but it was not in headless ui