Is Nuxt.js (not pure Vue) check - vue.js

Is there a way to check is Nuxt.js is being used?
Why I need to do it
For the UI frameworks development, herewith it's unknown will be used with Nuxt.js or just pure Vue. For example, depending on Vue or Nuxt, we need different link component:
<component is="isNuxt ? 'nuxt-link' : 'router-link'" />
What it the implementation of isNuxt method?

I think the easy way could be:
const isNuxt = () => !!window.$nuxt

Related

How to use onBeforeRouteLeave in Nuxt?

I am new to Nuxt and I am not able to find how to use onBeforeRouteLeave in Nuxt with composition API
If possible to give me an example it will be great Thanks
Nuxt 3 uses Vue Router for routing. The documentation goes over onBeforeRouteLeave Here.
OnBeforeRouteLeave acts as a guard to prevent a page from leaving before a task is completed. Heres an example of how it could be used that you may be familiar with!
onBeforeRouteLeave (to, from) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (!answer) return false
}

Pass ref to default slot in renderless component

I am trying to build a renderless component in vue 3 and want to pass a ref to the default slot.
When I am using the h render function I can just pass a ref:
return h('div', {ref: someRef}); // works
If I try to do the same with the default slot, it does not work:
return slots.default({ ref: someRef}) // does not work
return slots.default({ someRef}) // also does not work
Is there any way to do this without wrapping the default slot into another div or similar?
Checked already the documentation and other resources, but couldn't find any solution.
Direct answer
Yes return a function from your setup hook!
setup(_, slots) {
const someRef = ref()
return () => slots.default({ ref: someRef })
}
vue3 docs link
vue3 docs for renderless component pattern
Contextual answer for those in the comment section questioning the renderless/headless pattern
Yes, sometimes you just want a renderless (or headless as the kids these days say) wrapper for functionality (logic), without limiting the HTML that consumers can use.
But for that functionality to work, the renderless/headless component still needs to identify some of the HTML that consumers render into the default slot, in order to provide DOM-related functionality for example.
I have the same struggle when using this pattern, and have been relying on a "hack": passing specific data attributes via slot scope, that consumers need to bind to the desired elements (not only root) and then using good old document.querySelector to grab them
I has served me well in vue2 and I've been using it in production with no problems, but I was wondering if with the new dynamic :ref attribute of vue3, we can do it differently: probably passing a reactive ref variable and then doing a simple assign, and apparently it works.
<renderless #default="{ someRef }">
<some-consumer-comp :ref="(el) => someRef.value = el" />
</renderless>
Here's a sandbox demo old way for vue 2
Here's a sandbox demo new way for vue 3
Do note that if you want to handle edge cases, like handling conditional rendering of slot content, you probably need to do a bit more work and add some watchers.
This pattern is a bit out of fashion these days, with the introduction of vue composables since you can abstract the logic into a useSomeFunctionality and use it directly on the component you want, but it's sill a valid one IMO.
Cheers!

Is overriding a global Vue component safe?

Let's say there is a global component BIcon.vue available everywhere.
And another component, but regular not global, called BIconFake.vue.
We can override BIcon.vue by BIconFake.vue like that:
<template>
<div>
<b-icon icon="plus"><!-- <- Here is it BIconFake component! -->
</div>
</template>
<script>
import BIcon from '~/components/BIconFake'
export default {
components: {
BIcon // <- BIconFake component inside!
}
}
</script>
By this way, Vue.js will display BIconFake component instead of regular BIcon component.
I tried to pass props, events or attributes and it works like expected.
Vue.js is awesome... and big. Really, I don't know everything about it, and I don't want to see side effects or unexpected behavior when doing this override.
So, I want to know if it's safe to do that? Does it make a mess in Vue.js instance? What about memory?
we can override component with pure vue.js. Also, I made this example for Buefy, but we can do that with any UI frameworks like Quasar, Vuetify...
Thinking globaly, Is it good to override components of UI frameworks? What about security, scalability and maintenability?
In fact, I searched a way to build a plugins or addons system to my Nuxt.js app, like wordpress plugins.
Is it a good architecture to start building my app by overriding vue component? Is there another way to build app addons for vue, by using npm or webpack?
If you are going to wrap existing components like that then you should keep in mind the Liskov substitution principle. <b-icon-fake> can likely be used in place of <b-icon> provided that it:
accepts the same props
emits the same events
exposes the same public methods (if it is used with a ref)
behaves in the same way
Most of those points probably do not apply for a simple <b-icon> component.
Also keep in mind the template of your wrapped component now includes an extra <div> around it. This can interfere with styling and things like that.
You can eliminate the additional memory overhead by using a functional component instead, but you will need to write the render function manually to preserve the behavior of the wrapped component. But honestly I wouldn't worry too much about memory usage unless you have determined it to be an issue (after profiling your app).
In terms of whether it is "good" to do this or not, I can't say. There are advantages and disadvantages. In my opinion, wrapping components is fine as long as you are the only consumer of the wrapper component and doing so doesn't affect any existing usage of the wrapped component outside of your code.

Can Vue.js be used to build a Pluggable component across frontend frameworks

I would like to build a pluggable component (preferably in vue) that is going to be used across projects with different frameworks.
global.app = () => {
new Vue({
el: element,
components: { App },
template: '<div><App/></div>',
});
};
I tried instantiating the above vue instance directly into a react component and angular component. It seems to work fine.
I had read articles about plugging vue in react (vuera, react-vue), angular and angularJS. However, I am not sure what kind of performance tradeoffs this idea can bring in.
Is it a good idea to have two different frameworks working together? How else to approach this problem?

Preserve component state with vue-router?

I have a listing/detail use case, where the user can double-click an item in a product list, go to the detail screen to edit and then go back to the listing screen when they're done. I've already done this using the dynamic components technique described here: https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components. But now that I'm planning to use vue-router elsewhere in the application, I'd like to refactor this to use routing instead. With my dynamic components technique, I used keep-alive to ensure that when the user switched back to the list view, the same selection was present as before the edit. But it seems to me that with routing the product list component would be re-rendered, which is not what I want.
Now, it looks like router-view can be wrapped in keep-alive, which would solve one problem but introduce lots of others, as I only want that route kept alive, not all of them (and at present I'm just using a single top level router-view). Vue 2.1 has clearly done something to address this by introducing include and exclude parameters for router-view. But I don't really want to do this either, as it seems very clunky to have to declare up front in my main page all the routes which should or shouldn't use keep-alive. It would be much neater to declare whether I want keep-alive at the point I'm configuring the route (i.e., in the routes array). So what's my best option?
You can specify the route you want to keep alive , like:
<keep-alive include="home">
<router-view/>
</keep-alive>
In this case, only home route will be kept alive
Vue 3
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
Exactly as is, you don't need a Component attribute in the App.vue. Also your this'll work even if your components don't have a name property specified.
I had a similar problem and looked at Vuex but decided it would require too much changes/additions in my code to add to the project.
I found this library https://www.npmjs.com/package/vue-save-state which solved the problem for me, keeping the state of 1 component synchronized with localStorage, and it only took a few minutes and a few lines of code (all documented in the Github page of the package).
One solution without localStorage:
import {Component, Provide, Vue} from "vue-property-decorator";
#Component
export default class Counter extends Vue {
#Provide() count = 0
/**
* HERE
*/
beforeDestroy() {
Object.getPrototypeOf(this).constructor.STATE = this;
}
/**
* AND HERE
*/
beforeMount() {
const state = Object.getPrototypeOf(this).constructor.STATE;
Object.entries(state || {})
.filter(([k, v]) => /^[^$_]+$/.test(k) && typeof v !== "function")
.forEach(([k]) => this[k] = state[k]);
}
}
What seems to me is you are looking for some kind of state management. If you have data which is shared by multiple components and you want to render component in different order, but dont want to load data again for each component.
This works like following:
Vue offers a simple state management, but I will recommend to use Vuex which is a standard for state management among vue community.