Call app.use for plugin in the component itself in vue 3 - vue.js

I'm building a component library that uses the v-tooltip plugin. So I need to install and use the plugin in the component itself instead using it globally with app.use().
I've read so many posts, and what I've tried so far doesn't work for my case.
I know that I can access the app in the Composition API as:
import VTooltip from 'v-tooltip';
import 'v-tooltip/dist/v-tooltip.css';
const App = getCurrentInstance().appContext.app;
App.use(VTooltip);
but that doesn't work, and I get this warning:
[Vue warn]: Component is missing template or render function.
Any help would be greatly appreciated.

to use this plugin in the component itself, you can try to do something like this:
<template>
<button v-tooltip="/* your code */"> Custom button </button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import VTooltip from "v-tooltip";
export default defineComponent({
directives: {
tooltip: VTooltip.VTooltip,
"close-popover": VTooltip.VClosePopover,
"v-popover": VTooltip.VPopover,
},
});
</script>

Thanks #Rago, you gave me an idea with the directives. The solution was really simple in this case... At the moment v-tooltip is undergoing a package rename (to floating-vue), so with the new plugin you can decide if you want to use a component or a directive.
This is the solution:
<template>
...
<span v-tooltip="help" class="form-help">?</span>
...
</template>
<script>
import 'floating-vue/dist/style.css';
import { VTooltip } from 'floating-vue';
export default defineComponent({
directives: {
tooltip: VTooltip,
},
...
});
</script>
And for the Composition API you just import it, and Vue will automatically detect the directive if you follow the naming convention - putting v in front of the directive:
import 'floating-vue/dist/style.css';
import { VTooltip } from 'floating-vue';
const vTooltip = VTooltip;

Related

Nuxt local import client only

I'm trying to use VuePlyr in Nuxt 2. Right now I have it working as a plugin /plugins/vue-plyr.js,
import Vue from 'vue'
import VuePlyr from '#skjnldsv/vue-plyr'
import 'vue-plyr/dist/vue-plyr.css'
Vue.use(VuePlyr)
but it is just used in one page, so I would like to remove it from the main bundle and just import it locally when used. I've tried this in my page (the template part was working when using the plugin).
<template>
<client-only>
<vue-plyr>
<div data-plyr-provider="vimeo" :data-plyr-embed-id="id" />
</vue-plyr>
</client-only>
</template>
<script>
import 'vue-plyr/dist/vue-plyr.css'
import Vue from 'vue'
export default {
async mounted () {
const VuePlyr = await import('#skjnldsv/vue-plyr')
Vue.use(VuePlyr)
}
}
</script>
but unfortunately, I'm getting this error
[Vue warn]: Unknown custom element: <vue-plyr> - did you register the component correctly?
Any idea how I could achieve this? Related with How to make a dynamic import in Nuxt?
You could import it like that
export default {
components: {
[process.client && 'VuePlyr']: () => import('#skjnldsv/vue-plyr'),
}
}
As mentioned in a previous answer.
In your nuxt config define the plugin as client only:
plugins: [
{ src: "~/plugins/vue-plyr.js", mode: "client" }
],
Then also make sure there's a client-only tag around the use of the component:
<template>
<client-only>
<vue-plyr>
<div data-plyr-provider="vimeo" :data-plyr-embed-id="id" />
</vue-plyr>
</client-only>
</template>
Edit: importing the component again in the mounted method isn't necessary if you added it as a plugin

Vue: When to register component in main.js vs in the .vue file

Say I have a basic vue project
main.js:
import { createApp } from 'vue';
import App from './App.vue';
import SomeComponent from './components/SomeComponent.vue';
const app = createApp(App);
app.component('some-component', SomeComponent);
app.mount('#app');
components/App.vue:
<template>
<some-component></some-component>
</template>
<script>
import SomeComponent from "./SomeComponent.vue";
export default {
components: { SomeComponent },
};
</script>
components/SomeComponent.vue:
<template>
<div></div>
</template>
<script>
export default {};
</script>
Note that in main.js, I call app.component('some-component', SomeComponent); and in SomeComponent.vue I also specify the same with components: { SomeComponent },. Only one of the two ways is needed (though specifying both doesn't seem to cause errors).
My question is this: When would you specify components in main.js instead of in the component that will actually use it?
It seems that I could create an entire storefront and list all of the components in main.js without ever using components: {} inside a single one of my components and it would work. But it seems more logical to me to list the used sub-components inside each component that will use them for the encapsulation and reusability it brings. But that's because I have an object oriented mindset.

Import npm package into a Vue.js Single File component

I would like to use Jodit in a SFC, but I am not sure how this is supposed to be done. I realized there is a wrapper (jodit-vue), but for educational purposes, I would like to know how it's done without it. I created a Vue CLI project with default presets, and all I changed is the App.vue:
<template>
<div id="app">
<textarea id="editor" name="editor"></textarea>
</div>
</template>
<script>
import "../node_modules/jodit/build/jodit.min.js"
export default {
name: 'App',
created(){
let editor = new Jodit('#editor');
editor.value = '<p>start</p>';
}
}
</script>
<style>
#import "../node_modules/jodit/build/jodit.min.css" ;
</style>
This produces the error: error 'Jodit' is not defined no-undef, and
if I change the import to:
import Jodit from "../node_modules/jodit/build/jodit.min.js"
Then the compilation is fine, but the browser console says:
vue.runtime.esm.js?2b0e:1888 TypeError: _node_modules_jodit_build_jodit_min_js__WEBPACK_IMPORTED_MODULE_0___default.a is not a constructor
Admittedly, I am new to all of this, but pointing me to the right direction is appreciated.
The jodit module exports the Jodit constructor, so your component would import it like this:
import { Jodit } from 'jodit'
You'd also need the Jodit styles, which could be imported like this:
import 'jodit/build/jodit.min.css'
To create a Jodit instance, we need to provide an element or selector to an existing <textarea>. The Vue component's elements are available in the mounted() lifecycle hook (not in the created() hook), so that's where we would initialize:
export default {
mounted() {
const editor = new Jodit('#editor')
editor.value = '<p>start</p>'
},
}
demo

How do I import Three.js into my Nuxt project

I want to import modules in examples folder in THREE.js such as OBJLoader into my Nuxt Project.
I can import main folder of THREE, but error occurs when trying to import modules in examples folder.
Tried these steps in official docs.
https://threejs.org/docs/index.html#manual/en/introduction/Import-via-modules
I'm getting error below
SyntaxError
Unexpected token {
<template>
</template>
<script>
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
export default{
}
</script>
here are my github repository
https://github.com/ksuhara/threejs-test
Finally I could find what was wrong.
Well, it has to do with nuxt building system. When using third parts libs, you should add them into nuxt.config.js bild->transpile array so it can be included as a dependency with Babel.
transpile: [
"three"
]
Ref: https://nuxtjs.org/api/configuration-build#transpile
Threejs must be run on the client side so enclosed the component with <client-only> tag and loaded it dynamically with const MyComponent = () => import('~/path/to/MyComponent.vue'); but now I am getting the error on server side.
Finally I managed to do it like this!
<template>
<div>
<client-only>
<threejs-component />
</client-only>
</div>
</template>
<script>
export default {
components: {
ThreejsComponent: process.browser ? () => import('~/path/to/ThreejsComponent.vue') : null
}
}
</script>
inside ThreejsComponent.vue are all the threejs imports

Failed to mount component using vue-js-toggle-button

I tried to use the plugin for a project with Vue 2 but got a Vue warn like below.
[Vue warn]: Failed to mount component: template or render function not
defined
Inside vue component:
import ToggleButton from 'vue-js-toggle-button'
export default {
components: { ToggleButton }
}
Then,
<toggle-button :value="true" :labels="{checked: 'Foo', unchecked: 'Bar'}"/>
The plugin is not that popular and any help would be much appreciated.
You don't export the toggle button into another component. You import it in whatever component you want to use it and tell Vue to use it with Vue.use(ToggleButton). Then you can use it inside your component's template and export that whole component afterwards!
Example would be:
<template>
<toggle-button #someOfYourValues#></toggle-button>
</template>
In here, you don't import anything of the ToggleButton! You just use it as a tag inside your components!
Let's move on to your main js file where all the Vue instance creation takes place. Usually, it looks similar to this:
<script>
import Vue from 'vue'
import ToggleButton from 'vue-js-toggle-button'
Vue.use(ToggleButton)
new Vue({
el: #yourDivInTheBaseHTMLFile
# some other stuff for your vue instance
})
</script>
I tested it inside my own current Vue project, which is a todo list with lots of components. It literally works inside every single one of them when you do a Vue.use().
If needed, I can link you to the project so you can have a look, but this simple explanation should do it ;)
For completeness (Vue SFC Class):
src/main.ts:
import Vue from 'vue';
import ToggleButton from 'vue-js-toggle-button';
Vue.use(ToggleButton);
new Vue({
...
render: h => h(App)
}).$mount('#app');
src/components/MyComponent.vue:
<template>
<toggle-button />
</template>
<script lang="ts">
import { ... } from "vue-property-decorator";
// do NOT import the component in here
#Component({
components: {
// do NOT declare the component in here
}
})
export default class MyComponent extends Vue {
}
</script>
<style scoped lang="scss">
</style>