Refresh statically generated page (data) once it has loaded on client - vue.js

For example I have some page in Nuxt:
data() {
return {
items: []
};
},
asyncData() {
return axios.get('site.com/url')
.then((response) => {
return {
items: response.data
};
});
},
Then I run npm run generate and get statically generated html-page with data (items) from backend server. And when I open this page in browser I see that injected data into the page.
But these items might be updated on the backend so I need to see them once I have got refreshed the page with F5 and without running again npm run generate.
So looks like I should refetch data in mounted() section. Maybe Nuxt has something more suitable for this?

The only option is use crawler: false property in your nuxt.config.js file. It will disable static content generation from you dynamic pages. Here is the documentation.

Related

Fetch data from local JSON file with Nuxt Pinia

Is it possible to fetch a local .json. file using fetch()? I originally used the import method but the site's data doesn't get updated unless the page gets reloaded.
I tried doing this but it's not working:
stores/characters.ts
export const useCharactersStore = defineStore("characters", {
state: () => ({
characters: [],
}),
getters: {
getCharacters: (state) => {
return state.characters;
},
},
actions: {
fetchCharacters() {
fetch("../data.json")
.then((response) => response.json())
.then((data) => {
this.characters = data.characters;
});
},
},
});
app.vue
import { useCharactersStore } from "~/stores/characters";
const store = useCharactersStore();
onMounted(() => {
store.fetchCharacters();
});
Any help would be appreciated.
maybe a bit late but I have encountered the same problem migration from Nuxt 2 to Nuxt 3.
I'm certainly no expert on this, so if anyone finds a better way or if I'm totally wrong please let me know !
Whenever you import a json file in vue code they are imported as a module, that get's embedded within the code compilation on build (Vue Docs). Tu use json as a external file you need to place your json within the /public directory and use axios or fetch to load the file with a lifecyle hook.
This could be mounted() for options api or beforeMount()/onMounted() with composition api.
However some important annotations for this method.
If the json file you want to use in your app is not reactive, i.e. won't change, you should place this in the static folder of the nuxt app.
In your example you fetch '../data/...', this would imply the server knows the domain to look for. It can't call the route like this, you would have to give the full url if you put your json file in the static folder.
Set the baseUrl in the of your nuxt.config.ts, see docs for specifications.
Then you can access the static folder with your .env variables
--> $fe
Then in you data script you can access your json file
async getJson(some parameters){
const data = $fetch('your domain with the runtimeConfig composable').then((data)=>{ console.log(data)});
Sidenote you can also load the file from the server-side using fs.readFile
read more about this in this awesome post here

Nuxt.js search by query param without reload

What are the steps needed to make a redirect to search results without page reload in Nuxt.js? So far, it's been sorted this way:
search() {
location.href = '/search?phrase=' + this.phrase;
},
and I need to make it happen without page refresh. In the page's dir is a search directory with index.vue inside like
/search/index.vue
so far I found some solutions to use $router.on(event) so I have something like this
created() {
this.$nuxt.$on('pushState', params => {
history.pushState(
{},
null,
'search?phrase=' + encodeURIComponent(params)
)
})
},
beforeDestroy() {
this.$nuxt.$off('pushState')
},
methods: {
search() {
this.$nuxt.$emit('pushState', this.phrase)
}
},
However, all I have managed to achieve is to change the URL, but no redirection is happening. So what are the steps necessary to make this redirection to the mainURL + 'search?phrase=' + query so that user would be indeed redirected, and the items were displayed like right now.
In the /search/index.vue items are fetched and displayed, but how do I force router to go to this URL not only display it in the browser?

How can one add custom http headers to Nuxt __page__ ( not static asset ! ) in Nuxt dev server?

https://github.com/hyperbotauthor/vue-chessground/tree/main/test
My problem is that I have to add custom headers to my Nuxt page in order that SharedArrayBuffer may work.
I know how to add custom headers to assets served from the static folder and to the production server:
render: {
static: {
setHeaders(res) {
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
},
},
dist: {
setHeaders(res) {
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
}
}
},
However in dev server these headers are not added to the Nuxt pages served from the pages folder.
If I hand write an HTML page in the static folder, then SharedArrayBuffer will work on that page. But not on the Nuxt page.
Is there any way to make Nuxt dev server add headers to Vue rendered pages?
EDIT:
If I include the hand written, in separation working HTML in an iframe from the Vue page, then it again won't work.
EDIT:
I opened an issue at Nuxt:
https://github.com/nuxt/nuxt.js/issues
You also need to add the headers to the response for pages as well. Try testing using Postman or something similar to view response headers, when you try to load the static resources, as well as the nuxt pages.
Setting render: { static: ... } in nuxt.config.ts worked for the static resources.
To set up middleware for the server creating the initial html pages you can do:
// middleware/setSameOriginHeader.ts
export default function (req: any, res: any, next: any) {
res?.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
res?.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
}
// nuxt.config.ts
export default {
ssr: false,
...
// middleware to set headers on pages
serverMiddleware: ['~/middleware/setSameOriginHeaders.ts'],
// set headers on resources in static dir
render: {
static: {
setHeaders(res: any) {
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
}
}
},
...
}

Nuxtjs Redis cache implementation for API calls inside components

I am using the plugin Nuxt Perfect Cache to server-side cache my QPI requests to an external service.
I am using the cacheFetch method on Component level and this component is loaded on a dynamic page (defined by its slug). When I navigate to the dynamic page, the API call is not cached in Redis, however when I reload the page, the caching happens as expected.
Below is how my code is structured:
_slug.js (for /users)
<template>
<h1>{{ user.name }}</h1>
<Posts :author = user.id>
</template>
<script>
import Posts from '~/components/Posts.vue'
export default {
components: { Posts },
async asyncData({params}) {
const user = await fetch(`/users/${params.slug}`)
.then(res => res.json())
}
}
</script>
And inside Posts.vue I use the perfect cache cacheFetch method to fetch the list of posts, something like:
props: ['author'],
async fetch() {
this.posts = await this.$cacheFetch({ key:`user--#{this.author}--posts`, expire: 60 * 60 },
async () => {
return await fetch(`/users/#{this.author}/posts`).then(res => res.json())
})
},
data() {
return {
posts: []
}
}
When I load the user page directly in the browser, the json response for the posts is saved in Redis as expected. When I navigate from within the application using a NuxtLink, the user page is displayed correctly (including the posts), but no key is set or get from Redis.
How can I ensure the API calls are cached when users interact with the app?
redis is only available in server side not client side when you are navigating in client side you don't have access to redis you can set absolute link to render server side when user is navigating but I don't recommend this.
the best solution is cache data in redis in your api.

Nuxt.js env Property, understanding and how to use it?

following https://nuxtjs.org/api/configuration-env
I have been trying to set up my apiUrl in nuxt.config.js once for the whole project, like:
export default {
env: {
apiUrl: process.env.MY_REMOTE_CMS_API_URL || 'http://localhost:1337'
}
}
adding this in nuxt.config.js, I'd expect (and would like) to have apiUrl accessible everywhere in the project.
In particular, it is needed for the 3 following cases:
with axios, to generate static pages from dynamic urls (in nuxt.config.js)
generate: {
routes: function () {
return axios.get(apiUrl + '/posts')
.then((res) => {
return res.data.filter(page => {
return page.publish === true;
}).map(page => {
return {
route: '/news/' + page.slug
}
})
})
}
},
with apollo, to get data via graphql (in nuxt.config.js)
apollo: {
clientConfigs: {
default: {
httpEndpoint: apiUrl + '/graphql'
}
}
},
in every layout, page and components, as the base url of media:
<img :src="apiUrl + item.image.url" />
As you might see, only thing I need is to 'print' the actual base url of the cms.
I have also tried to access it with process.env.apiUrl, with no success.
The only way I was able to make it has been to create an extra plugin/apiUrl.js file, which injects the api url, and seems wrong to me as I am now setting the apiUrl twice in my project.
I asked this question in the past, but in a way less clear way. I was suggested to use dotenv, but from the docs it looks like adding an additional layer of complication that might not be necessary for a simpler setup.
Thanks.
I think dotenv module really is what you need.
This is my setup:
Project root has a .env file that contains
BASE_URL=https://www.myapi.com
require('dotenv').config() at top of nuxt.config.js
#nuxtjs/dotenv installed and added to buildModules of nuxt.config.js
env: { BASE_URL: process.env.BASE_URL} added to nuxt.config.js
axios: { baseURL: process.env.BASE_URL } added to nuxt.config.js (optional)
You should have access to your .env throughout the project. (process.env.BASE_URL)
I haven't used apollo, but you should be able to set the apollo endpoint with process.env.BASE_URL + '/graphql'
As of Nuxt 2.13, #nuxtjs/dotenv is not required anymore. Read here
The concept that I was missing is that you set up the same named variable in your server / pipeline, so that you have your (always local / never pushed) .env file and a same name variable remotely, not added to your repo (where the value can be the same or different)