NuxtJS calling hooks from within plugin - javascript

Is it possible to use callHook in a custom plugin?
I have to register a custom service class for fetching data and the fastest way to do this was by registering my custom class within a module like this (example taken from this Medium post: https://medium.com/swlh/service-classes-using-plugins-in-nuxt-js-32c0f387ecb9):
// plugins/services.plugin.js
import { LoggingService } from '../logging.service'
export default ({ app }, inject) => {
// create an instance of the LoggingService with the prefix 'My App'
const logging = new LoggingService('My App')
// inject the service, making it available in the context, component, store, etc.
inject('logging', logging)
}
Everything works as expected except I can't for the life of me figure it out if I can define my custom hooks in a plugin. I figured if I can get a reference to the nuxt context I'd be able to do it. I did not find any information about whether what I'm trying to do was possible or not.

Related

How to use plugins in vuex (Vue 2x) [duplicate]

I declare a global variable in the main.js of the Vue.js project.
Vue.prototype.$API = "myapihere"
And I want to use this from everywhere.
and it's work properly by using this.$API.
But in Vuex it does not work.
console.log(this.$API);
Here this.$API is undefined.
How I use my $API in Vuex.
Vue 2 and Vuex 3 answer
In the store you can access the vue instance by accessing this._vm
const store = new Vuex.Store({
mutations: {
test(state) {
console.log(this._vm);
}
}
});
I'm using Vue 3 and Vue.prototype.$foo seems to have been removed for this version. I also found that in my version of VueX there is no this._vm.
I explored the Provide / Inject method which is recommended by the Vue 3 docs. This worked nicely for accessing globals from within my components, but I couldn't access them from within store.
The solution I went for was to use globalProperties on the Vue object and standard properties on store, and set them just before mounting the app.
main.js:
import store from './store/index';
import App from './App.vue';
// Load custom globals
import conf from '#/inc/myapp.config';
const app = createApp(App)
.use(store);
// Register globals in app and store
app.config.globalProperties.$conf = conf;
store.$conf = conf;
app.mount('#app');
What I like about this is that I can access the globals in the same way in both store and components.
In a component:
export default {
data() {
return {
};
},
created() {
console.log( this.$conf.API_URL );
},
}
...and you can access this.$conf.API_URL in the same way from actions, mutations and getters.
Once I'd found this solution I no longer needed access to the whole Vue instance from within store, but if you need it for some reason you can assign store.$app = app; in the same place in main.js.
You have 2 approaches:
Pass down the property (or even access the _vm property from inside Vuex) as an argument from a component
methods: {
this.$store.dispatch('someAction', this.$API)
}
Declare and export that same variable from another file and consume it from your main.js AND your Vuex file:
// api.js
export const API = "http://localhost:5000/api"
// main.js
import { API } from './api.js
...
Vue.prototype.$API = API
// store.js
import { API } from './api.js
// you can use API now!
Although I would personally lean towards the second, I would not store the API path in Vue at all as I'd rather have the api.js file as a service to perform all ajax calls and consume that file from where I need.
use this._vm
here is why
by default when you access this in vuex store it will point store so it will output something like this
so after that, you see that there is something called _vm in store here it is
so that _vm points to the vue component so to access it you will need to use this._vue
you can better create a getter of the vue instance like
const store = new Vuex.Store({
getters: {
vue(state) {
return this._vm
}
}
});
//so you can use it across your store
store.getters.vue
//Note
//the above way of accessing getter works on non `namespaced` stores
As of recently, under Vuex 4.* and Vue 3.*, this.$app hasn't been defined for the store object. Instead you have Vue Router defined as this.$router.
So for javascript, the way to get app in store would be like so:
The code would now be: router.app = app; and inside, say, an action: let app = this.$router.app;

Nuxtjs custom module

I'm quite new to Nuxtjs so I made a test project which purpose is merely the (of course) testing of Nuxtjs functionalities.
Currently I'm trying to create a simple custom module: afaik a module is basically a wrapper around a vou/js library/plugin, something like a high-level integration used to expose configurations on how the underlying library/plugin is imported and used in the Nuxt application.
So I'm trying with a simple module that declare some plain js classes that I'll use in my application, e.g. Order and Product, and that's what I came out with:
Directory structure
pages
the-page.vue
modules
classes
index.js
order.js
/modules/classes/index.js
const path = require('path')
export default function (moduleOptions) {
const { nuxt } = this
// add the debug plugin
this.addPlugin({
src: path.resolve(__dirname, 'order.js'),
})
}
/modules/classes/order.js
class Order {
constructor(id) {
this.id = id;
console.log('created order #' + this.id);
}
}
export {Order};
/nuxt.config.js
export default {
// ...
buildModules: [
// ...
'~/modules/classes'
],
// ...
}
/pages/the-page.vue
<script>
export default {
name: 'ThePage',
data () {
return {
}
},
methods: {
createOrder () {
const order = new Order(123)
}
}
}
</script>
The error
My defined class are still not imported in my pages:
/app/pages/the-page.vue
18:13 error 'order' is assigned a value but never used no-unused-vars
18:25 error 'Order' is not defined no-undef
Considerations
Probably I'm missing something about modules usage and/or implementation, but every tutorial I found starts with too complex scenarios, and since I'm at the beginning with Nuxtjs I need something easier to implement.
Ok, I found out that I was mistaken how NuxtJs modules are intended to work and was traying to do somenthing they are not intended for.
Nuxt modules cannot import js classes in every component of the application as I wanted to do, they just "add a property" to the main application instance that is made accessible through this.$<something>, like e.g. you can already do in simple Vue with the Vue Router or the Vuex store plugins that give access to the this.$router and this.$store properties.
NuxtJs modules just wrap simple plugins and expose configuration options to made.

How can I import compiled svelte-components/-apps into a svelte-app at runtime

Is it possible to dynamically import precompiled svelte components or whole svelte apps.
And when, how do I compile a single component in svelte 3. I found this approach, but nothing in the docs:
https://github.com/sveltejs/svelte/issues/1576
I want to combine several independent (hosted) Svelte apps on one page to one bigger svelte-app (microfrontend). The goal is, that every sub app can be independent deployed and hosted wherever (may be an own docker container). And any change should be visible in the aggregator app without recompiling it.
I think I wat to do something like this:
https://single-spa.js.org/docs/separating-applications.html
but with no other framework, that is blowing my app and components.
I don't want to use custom components, because of the inflexible styling of the Shadow DOM. I must be able to change css over a global stylesheet.
Has anyone an idea?
Thank you :)
You can take a look at Ara Framework. It has a standalone component named Nova Bridge.
This approach consists of a component that renders a placeholder micro-frontend view will be mounted. Then the component emits a DOM event named NovaMount that is listened by the JavaScript bundle of the micro-frontend to render it and mount it in run-time.
Here an example of the entry point for your micro-frontend.
import { mountComponent, load, loadById } from 'hypernova-svelte'
import Example from './components/Example.svelte'
const render = (name, { node, data }) => {
if (name === 'Example') {
return mountComponent(Example, node, data)
}
}
document.addEventListener('NovaMount', ({ detail }) => {
const { name, id } = detail
const payload = loadById(name, id)
if (payload) {
render(name, payload)
}
})
load('Example').forEach(render.bind(null, 'Example'))
The microfrontend uses hypernova-svelte. You can take a look in this article I wrote for implementing Svelte in Nuxt.
https://ara-framework.github.io/website/blog/2019/08/27/nuxt-js

Next.js: How to dynamically import external client-side only React components into Server-Side-Rendering apps developed?

I know this question has been asked multiple times before but none of the solution seems to work.
I'm trying to use the library 'react-chat-popup' which only renders on client side in a SSR app.(built using next.js framework) The normal way to use this library is to call import {Chat} from 'react-chat-popup' and then render it directly as <Chat/>.
The solution I have found for SSR apps is to check if typedef of window !=== 'undefined' in the componentDidMount method before dynamically importing the library as importing the library normally alone would already cause the window is not defined error. So I found the link https://github.com/zeit/next.js/issues/2940 which suggested the following:
Chat = dynamic(import('react-chat-popup').then(m => {
const {Foo} = m;
Foo.__webpackChunkName = m.__webpackChunkName;
return Foo;
}));
However, my foo object becomes null when I do this. When I print out the m object in the callback, i get {"__webpackChunkName":"react_chat_popup_6445a148970fe64a2d707d15c41abb03"} How do I properly import the library and start using the <Chat/> element in this case?
Next js now has its own way of doing dynamic imports with no SSR.
import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(
() => import('../components/hello3'),
{ ssr: false }
)
Here is the link of their docs: next js
I've managed to resolve this by first declaring a variable at the top:
let Chat = ''
then doing the import this way in componentDidMount:
async componentDidMount(){
let result = await import('react-chat-popup')
Chat = result.Chat
this.setState({
appIsMounted: true
})
}
and finally render it like this:
<NoSSR>
{this.state.appIsMounted? <Chat/> : null}
</NoSSR>
You may not always want to include a module on server-side. For
example, when the module includes a library that only works in the
browser.
Import the library normally in child component and import that component dynamically on parent component.
https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr
This approach worked for me.

Where to store common component methods in #NUXT.JS

Actually i want to know where to store common components methods in #NUXT.JS.
things which i have tried.
--> Storing common code in middleware (its use-less) because according to my knowledge middleware is only capable of handling request and response to server.
methods: {
// states methods.
SwitchManager: function (__dataContainer, __key, __value) {
// stand alone debugger for this module.
let debug = __debug('computed:_3levelSwitch')
// debug showing function loaded.
debug('(h1:sizeCheck) creating switch..')
// switch.
switch (__key) {
// fake allow set value to true of given key
default:
this[__dataContainer][__key][__value] = true
break
}
return this[__dataContainer][__key][__value]
},
SizeCheck: function (__size) {
// stand alone debugger for this module.
let debug = __debug('tags:p')
// debug showing function loaded.
debug('(p:sizeCheck) checking..')
// init switch.
this.SwitchManager('pill', 'size', __size)
},
StateCheck: function (__state) {
// stand alone debugger for this module.
let debug = __debug('tags:h1')
// debug showing function loaded.
debug('(h1:sizeCheck) checking..')
// init switch.
this.SwitchManager('pill', 'state', __state)
}
},
created () {
// h1 tag size check
this.SizeCheck(this.size)
this.StateCheck(this.state)
}
I go for mixins like with plain vue.js. Only difference - for global mixins - I include them as a plugin, but first:
Non global mixins
I would create an extra folder for my mixins. For example in a /mixins/testMixin.js
export default {
methods: {
aCommonMethod () {}
}
}
Then import in a layout, page or component and add it via the mixins object:
<script>
import commonMixin from '~/mixins/testMixin.js'
export default {
mixins: [commonMixin]
}
</script>
Global mixins
For example in a new file plugins/mixinCommonMethods.js:
import Vue from 'vue'
Vue.mixin({
methods: {
aCommonMethod () {}
}
})
Include that file then in nuxt.config.js
plugins: ['~/plugins/mixinCommonMethods']
After that you would have the method everywhere available and call it there with this.commonMethod(). But here an advice from the vue.js docs:
Use global mixins sparsely and carefully, because it affects every single Vue instance created, including third party components. In most cases, you should only use it for custom option handling like demonstrated in the example above. It’s also a good idea to ship them as Plugins to avoid duplicate application.
Inject in $root & context
Another possibility would be to Inject in $root & context

Categories