Accessing Vue Nuxt plugins in layouts using fetch() - vue.js

Wanted to ask if I am doing this right, it feels clunky. I am accessing a plugin in a Nuxt layout component. I want to dynamically generate content within the layout via the new fetch() api.
async fetch() {
this.notifications = await this.$root.context.app.contentfulClient.getNotifications()
this.treatments = await this.$root.context.app.contentfulClient.getTreatments()
},
It works as expected, but it seems a long handed way of accessing the plugin methods. Is this architecturally bad practice?

Nuxt plugins normally add properties to the Nuxt context, making them available from a component's this without having to explicitly drill into the context like you're doing.
Assuming your plugin injects contentfulClient like this:
// ~/plugins/contentfulClient.js
export default ({ app }, inject) => {
inject('contentfulClient', {
async getNotifications() {/*...*/},
async getTreatments() {/*...*/},
})
}
Then your component could use it like this:
async fetch() {
this.notifications = await this.$contentfulClient.getNotifications()
this.treatments = await this.$contentfulClient.getTreatments()
},

Related

Vue2 Composition Api - How do I fetch data from api?

I am using Vue2.6 with composition api.
I need to reroute to different pages depends on an api response.
Can someone please guide me, please?
I tried using onBeforeMount but it renders the UI elements then rerouted to the corresponding page to the api response..so I can see a flash of the wrong UI..
setup() {
const myData = 'myData';
onBeforeMount(async () => {
try {
const results = await fetchData();
// do reroute depends on results response
}
} catch (err) {
console.log(err);
}
});
return {
myData,
};
I also tried adding async in the setup method but it errored saying my ref variables "Property or method "myData" is not defined on the instance but referenced during render."
async setup() {
const myData = 'myData';
onMounted(async () => {
try {
const results = await fetchData();
// do reroute depends on results response
}
} catch (err) {
console.log(err);
}
});
return {
myData,
};
It looks like you're trying to handle routing (re-routing) dynamically from inside a component. I can't see the rest of the apps, so can't speak to the validity of such a solution, but would like you dissuade you from doing that. routing logic should, IMO, not be handled in a component. The components should mostly just handle the template and user interaction. By the time you're rendering a component, that API should have been resolved already.
I would recommend to resolve the API response before the route is
even completed. You or use a navigationGuard to resolve the API during the route execution. This functionality is asynchronous, so you can await the response before proceeding.
Alternatively, if you really want to handle it in the component, you will have that delay while the API is resolving, but you can implement some loader animation to improve the experience.

Awaiting code execution in quasar.dev boot file before vue.js instantiation

The quasar.dev framework introduces the concept of boot files: https://quasar.dev/quasar-cli/boot-files
Using the vue-oidc-client, I am required to wait for the oidc.startup() call before the Vue instance is created (see https://github.com/soukoku/vue-oidc-client/wiki#app-start)
Since I can't simply put an await outside of an async function, I am wondering how I can achieve this.
My code as reference:
// Importing stuff and creating 'oidc' with createOidcAuth(...)
const startupSucessful = oidc.startup()
if(!startupSucessful) throw Error("Unable to bootstrap OIDC client");
export default boot(async ({ app, router, Vue }) => {
oidc.useRouter(router);
});
Since your export block is async, just put the code you want to wait for there:
export default async ({ app, router, Vue }) => {
const startupSucessful = await oidc.startup()
if(!startupSucessful)
throw Error("Unable to bootstrap OIDC client");
else
oidc.useRouter(router);
});

using mock data while on development with vue + vuex

I'm working on a Vue app which also uses vuex.
Everything is setup ad working correctly as expected but i'd like to improve it so that I can work on it without actually calling the API endpoints (mainly to avoid rate limit).
I created a mock folder and placed some file in there.
How do I manage to use those mock in development, and the real api endpoint on the build on production withouth making a mess in my code ?
I created a repo with as less as possible.
It includes vue + vuex, a single smart component in charge of reading from the store, and a dumb component do display it.
In poor words, I'm looking for a way to do change this:
const actions = {
async fetchTodos({ commit }) {
let response;
if (process.env.NODE_ENV === "development") {
response = { data: todos };
} else {
response = await axios.get("https://jsonplaceholder.typicode.com/todos");
}
commit("setTodos", response.data);
}
};
with something which would be easier to maintain and wouldn't increase the bundle size.
I thought about mocking the whole action object, which seemed to be ok, but how do i avoid to bundle my mock files at that point?
How do you manage your front end environment to avoid this kind of problem?
What I did is encapsulate the whole API in another class/object. That single point of entry then switches between the mock and real api:
// store.js
const api = require('./api');
const actions = {
async fetchTodos({ commit }) {
// you can use api.getTodos() instead or another naming convention
const response = await api.get('todos');
commit("setTodos", response.data);
},
};
// api.js
const realapi = require('./realapi');
const mockapi = require('./mockapi');
module.exports = process.env.NODE_ENV === 'production' ? realapi : mockapi;
// mockapi/index.js
const todos = loadTodos();
module.exports = {
async get(path) {
switch (path) {
case 'todos':
return { data: todos };
// etc.
}
}
};
// realapi/index.js
const root = 'https://jsonplaceholder.typicode.com/';
module.exports = {
get(path) {
return axios.get(root + path);
}
};
Builders like Webpack can optimize the build and remove the whole mock api part in production builds based on the environment.

Nuxt custom module hooks not called

I want to pass some extra data from the ssr server that's present after the middleware has run, and use that on client side middleware. A bit similar to what nuxt already does with vuex.
Documentation at the render:context hook:
Every time a route is server-rendered and before render:route hook. Called before serializing Nuxt context into window.__NUXT__, useful to add some data that you can fetch on client-side.
Now my custom plugin defines some hooks as stated in the documentation, but not all seem to be called properly:
module.exports = function() {
this.nuxt.hook('render:route', (url, result, context) => {
console.log('This one is called on every server side rendering')
}
this.nuxt.hook('renderer', renderer => {
console.log('This is never called')
}
this.nuxt.hook('render:context', context => {
console.log('This is only called once, when it starts loading the module')
}
}
What am I doing wrong and how can I pass custom ssr data to the client side renderer?
Ok, just found the solution to the core problem of passing custom data from the (ssr) server to the client:
Create a plugin: plugins/my-plugin.js
export default ({ beforeNuxtRender, nuxtState }) => {
if (process.server) {
beforeNuxtRender(({ nuxtState }) => {
nuxtState.myCustomData = true
})
} else {
console.log('My cystom data on the client side:', nuxtState.myCustomData)
}
}
Then register the plugin in your nuxt.config.js:
module.exports = {
plugins: ['~/plugins/my-plugin']
}
Docs here.

Show loading property on Pageload with nuxt

I have a nuxt project that is working well. However on the loading of the page a async method is performed.
import charge from '~plugins/charge'
export default {
asyncData (context, callback) {
const subscription = context.params.id;
charge.getAll(subscription, function(result){
let data = result.data;;
callback(null, data)
});
}
}
My Problem is, that the page stays with until the async operation has been performed. How can i Show a loader until the function returns a result?
There is an official example in Nuxt.js repo. Check out the Custom-Loading example.