Retrieve a file before anything else happens - vuejs2

Iʼm creating a simple SPA that will retrieve data from an API. The page itself is served by a separate backend process which is the only entity that knows the API address. As such, it also provides an endpoint that, among other things, returns the API URL:
{
"api_url_base": "http://api.example.org/v1"
}
This is needed because the whole thing is deployed at multiple sites where we donʼt have control over DNS records and it may or may not be easy to derive the API URL from the front end appʼs.
Now i need to write my Vue app so nothing can happen until i fetch and process this file. To achieve that, i added to the appʼs beforeMount method:
this.settings = axios.get('/settings.json');
and in my componentsʼ beforeMount:
var comp = this;
app.__vue__.settings.then((response) => {comp.url = response.data.api_url;});
However,it seems the componentʼs beforeMounted often runs before the appʼs, and app. __vue__.settings is undefined when i get to the componentʼs beforeMount.
Where do i go wrong? Am I putting things at wrong places, or is my approach completely wrong?

You can fetch data before mount the vue app.
axios.get('/settings.json').then(response => {
// do something with response
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
}

One way (as suggested in the previous answer) is to make one more call, before anything else. However it brings numerous downsides.
Let me just say that it freezes the loading of your application until the response is received.
There is hope as you can cleverly use (f.e.) good ol' dependency injection to pass the required data to your app.
This article answers this question fully and completely: https://codeburst.io/passing-configuration-to-vue-js-1b96fa8f959

Related

Is it possible to use nuxt fetch() and set the values in head()?

The problem is that head() seems to be executed before async fetch(), which causes errors when trying to insert page's metadata and title. I KNOW asyncData exists, but the fact that it blocks page loading at a route transition level makes it provide such a HORRIBLE user experience (in a mobile device with bad connection, page transition can stay blocked for seconds) and reminds of old PHP rendered websites, not a modern SPA. Nuxt fetch() in the other hand, while still server side rendering the page, exposes $fetchState.pending and makes possible to exhibit an instant page transition showing the page skeleton, for example (consequently making the user experience better). The only problem i am having is this one with head() data. Is this problem solvable or just one unsolvable drawback of using fetch() instead of asyncData()?
Important Note: I am referring to Nuxt's new fetch method, not the legacy one.
example code that doesn't work:
data() {
return {
car: null,
}
},
async fetch() {
this.car = await this.$axios.$get('/cars/' + this.$route.params.id)
},
head() {
return {
title: this.car.name,
}
},
My colleague did a talk a few weeks ago, speaking about SEO in general, here is related section: https://youtu.be/W9camkXNjkw?t=920
Looking at all my given answers regarding SEO and also Github issues, all examples are using asyncData or some static approach.
When you think about it, I'm not sure how you could generate something on SSR, while being totally dynamic + non-blocking.
Either you know it ahead of time and can generate the OG tags, or you don't if it's totally volatile.

Vue page cannot open after refreshing the page

I added the routes dynamically to the router and I can visit all pages with router-view. However, when I try to refresh the page I cannot visit the page again although the URL is the same. It is http://localhost:8081/me.
this.$router.addRoute("Main", {
path: '/me',
name: 'Me',
component: () => import(`#/components/Me.vue`)
});
As I said, I can normally visit the page "Me", but when I refresh it, I cannot see its content anymore with the warning:
[Vue Router warn]: No match found for location with path "/me"
I tried to create router with createWebHistory("/") after reading the cause of the error but nothing seems to change. I will appreciate any help.
There are two reasons why this would happen.
First serving SPA application from the server.
Make sure that your back-end is set to serve index.html file for all routes since back-end server is unaware of the routes set by client-side router. Something like express-history-api-fallback-middleware can help is using Node.js/Express.js.
Second problem is that of using addRoute.
As you described, the problem could be that Vue router is taking routing decision before your code in components/common/LeftMenu.vue is getting executed which is responsible for calling addRoute(). Ensure that this code is called before routing decision is being made. Best way would be to move this logic in top-level application component. And, if you can move that to top-level components, that means you can try to declare all routes while defining the router.
Why that should be done?
Using addRoute is not necessarily an anti-pattern but having to rely on addRoute is often code smell. You would really need it in extremely rare scenarios. Routing is a high-level architectural concern for your application and thus better to be declared upfront somewhere at top-level module even before application is getting initialized. Low level components should not attempt to manipulate routing data structure (violation of DIP principles).
One scenario where you might be tempted to use addRoute is taking decision after some data manipulation by the component with addition of some API call. That seems legitimate need but then to address that there are better ways. Considering using route guards (guards support async resolution too!) and prevent user from entering the view till the guard is resolved successfully.

ExpressJs and POST from external source to my income router, how to get data

I'm getting my hands dirty with Node and expressJS, new with Node and ExpressJS, and there something that I can't get right.
There is a service that POST data (json format {}) to my "income" router, the thing is, a logger helper that check all routers is printing (console.log) the incoming data, but inside the router, I can't get anything (i can't do a console.log for example), not req.body, there is "nothing", just the res.sendStatus(200) that is required for (https://cloud.google.com/pubsub/docs/push).
Any idea about why this happens?
Thanks
There could possibly be some middlewares attached that are actually doing the job, while the router is merely printing the logs. In this case, middleware are attached to be functional well before the code in route gets executed.
Check for app.use or router.post('SOMEPATH',MIDDLEWARE1, MIDDLEWARE2)
ExpressJS's core strength is to modularise the code using middleware.

"Default Apollo Queries" VS "AsyncData" (Nuxt.js)

I'm building a site with Nuxt/Vue, and it's using a GraphQL backend API. We access this using the Apollo module for Nuxt.
In a page component, you can do this (I think this is called a Smart Query, but I'm not sure):
apollo: {
pages: {
query: pagesQuery,
update(data) {
return _get(data, "pageBy", {});
}
},
}
}
But you can also do the query like this I think, using the Nuxt asyncData hook:
asyncData(context) {
let client = context.app.apolloProvider.defaultClient;
client.query({query, variables})
.then(({ data }) => {
// do what you want with data
});
}
}
I'm not sure what the difference is between these two ways, and which is better. Does anyone know? I couldn't find an explanation in the docs anywhere.
Yeah, good question. The code you have shown at the top is indeed called a Smart Query. In fact
Each query declared in the apollo definition (that is, which doesn't
start with a $ char) in a component results in the creation of a smart
query object.
A nuxt project using the #nuxtjs/apollo module can use these out of the box. The beauty of the smart query is the options that it comes with and one of these is the 'prefetch' option. This, as it sounds, allows prefetching and is by default set to true. It can also accept a variables object or a function. You can see the docs here.
This means that the outcome of a smart query or an asyncData query will essentially be the same. They should be resolved in the same timeframe.
So why choose one or the other? This would probably be down to preference, but with all the options that a smart query allows you can do a lot more, and you can include subscriptions which might not be possible in asyncData.
More about smart queries here.

Flux without data caching?

Almost all examples of flux involve data cache on the client side however I don't think I would be able to do this for a lot of my application.
In the system I am thinking about using React/Flux, a single user can have 100's of thousands of the main piece of data we store (and 1 record probably has at least 75 data properties). Caching this much data on the client side seems like a bad idea and probably makes things more complex.
If I were not using Flux, I would just have a ORM like system that can talk to a REST API in which case a request like userRepository.getById(123) would always hit the API regardless if I requested that data in the last page. My idea is to just have the store have these methods.
Does Flux consider it bad that if I were to make request for data, that it always hit the API and never pulls data from a local cache instance? Can I use Flux in a way were a majority of the data retrieval requests are always going to hit an API?
The closest you can sanely get to no caching is to reset any store state to null or [] when an action requesting new data comes in. If you do this you must emit a change event, or else you invite race conditions.
As an alternative to flux, you can simply use promises and a simple mixin with an api to modify state. For example, with bluebird:
var promiseStateMixin = {
thenSetState: function(updates, initialUpdates){
// promisify setState
var setState = this.setState.bind(this);
var setStateP = function(changes){
return new Promise(function(resolve){
setState(changes, resolve);
});
};
// if we have initial updates, apply them and ensure the state change happens
return Promise.resolve(initialUpdates ? setStateP(initialUpdates) : null)
// wait for our main updates to resolve
.then(Promise.params(updates))
// apply our unwrapped updates
.then(function(updates){
return setStateP(updates);
}).bind(this);
}
};
And in your components:
handleRefreshClick: function(){
this.thenSetState(
// users is Promise<User[]>
{users: Api.Users.getAll(), loading: false},
// we can't do our own setState due to unlikely race conditions
// instead we supply our own here, but don't worry, the
// getAll request is already running
// this argument is optional
{users: [], loading: true}
).catch(function(error){
// the rejection reason for our getUsers promise
// `this` is our component instance here
error.users
});
}
Of course this doesn't prevent you from using flux when/where it makes sense in your application. For example, react-router is used in many many react projects, and it uses flux internally. React and related libraries/patters are designed to only help where desired, and never control how you write each component.
I think the biggest advantage of using Flux in this situation is that the rest of your app doesn't have to care that data is never cached, or that you're using a specific ORM system. As far as your components are concerned, data lives in stores, and data can be changed via actions. Your actions or stores can choose to always go to the API for data or cache some parts locally, but you still win by encapsulating this magic.