created hook for vuex / nuxtClientInit? - vue.js

I was wondering whats the best way to do something like nuxtClientInit. I'm trying to load the Auth State as early as possible on the client and save it in my vuex store but not on the server side. It would be great if vuex had something like the created hook for components but that doesn't exist to my knowledge.
How could I achieve this behavior? One way could be calling an action from a layout but is that the best way?

I understand the nuxt team are working on a nuxtClientInit feature but before they release that you could just make your own. To understand the workflow that nuxt undertakes when there is a request you can look at the lifecycle here. This shows that nuxtServerInit is called first then middleware. During this middleware call nuxt.config.js is served and this contains your custom configuration. Part of this is 'plugins' which as the docs say,
This option lets you define JavaScript plugins that should be run
before instantiating the root Vue.js application.
So if you write a plugin to call a store action you can then get and set your local storage from there. So, start with a nuxt-client-init plugin:
//nuxt-client-init.client.js
export default async context => {
await context.store.dispatch('nuxtClientInit', context)
}
then add the plugin to nuxt.config.js:
//nuxt.config.js
plugins: [
'~/plugins/nuxt-client-init.client.js'
],
If you notice the naming convention here, the .client.js part of the plugin tells nuxt this is a client only plugin and is shorthand for '{ src: '~/plugins/nuxt-client-init.js', mode: 'client' }' which since nuxt 2.4 is the way to define the old '{ src: '~/plugins/nuxt-client-init.js', ssr: false }'. Anyway, you now have a call to your store so you can have an action to call from local storage and set a state item.
//store/index.js
export const actions = {
nuxtClientInit({ commit }, { req }) {
const autho = localStorage.getItem('auth._token.local') //or whatever yours is called
commit('SET_AUTHO', autho)
console.log('From nuxtClientInit - '+autho)
}
}
You probably need to restart your app for that to all take effect but you are then getting and using your Auth State without any of that pesky nuxtServerInit business.

Related

Initate Session on page load

I have a requirement where I need to set Global Axios header and refresh session(Calling multiple Api's). In vuejs we would have a App.vue which is the entry point for our application we would do these types of processing in that.
App.vue
export default {
async created(){
await this.$store.dispatch('initateSession');
}
}
The benefits of doing this is that this is called only once(not on every route change), and on every page load, I am looking to implement the same functionlity in Nuxt.
Now as we dont have any App.vue in case of Nuxt one solution that i could think off is to create a middleware for this , which can work but that will be called on every route change I dont want that, does anyone know any workaround for it?
Instead of middleware you can create a plugin:
plugins/session.js:
window.onNuxtReady(() => {
// Do something
})
And then add it to the plugins section inside nuxt.config.js.

Fetching global api data in nuxt

I'm starting Nuxt project and I have to fetch basic data from my backend.
for example language dictionary or some data for leftbar and etc.
in Vue I can just call everything I need in App.vue and save it in vuex and then use whenever I want, but with Nuxt every page is different and I'm curious where should i call this global data api calls.
I'm guessing I have to create middleware and call actions if data is not loaded already or there is better solution?
You mention it's global data and you're using universal mode- I think you're looking for nuxtServerInit(). This store action runs once on the server, before created, mounted hooks etc. You can use it to populate your store with data that your components (including pages) rely on.
Take a look at the docs.
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user) {
commit('user', req.session.user)
}
}
}

How can I load JSON config file and let the Vue app wait for this?

A typical scenario for me is:
a Vue app (packed with webpack, BTW)
a separate config file for configuring the app
The config file should not be included in the webpacked deployment package, since it is server-dependent (database credentials etc.)
For some reason I am not intending to elaborate on here I keep the config in a JSON file.
So the question is:
How can I delay "starting" the Vue app until the JSON config file has been loaded (and parsed) from the backend?
I know how to load and parse, but the question for me is Vue-specific: what's the best practice to "wait" for something before starting the whole thing?
(Is something like beforeCreate lifecycle hook in the App.vue component the way to go? Does it play nice with asynchronous tasks like loading a JSON file over the net?)
One way that I have used to solve this kind of issue is to use the router.beforeEach. Here is an example of my code:
router.beforeEach(async (to, from, next) => {
if (!store.state.initialized) {
// the store initialize will set initialized to true
await store.dispatch('initialize')
}
// if user not logged in or the route is not public
if (!store.state.user && !to.meta.public) {
next('/login')
} else {
next();
}
});

“window is not defined” in Nuxt.js

I get an error porting from Vue.js to Nuxt.js.
I am trying to use vue-session in node_modules. It compiles successfully, but in the browser I see the error:
ReferenceError window is not defined
node_modules\vue-session\index.js:
VueSession.install = function(Vue, options) {
if (options && 'persist' in options && options.persist) STORAGE = window.localStorage;
else STORAGE = window.sessionStorage;
Vue.prototype.$session = {
flash: {
parent: function() {
return Vue.prototype.$session;
},
so, I followed this documentation:
rewardadd.vue:
import VueSession from 'vue-session';
Vue.use(VueSession);
if (process.client) {
require('vue-session');
}
nuxt.config.js:
build: {
vendor: ['vue-session'],
But I still cannot solve this problem.
UPDATED AUGUST 2021
The Window is not defined error results from nodejs server side scripts not recognising the window object which is native to browsers only.
As of nuxt v2.4 you don't need to add the process.client or process.browser object.
Typically your nuxt plugin directory is structured as below:
~/plugins/myplugin.js
import Vue from 'vue';
// your imported custom plugin or in this scenario the 'vue-session' plugin
import VueSession from 'vue-session';
Vue.use(VueSession);
And then in your nuxt.config.js you can now add plugins to your project using the two methods below:
METHOD 1:
Add the mode property with the value 'client' to your plugin
plugins: [
{ src: '~/plugins/myplugin.js', mode: 'client' }
]
METHOD 2: (Simpler in my opinion)
Rename your plugin with the extension .client.js and then add it to your plugins in the nuxt.config.js plugins. Nuxt 2.4.x will recognize the plugin extension as to be rendered on the server side .server.js or the client side .client.js depending on the extension used.
NOTE: Adding the file without either the .client.js or .server.js extensions will render the plugin on both the client side and the server side. Read more here.
plugins: ['~/plugins/myplugin.client.js']
There is no window object on the server side rendering side. But the quick fix is to check process.browser.
created(){
if (process.browser){
console.log(window.innerWidth, window.innerHeight);
}
}
This is a little bit sloppy but it works. Here's a good writeup about how to use plugins to do it better.
Its all covered in nuxt docs and in faq. First you need to make it a plugin. Second you need to make your plugin client side only
plugins: [
{ src: '~/plugins/vue-notifications', mode: 'client' }
]
Also vendor is not used in nuxt 2.x and your process.client not needed if its in plugin with ssr false
In Nuxt 3 you use process.client like so:
if (process.client) {
alert(window);
}
If you've tried most of the answers here and it isn't working for you, check this out, I also had the same problem when using Paystack, a payment package. I will use the OP's instances
Create a plugin with .client.js as extension so that it can be rendered on client side only. So in plugins folder,
create a file 'vue-session.client.js' which is the plugin and put in the code below
import Vue from 'vue'
import VueSession from 'vue-session'
//depending on what you need it for
Vue.use(VueSession)
// I needed mine as a component so I did something like this
Vue.component('vue-session', VueSession)
so in nuxt.config.js, Register the plugin depending on your plugin path
plugins:[
...
{ src: '~/plugins/vue-session.client.js'},
...
]
In index.vue or whatever page you want to use the package... import the package on mounted so it is available when the client page mounts...
export default {
...
mounted() {
if (process.client) {
const VueSession = () => import('vue-session')
}
}
...
}
You can check if you're running with client side or with the browser. window is not defined from the SSR
const isClientSide: boolean = typeof window !== 'undefined'
Lazy loading worked for me. Lazy loading a component in Vue is as easy as importing the component using dynamic import wrapped in a function. We can lazy load the StepProgress component as follows:
export default {
components: {
StepProgress: () => import('vue-step-progress')
}
};
On top of all the answers here, you can also face some other packages that are not compatible with SSR out of the box and that will require some hacks to work properly. Here is my answer in details.
The TLDR is that you'll sometimes need to:
use process.client
use the <client-only> tag
use a dynamic import if needed later on, like const Ace = await import('ace-builds/src-noconflict/ace')
load a component conditionally components: { [process.client && 'VueEditor']: () => import('vue2-editor') }
For me it was the case of using apex-charts in Nuxt, so I had to add ssr: false to nuxt.config.js.

Nuxt - How can I run a code in client-side after server-side-rendering?

I created a plugin injecting a noty (https://ned.im/noty/#/) so I can use it globally, it looks like this:
export default ({ app }, inject) => {
const notify = function (options = {}) {
if (process.client) {
new Noty(options).show();
}
}
app.$notify = notify;
inject('notify', notify);
}
This plugin shows a noty only on the client-side. On the server-side a noty does not appear, cause it can be displayed only in browser.
I have a page with product details and I am receiving data in asyncData method. When the product was not found I would like to show a noty with proper message and redirect user to a product list page. When I change a route in client-side everything works awesome. However on the first page load (eg. I change an url manually in the browser) which happens on the server-side a noty does not appear, only a redirect works.
My question is: how to show a noty in this case? How to create a noty in the browser after SSR or what is the best other solution to my problem?
Is there any way to run some code after client-side is already rendered (after server-side-rendering)?
You could just disable ssr for that plugin.
plugins: [
...,
{ src: '~plugins/yourplugin.js', ssr: false }
]
Okay, I found a module for that: https://github.com/potato4d/nuxt-client-init-module
it's not possible right know (nuxt <= 2.14.0 when i answering)
but you can combine client plugin and client middleware to achieve that
please take a look at this link:
https://github.com/nuxt/nuxt.js/issues/2653#issuecomment-390588837