nuxt / nuxt

The Intuitive Vue Framework.
https://nuxt.com
MIT License
54.87k stars 5.02k forks source link

Support for explicit import global components #13413

Closed xiaoxiangmoe closed 2 years ago

xiaoxiangmoe commented 2 years ago

Can we use

<script setup lang="ts">
import { NuxtLink } from 'some-nuxt-lib-location'
</script>
<template>
  <div>
    <nuxt-link :to="`/test/123`">
      Random path
    </nuxt-link>
  </div>
</template>

Additional context

We use https://eslint.vuejs.org/rules/no-undef-components.html and all component should be registered locally.

danielroe commented 2 years ago

Would you provide a reproduction? I'm not sure what you mean.

xiaoxiangmoe commented 2 years ago

Not a bug. It's a feature request or question.

In vue-router, we can use import { RouterLink, RouterView } from 'vue-router'

<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
</script>

<template>
  <header> 
    <div class="wrapper"> 
      <nav>
        <RouterLink to="/">Home</RouterLink>
        <RouterLink to="/about">About</RouterLink>
      </nav> 
  </header>
  <RouterView />
</template>

see

https://github.com/vuejs/create-vue-templates/blob/284fcf591115e5cf39e4461e2fd4cd2c5ea009bb/typescript-router/src/App.vue#L1-L2

Which lib should I import when I use <NuxtLink>?

Can I write import { NuxtLink } from 'nuxt3' or something else?

<script setup lang="ts">
import { NuxtLink } from 'nuxt3'
</script>

<template>
  <header> 
    <div class="wrapper"> 
      <nav>
        <NuxtLink to="/">Home</NuxtLink>
        <NuxtLink to="/about">About</NuxtLink>
      </nav> 
  </header> 
</template>
lperez22 commented 2 years ago

You shouldn't have to import NuxtLink it will be auto imported by using the component. I have an example here https://stackblitz.com/edit/nuxt-starter-g2m6nk

atinux commented 2 years ago

You can learn more about the auto-import in https://v3.nuxtjs.org/concepts/auto-imports

danielroe commented 2 years ago

What do you think @pi0 - would it be useful to expose a #components import for directly importing from scanned components?

xiaoxiangmoe commented 2 years ago

We use https://eslint.vuejs.org/rules/no-undef-components.html and all component should be registered locally. So I can't use auto import in our project.

pi0 commented 2 years ago

Seems a good idea @danielroe. We had same possibility with Nuxt2 (https://github.com/nuxt/components/blob/main/templates/components/index.js)

Would be nice if we could also expose possible component names as an array as well.

baryla commented 2 years ago

I think this will definitely be useful, especially for peeps using JSX components. At the moment, doing something like this actually works:

// App.tsx
import { defineComponent } from 'vue';

export default defineComponent(() => {
  return () => (
    <NuxtLayout>
      <NuxtPage />
    </NuxtLayout>
  )
});

but because there are no imports, TS actually complains with Cannot find name 'NuxtLayout'. ts(2304) etc. This I guess could be fixed with something like a .d.ts file and registering a global type for them but it seems like a hacky workaround to be honest.

danielroe commented 2 years ago

@baryla FYI, there are global types registered in .nuxt/types/components.d.ts for auto-scanned components and also, for built-in Nuxt components: https://github.com/nuxt/framework/blob/dbab979a2ed28b8f3d02044079f6b9039114d5ff/packages/nuxt3/src/pages/runtime/router.ts#L18-L28.

baryla commented 2 years ago

@danielroe thanks for the reply. I just checked my .nuxt/types/components.d.ts and all I have in there is:

// Generated by components discovery
declare module 'vue' {
  export interface GlobalComponents {
    'NuxtWelcome': typeof import("../../node_modules/nuxt3/dist/app/components/nuxt-welcome.vue")['default'],
    'ClientOnly': typeof import("../../node_modules/nuxt3/dist/app/components/client-only")['default']
  }
}
export {}

I'm not sure if I should turn anything on in the settings? My nuxt.config.ts file has no settings turned on.

When I created a component in /components, it did generate a global type for it however, TS still complained that no imports have been defined when I use it so I'm not sure if I'm doing something wrong or...?

btw. 👆 this is from a completely fresh installation of Nuxt.

misaon commented 2 years ago

+1

zsilbi commented 1 year ago

My dev server hangs on specific routes on page reload when I import and use components imported from #components. It seems like a Vite issue, but if I import the same component from it's direct location the issue is gone. It also applies to built-in components like NuxtLink.

I was able to create a small reproduction of the issue, you can find it here: https://stackblitz.com/edit/nuxt-starter-azudzq?file=pages%2Findex.vue

slacktracer commented 1 year ago

Did you find a way to do it, @xiaoxiangmoe? Right now having to import things from #imports or #app is the worst thing about Nuxt for me. In particular it messes with auto sorting of imports.

TimofeyBiryukov commented 3 months ago

+1

AngeloSchulerPiletti commented 2 months ago

In my scenario, I want to import NuxtLink to use it in a dynamic component.

I found two different approaches for this:

  1. The first one is to import the NuxtLink as:
<script lang="ts" setup>
import NuxtLink from '#app/components/nuxt-link.js'
</script>

<template>
   <component
       :is="item.callback ? 'button' : NuxtLink"
   >
        Other stuff here
    </component>
</template>
  1. The second is to define nuxt link using the defineNuxtLink:
<script lang="ts" setup>
const nuxtLink = defineNuxtLink({})
</script>

<template>
   <component
       :is="item.callback ? 'button' : nuxtLink"
   >
        Other stuff here
    </component>
 </template>

Which is the correct approach? Both are working fine

danielroe commented 2 months ago

I would import from #components instead.

brendonmatos commented 2 months ago

Just to add, this is super useful when passing the component as a variable in Shadcn Vue. Just tested it and works perfectly

<script lang="ts" setup>
import { NuxtLink } from '#components'
</script>
<template>
   <UiButton :as="NuxtLink" :as="NuxtLink" :to="`/song/${id}`">Go to song page</UiButton>
</template>
AdrianFahrbach commented 2 months ago

I guess that the #components import kind of solves this problem, but I still agree with @slacktracer that the # imports are a bad practice. I usually disable auto-imports because when I want full control over my imports. Those # imports don't give me full control, they just cut the middleman. If the auto-generation of the import files isn't working for me or can't be used in my scenario, then I'm basically screwed. Same goes for Nuxt modules btw! There are lots of modules that don't even tell you where to import their components from.

Working without the Nuxt auto-imports is hard right now. It is opinionated towards that feature. I think DX features like that should build on top of the regular way of doing things and therefore would wish for normal imports of the global components outside of the auto-generation magic.