Nuxt not automatically importing components from nested directory - vue.js

In my nuxt app, components in nested directories are not automatically importing as expected. For some of my components i have something like the following:
vue 2.6.12, nuxt 2.15.0
components\ Directory structure
TopArea\
--SomeComponent.vue
<template>
<header class="header">
<div>Hello</div>
<SomeComponent />
</header>
</template>
No other component in the application has the name SomeComponent. In the example above i get the error: Unknown custom element: <SomeComponent> - did you register the component correctly? For recursive components, make sure to provide the "name" option.. I can get around the issue by specifying the directory name before the component filename (TopAreaSomeComponent), use the prefix option in nuxt.config, or by manually importing the component. This is confusing because the docs state:
Nested Directories
If you have components in nested directories such as:
components/baseButton.vue
The component name will be based on its own filename. Therefore, the component will be:
<button />
It goes on to say "We recommend you use the directory name in the filename for clarity". But that seems like a rule than a recommendation. If i don't use the directory name as part of the filename, dynamic imports are not working for components in nested directories.
Is this an error in the docs or am I reading it wrong?

Since Nuxt 2.15.0, components changed in the way they work as stated in this github issue.
Depending of you structure and how you want to handle your organization, you may edit your configuration accordingly to the migration guide available here: https://github.com/nuxt/components#v1-to-v2
Or you could also simply set the pathPrefix option to have all your components available without any prefix at all.
nuxt.config.js/ts
components: [
{
path: '~/components', // will get any components nested in let's say /components/test too
pathPrefix: false,
},
]
PS: this solution also works with Nuxt3.
This documentation actually do need an update, indeed: https://nuxtjs.org/docs/2.x/directory-structure/components#components-discovery
This is how it works: for a given page
<template>
<div>
<yolo-swag /> <!-- no need for <nested-yolo-swag /> here -->
</div>
</template>
And with the following file tree
Update for Nuxt3
Looks like this is the new official syntax
import { defineNuxtConfig } from 'nuxt'
export default defineNuxtConfig({
components: {
global: true,
dirs: ['~/components']
},
})

This may answered already. But to illustrate the solution to comers here here's the way according to docs:
<TopAreaSomeComponent />
if your components is nested deeply:
components / TopArea / SomeComponent.vue
https://nuxtjs.org/docs/directory-structure/components/#nested-directories

Related

attribute binding in vue 3

I'm new to Vue and currently trying to dynamically change the video or image source link by passing the data in through a prop. I created a component with specific template structure that I would like to pass in the source from the main app.js page. I've tried binding it in both areas but unsure if I'm doing it correctly. I tried using regular divs and stuff to embed the video in app.js and it shows the content perfectly.
parent element contains 'Video' component-
<Video theme="IL" :vidSrc="srcIL.vid"></Video>
import Video from "./components/Video.vue";
export default {
name: "App",
components: {
Video
},
data() {
return {
srcIL: {
vid: "./assets/invi-lines/invisible-lines-film.mp4"
}
};
}
child 'Video component'
<template>
<div class="introVid top">
<video controls :src="vidSrc"></video>
</div>
</template>
<script>
export default {
props: ["theme", "vidSrc"]
};
</script>
This seems like you have it set up properly, and it is hard to know exactly what is causing the issues from the info provided, but I'm going to make a guess that it might be that the asset is not getting bundled.
I tried using regular divs and stuff to embed the video in app.js and it shows the content perfectly
I suspect you had something like:
<video controls src="./assets/invi-lines/invisible-lines-film.mp4"></video>
which would have taken the resource from the assets and packaged it for use.
see relative-path-imports for details.
You can try forcing these to load using require somewhere in the project, which will force the compiler to copy the asset, but really, if you have dynamic assets (assuming there's more than a handful and they can change) you should have them in the public folder already, not in the source folder. So my recommendation is that you move the dynamic assets to the public folder (assuming that was your issue to begin with)

Cannot use vue-start-rating in nuxt.js?

Cannot Used vue-star-rating in nuxt.js ReferenceError
document is not defined
<template>
<star-rating v-model="rating"></star-rating>
</template>
import StarRating from "vue-star-rating";
export default {
components: {
StarRating
}
}
thi is my codesandbox
Currently vue-star-rating does not support SSR, however, there is a feature-request open for this.
Currently, the only way to get this working with nuxt is to downgrade vue-star-rating to 1.6.2 and wrap it in no-ssr tags,
<no-ssr>
<star-rating :rating="3"></star-rating>
</no-ssr>
The solution above didn't work for me.
So, I just took the library (2 components and 1 class) and moved it to my component folder, so the components support the SSR now.

Vue Template - Making any URLs found in returned text string to a link

I am working on a project that is Vue modular based (code used is: https://github.com/mishushakov/dialogflow-web-v2/blob/bc3ce7d7cf8e09a34b5fda431590bd48cc31f66b/src/App.vue)
Linking to the file I think need to make the change to, have been trying but I don't really know Vue at all and had not luck.
The returned message is plain text for example: this is a test message, please visit https://wwww.google.com
What I am trying to do, is from that text string, if a URL found is to create a link from that found URL
<RichComponent><RichBubble v-if="message.queryResult.fulfillmentText" :text="message.queryResult.fulfillmentText" /></RichComponent>
Is what the current code is that returns the data.
Is there a best way to achieve this? Is there a core function maybe?
I have tried to npm install linkify but cannot seem to get it working so maybe a direct approach would be better?
You can use linkifyjs to convert links in a string into anchor tags. The linkifyjs/lib/linkify-string.js file augments the String prototype with a linkify() method.
<template>
<p v-html="msg.linkify()"></p>
</template>
<script>
import 'linkifyjs/lib/linkify-string' // side effect: creates String.prototype.linkify
export default {
props: ['msg'],
}
</script>
It also exports that method if you prefer an explicit call:
<template>
<p v-html="linkify(msg)"></p>
</template>
<script>
import linkify from 'linkifyjs/lib/linkify-string'
export default {
props: ['msg'],
methods: {
linkify,
}
}
</script>

Vue components re-rendering on router push

I have created a global component that i share across multiple routes. i have simplified the component below for demonstration purposes.
#name area-wrapper
<template>
<div id="area">
<div id="area-menu">
<menu/>
</div>
<div id="area-content">
<slot/>
</div>
</div>
</template>
Within the menu is a navbar which has options that will change the content of the slot which i could just turn into a component v-bind:is component.
What i have done is created several page for the routing
pages
_entity <--*** forgot to include this ***
app
index.vue
_appId.vue
new.vue
Each of these pages includes the component above and then adds in their own content for id="area-content
What i have been noticing is that the entire area-wrapper is being reloaded when i move from
website.com/app/112 (pages/app/_appId.vue)
website.com/app/11 (pages/app/_appId.vue)
I have noticed that if i move the area-wrapper to a layout then it works the problem is that the component will eventually be shared with several apps but will have a different <menu/> and layouts do not have slots
I'm not sure why vue is re-rendering the entire component even though it is shared among all the pages and is the same across each page.
What am i missing here?
If this is expected behavior my question becomes, how can i create a shared component that acts like a layout that i include in several pages without adjusting the props and have it not constantly reload
+==== UPDATE ====+
i have been trying to get nest routes to work because i believe this is what i am after. However nuxt is not generating them correctly
Per the documentation(``) i need to change my stucture to
pages
_entity
messaging
settings
index.vue
msg
index.vue
messaging.vue(wrong - changed back to index.vue) -> within here add the <nuxt-child> component
messaging.vue(need to move to _entity folder to create children)
nuxt should create the child components. However it is still continuing to create full routes. i am using nuxt-i18n will that cause a problem?
routes
...
{
path: "/:entity/messaging/messaging",
component: _8a865700,
name: "entity-messaging-messaging___en"
}, {
path: "/:entity/messaging/:msg?",
component: _1ef926cc,
name: "entity-messaging-msg___en"
}, {
path: "/:entity/messaging/settings",
component: _7b358e6a,
name: "entity-messaging-settings___en"
}
I originally created the nested route within the folder.Instead, you need to put the parent page within the root of what directory the folder exists.
pages
_entity
messaging
settings
index.vue
msg
index.vue
messaging.vue(wrong - changed back to index.vue) -> within here add the <nuxt-child> component
messaging.vue(need to move to _entity folder to create children)
You should define routing in your app as suggested here (pure Vue) or here (with vue-router). Without it you are reloading a whole page (and the app) when you change the URL.

Why doesn't the nested component render as a slottable custom element?

Are there limitations to compiling Svelte components as custom elements? For instance, are we able to nest components? And fill slots in those nested components?
I'm having trouble using a Svelte component as a custom element in my older Vue app.
I've got a Select and a Modal component in this simplified example: https://svelte.dev/repl/4d4ad853f8a14c6aa27f6baf33751eb8?version=3.6.4
I'm then compiling these with a standard-fare rollup.config.js:
export default {
input: "src/components.js",
output: [
// ...
{ file: "dist/index.min.js", format: "umd", name }
],
plugins: [
svelte({
dev: !production,
customElement: true,
// ...
}),
resolve(),
commonjs(),
!production && livereload("public"),
production && terser()
],
// ...
};
Then I go to use the custom elements. On click of the <conversational-select>, I get markup that looks like the following:
<conversational-select label="Domains" firstvaluelabel="All Domains">
<!-- shadow-root -->
<style>...</style>
<span class="select" >
<div class="select-value">Governance Board</div>
<div class="select-label" ></div>
</span>
<!-- The below div is the appropriate markup for Modal but the style isn't inlined and isn't slotted.
<!-- maybe because it didn't append as <sk-modal>? -->
<div ><slot></slot></div>
</conversational-select>
The "Modal" is sort-of rendering. But it doesn't fill the slot with span .chips. Doesn't inline the styles like the conversational-select does. Doesn't seem to attach its own event listeners. But does seem to create the fade transition thanks to Svelte's transition:fade directive.
I can reproduce this with a vanilla html file, so it's not Vue's fault.
Am I breaking some known rule with custom elements, butting up against the limitations of Svelte's custom element compilation, or just mistaken somewhere?
I was the author of the Svelte github issue that has been mentioned. I believe that I have a fix here. There were a few issues that existed:
slotted was never set
"nested" elements were not being added correctly
I expect the Svelte authors to make changes to my pull request, but if you want to use it, you can:
Clone my branch
Run npm && npm build && npm link
Go to your project and run npm link svelte