Vue SSR issue with no ssr - vue.js

I'm using my own SSR boilerplate for Vue.
https://github.com/Djancyp/luna-vue-ssr-boilerplate
All working fine pages are SSR rendering.
The issue that I'm currently having is no SSR components are failing as soon as I import them to components.
server trow err:
ReferenceError: document is not defined
I'm aware of the issue is document does not exist on nodejs server.
My question is How can I stop rendering no SSR components on the server ?
-I've tried No-SSR but no joy.
my server-enty.ts
import createApp from './app'
const config = require('config')
const isDev = process.env.NODE_ENV !== 'production'
export default context => {
return new Promise((resolve, reject) => {
console.log('what the f server')
const s = isDev && Date.now()
const { app, router, store } = createApp(config)
const { url } = context
const { fullPath } = router.resolve(url).route
if (fullPath !== url) {
return reject({ url: fullPath })
}
router.push(url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
console.log(matchedComponents)
if (!matchedComponents.length) {
console.log('what the **** mate error')
return reject({ code: 404 })
}
Promise.all(matchedComponents.map(({ asyncData }) => asyncData && asyncData({
store,
route: router.currentRoute
}))).then(() => {
isDev && console.log(`data pre-fetch: ${Date.now() - s}ms`)
const meta = (app as any).$meta()
context.meta = meta
context.state = store.state
resolve(app)
}).catch(err => {
console.log(err)
return reject
})
}, reject)
})
}

Vue-SSR executes asyncData and serverPrefetch on the server-side. Remove these from your component, move the code to created/ 'mounted' and it should stop rendering on the server-side.
My assumption is that you are executing document. within asyncData or serverPrefetch.

Promise.all(matchedComponents.map(({ asyncData }) => asyncData && asyncData({
store,
route: router.currentRoute
}))).then(() => {
isDev && console.log(`data pre-fetch: ${Date.now() - s}ms`)
const meta = (app as any).$meta()
context.meta = meta
context.state = store.state
resolve(app)
}).catch(err => {
console.log(err)
return reject
})
}, reject)
the issue was that I was rejecting if the async template not exist.
Promise.all(matchedComponents.map(({ asyncData }) => asyncData && asyncData({
store,
route: router.currentRoute
}))).then(() => {
isDev && console.log(`data pre-fetch: ${Date.now() - s}ms`)
const meta = (app as any).$meta()
context.meta = meta
context.state = store.state
resolve(app)
}).catch(err => {
console.log(err)
return reject
})
})
this resolved the issue but needs to improve the code a little bit.
Thanks for helps guys.

Related

addRoute doesn't update route list

I try to adding routes to my router while the application is already running, more specifically after the connection.
I have this in my app.js
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const routes = [
{
path : '/',
name: 'principal',
component : PrincipalComponent,
},
{
path : '/403',
component : Erreur403Component,
}
];
const router = new VueRouter({routes});
export {router}
And in my vuex
import {router} from "../app.js"
const actions = {
loginUser({state, commit}, user) {
return new Promise((resolve, reject) => {
axios.get('/menuGeneration')
.then(data => {
data.data.forEach(route => {
router.addRoute({
path : "\test"
});
router.push("\test");
})
})
.catch(err => console.log(error);
console.log(router.getRoutes());
})
}
}
But I only have the first 2 routes declared in app.js
I have checked that axios sends me the list of menus
If anyone has a lead, I'm intereste !
For information :
vue#2.6.12
vue-router#3.6.5
vuex#3.6.0
UPDATE
After the advice yoduh of I modified the code following
axios.get('/menuGeneration')
.then(data => {
data.data.forEach(route => {
router.addRoute({
path : "/test",
component : TestComponent
});
})
console.log(router.getRoutes());
})
.catch(err => console.log(error);
And it's work
But when i add a replaces for the current resource
axios.get('/menuGeneration')
.then(data => {
data.data.forEach(route => {
router.addRoute({
path : "/test",
component : TestComponent
});
})
window.location.replace('/dashboard')
})
.catch(err => console.log(error);
it does not guard the routes.
what is the way to keep the routes ?
it does not guard the routes.
what is the way to keep the routes ?
You must always navigate using vue-router if you want vue-router's navigation guards to activate on route changes. This line:
window.location.replace('/dashboard')
can be replaced with the vue-router replace equivalent which will activate your navigation guards
router.replace('/dashboard')

How to commit mutation from `plugins` directory using Nuxt.js?

I have just run into such a problem, I am trying to customize Axios module, My aim is to access my dom.js vuex module state from 'plugins' directory, The code below works but I have the following error in the console
Do not mutate vuex store state outside mutation handlers
So, The reason for this error is also clear to me, I wonder how I can Commit mutation from 'plugins' directory to my dom.js vuex module?
Thanks!
//plugins/axios.js
export default function ({ $axios, redirect, store}) {
$axios.onError(error => {
const code = parseInt(error.response && error.response.status)
if (code === 401) {
store.state.dom.alertIs = true
redirect('/')
}
})
}
/store/dom.js
export const state = () => ({
alertIs:false
})
Declare a mutation (named "SET_DOM_ALERT") in your store:
// store/dom.js
export default {
state: () => ({
alertIs: false
}),
mutations: {
SET_DOM_ALERT(state, value) {
state.alertIs = value
}
}
}
Then, use store.commit('dom/SET_DOM_ALERT', newValue) in your plugin (notice the dom/ prefix for the namespace):
// plugins/axios.js
export default function ({ $axios, redirect, store}) {
$axios.onError(error => {
const code = parseInt(error.response && error.response.status)
if (code === 401) {
store.commit('dom/SET_DOM_ALERT', true) // 👈
redirect('/')
}
})
}
demo

How do I send response object from my get request to the front end with Express and Axios?

I am trying to pull data from MongoDB to populate some timers in this app I'm building. However, I can't seem to send my response to the front end with Axios. Here is my route on the backend:
const express = require('express');
const router = express.Router();
const TimerModel = require('../models/Timer');
router.get('/', async (req, res) => {
try {
const timers = await TimerModel.find({});
console.log('Succesful get req', timers);
res.send(timers);
} catch (err) {
console.log(err.message);
res.status(500).send('Server Error');
}
});
module.exports = router;
My console.log in the try statement prints the correct data but I'm having issues with sending it to the front end. Here is the component:
import React, { useState, useEffect } from 'react';
import Timer from '../Timer/Timer';
import axios from 'axios';
import './Wrapper.css';
function Wrapper() {
//State effects
useEffect(() => {
axios
.get('/')
.then((res) => {
console.log(res);
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
});
const handleChange = (event) => {
setTitle(event.target.value);
};
const addTimer = () => {
const timer = <Timer title={title} key={timers.length} />;
let allTimers = timers.slice();
allTimers.push(timer);
setTimers(allTimers);
setTitle('');
};
return (
//JSX Code
);
}
export default Wrapper;
In the axios call I make, I get this weird object when I run console.log(res) and I get my index.html for the res.data. Why don't I have access to the timers object I made with my backend request? Isn't it being sent when I run the command res.send(timers) in my route?
You need to add your API url in axios request. Currently, axios is taking url of your React website that is why your response have index.html file of React website.
useEffect(() => {
axios
.get('api_url/')
.then((res) => {
console.log(res);
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
});
You can save the result in a state like
`````````````
`````````````
const [time, setTimer] = useState(null)
useEffect(() => {
axios.get('/').then(res => setTimer(res.data)
}, [])
`````````````
`````````````
and then use time vairable where you want

How do I get nuxtServerInit to dispatch an action on the Server?

I have a nuxt project using firebase. I want to use SSR and initiate and populate the store on SSR but I cannot get the code below to work.
I am working on a nuxt project I have a plugin/firebase project that initiates the firebase sdk. I have an asyncData function that works.
in my /store/index.js file I export the state function and the actions. In the actions I have the async nuxtServerInit that dispatches a `posts/getPosts' action passing the context.
In my store/index I have
export const state = () => ({})
export const actions = {
async nuxtServerInit({ dispatch }, context) {
await dispatch('posts/getPosts', context)
}
}
In my 'store/posts.js` I have
import { db } from '~/plugins/firebase'
export const state = () => ({
ActivePosts: []
})
export const actions = {
getPosts({ commit }) {
const postList = []
return db
.collection('posts')
.where('status', '==', 'approved')
.orderBy('CreatedAt', 'desc')
.get()
.then(docs => {
docs.forEach(doc => {
const newPost = doc.data()
newPost.id = doc.id
this.postList.push(newPost)
console.log(newPost)
})
})
.then(() => {
commit('addPosts', postList)
})
.catch(e => console.log(e))
}
}
In my firebase plugin I have
import firebase from 'firebase'
const firebaseConfig = {
apiKey: '<<correctkey>>.',
authDomain: '<<correctkey>>',
databaseURL: '<<correctUrl>>',
projectId: '<<correctid>>',
storageBucket: '<<correctbucket>>',
messagingSenderId: '<<correctkey>>',
appId: '<<correctkey>>'
}
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig)
}
export const db = firebase.firestore()
export const auth = firebase.auth()
This code, at least I thought, should initiate my store on the server and fill it with post values. When I check my store in vue developer tools there are no values in the store, although the getter is present and the state values(empty array) is present. This tells me that the store is initiated and the module is present, at least on the client side.
Turns out the problem was not with my action but the mutation. Here is the final code that got me to working.
import { db } from '~/plugins/firebase'
export const state = () => ({
ActivePosts: []
})
export const getters = {
getPosts(state) {
return state.ActivePosts
}
}
export const mutations = {
addPosts(state, payload) { // had to change { state } to state.
state.ActivePosts.push(payload)
}
}
export const actions = {
getPosts({ commit }) {
const postList = []
return db
.collection('posts')
.where('status', '==', 'approved')
.orderBy('CreatedAt', 'desc')
.get()
.then(docs => {
docs.forEach(doc => {
const newPost = doc.data()
newPost.id = doc.id
postList.push(newPost) //removed the `this.`
})
commit('addPosts', postList) //moved the commit to the // moved the commit out of its own then.
})
.catch(e => console.log(e))
}
}

Vue Router beforeEach not being called

I'm currently having trouble finding a bug in router code, it worked before and I don't know when or how I broke it. I already checked in older versions but it seems to not have changed. The problem is that even when I'm deleting all code out of the beforeEach Hook in my router and just using a console.log() statement, nothing gets printed in the console and my auth-guard is therefore not working. I tried to change the order according to this: https://forum.vuejs.org/t/router-beforeeach-if-manually-input-adress-in-browser-it-does-not-work/12461/3 but nothing changed.
I am having the following code:
router/index.js
router.beforeEach = (to, from, next) => {
console.log('he?')
const currentUser = Firebase.auth().currentUser
const isGold = store.getters['user/isGold']
const requiresAuth = to.matched.some(route => route.meta.requiresAuth)
const requiresGold = to.matched.some(route => route.meta.requiresGold)
console.log(requiresGold, isGold, 'halloooooooo?')
if (currentUser && to.name === 'Login') {
next('/dashboard')
}
if (requiresGold && !isGold) {
console.log('trigger')
}
if (requiresAuth && !currentUser) {
next('/login')
} else {
next(false)
}
}
main.js
Firebase.auth().onAuthStateChanged(user => {
if (user) {
const getToken = () => {
return user.getIdToken(true).then(token => {
store.dispatch('user/setToken', token)
})
}
getToken().then(() => {
store.dispatch('user/setUser')
setInterval(getToken, 3540 * 1000)
})
}
new Vue({
el: '#app',
store,
router,
template: '<App/>',
components: { App }
})
})
Thanks in advance for any help!
You do not assign to router.beforeEach. router.beforeEach is a method, and you call it with a function. (docs) This is how you should use the router navigation guard:
router.beforeEach((to, from, next) => {
console.log('he?')
const currentUser = Firebase.auth().currentUser
const isGold = store.getters['user/isGold']
const requiresAuth = to.matched.some(route => route.meta.requiresAuth)
const requiresGold = to.matched.some(route => route.meta.requiresGold)
console.log(requiresGold, isGold, 'halloooooooo?')
if (currentUser && to.name === 'Login') {
next('/dashboard')
}
if (requiresGold && !isGold) {
console.log('trigger')
}
if (requiresAuth && !currentUser) {
next('/login')
} else {
next(false)
}
});