Closed my other issue-thread since it basically boils down to this.
Is it possible to generate a 100% static site when ur using an API to fetch data, so that one can get rid of the API and requests? If not, will this be available in v1? If yes, any examples on how to do this? I know there is a process.static bolean?
Yes, Nuxt can generate 100% static site.
As the document returned by Nuxt server is the HTML filled with data rendered in Node.js.
However, if you have data that requires client-related data, such as cookies that store user session data, or browser sizes, you need to do it on client side.
@f15gdsy Hmm okey, but i'm calling an API (cosmic.js) in the asyncData method, and these requests are still being made after nuxt generate, with the static files deployed. Why is this and is it possible to not do any more requests after nuxt generate?
Hi @jesperlandberg,
These requests are required to make your website as a Vue.js web app and not a static website.
Vue.js need these requests to fill data from an API used in your page component otherwise, you will lose the benefit of a web app.
@alexchopin But the data is in window.__NUXT__={]. This is not possible to use? I saw some other example of someone creating json files from requests on generate, then checking what to use using process.static. Is there any plan to implement something like this? My initial though was that I would be able to just generate the site with webhooks when updating in the CMS, and then no more requests would be made untill the next generate? But currently if using an API the site will always be dependent of this, correct?
Had the same question back in september and concluded that this feature, atleast to some degree, is planned after 1.0 release if I'm not mistaken. #1659 was my issue. Also see the linked #1051.
Recently had the idea of caching the the json-data using the pwa-module (https://github.com/nuxt-community/pwa-module/) by passing { globPatterns: ['**/*.{js,css,json}'] }
as workbox options. Still haven't tested this, but it should work. I'll report here if anyone is interested.
@colsen1991 Nice, will also take a look at the pwa-module. And yes would be awesome if you could keep me updated=)
@jesperlandberg Sorry for the delay. But been super busy (and lazy) lately :( Anyways, played around for an hour today, and found that using v2.0.0 of the nuxt pwa-module and adding workbox: { handleFetch: true }
to nuxt.config.js
to be quite effective.
Tried to make workbox add the json-files from data/
to the precache manifest, but to no avail. The issue is that generate
works out of .nuxt/dist
during generation, and that folder is emptied at the start of generate
, while I'm fetching the data during pregenerate
. Gonna have a look at writing a module to copy the data into .nuxt/dist
during generation instead. But I need more time for that. I'll keep you posted :)
But I need more time for that. I'll keep you posted :)
@colsen1991 Did you already find/settle on a solution?
@mootari No unfortunately not :( I still haven't had the time to try to write that module which uses prefetched data and copies it into .nuxt/dist
. So far I've found a couple of solutions which are OK if you wan't something that is 100% static ish:
pregenerate
, place it in static/data
folder and import
the json files in the components which uses them.This works great for actual static sites as only the data relevant to the components and layouts of a praticular page is loaded in the .hmtl
file. But the tactic doesn't work for dynamic paths. So in these you'll have to fetch the data in asyncData
method.
vuex
store.Works great for a 100% static site, but the downside is that for every page you also get the all of the json
, which is part of the .html
file, meaning that it's also blocking rendering for a bit longer than neccessary. But the method works good for a site with little data.
At the moment I am currently using method for my sites as 100% isn't really a must-have in most cases, and the downside of method two is too big in most cases. I do hope to get that module up and going at some point, which would enable putting the prefetched data in .nuxt/dist
folder so that it I can utilize method 1 and prefetch the data with a service worker client side and cache it. I'll update here whenever I get that going. But the nuxt
itself might beat me to it with official 100% static generation out of the box, heh x)
@Atinux I'm in the same boat, about to tackle this by saving my api responses to json at build time to circumvent the post-generate API calls. With the release of Nuxt 1.0 just over a month ago, do you have any new insight into this?
_edit:_
@pi0 @alexchopin ...?
@mingyjongo there is an example of 100% static site by @Atinux https://github.com/Atinux/nuxt-static
@jesperlandberg @mingyjongo @colsen1991 @mootari @Al-Rozhkov The example by @Atinux is still not fully static, it fetches just the IDs of all items in the API to generate the routes and throws away the rest of the object.
But there is an option to save the payload and make it available in the context of the dynamic route:
https://nuxtjs.org/api/configuration-generate#speeding-up-dynamic-route-generation-with-code-payload-code-
When using nuxt generate
any passed payload
data still doesn't appear to be available beyond the applications first page load, which is no different than the default nuxt generate behaviour. So anyone trying to achieve a 100% "static" site will still need to rely on a persistent api for content. And the issue still exists of any particular page potentially displaying different content depending if it was mounted from first page load, or navigated to via <nuxt-link>
routes.
Steps to replicate
nuxt.config.js
generate: {
routes: function() {
return axios
.get("https://jsonplaceholder.typicode.com/posts/")
.then(res => {
return res.data.map(post => {
return {
route: "/posts/" + post.id,
payload: post.body
};
});
});
}
}
/pages/posts/_id.vue
<template>
<div>
<pre>{{ post }}</pre>
</div>
</template>
<script>
import axios from "axios";
export default {
async asyncData({ params, error, payload }) {
if (payload) return { post: payload };
else
return {
post: "not from payload!"
};
}
};
</script>
Then run nuxt generate
and deploy the /dist
folder somewhere, or start a simple http server on the /dist
directory. (worth noting that nuxt start
after nuxt generate
behaves differently again to viewing the static files directly)
Would desperately love an update on the progress however, or to know if it is even still on the roadmap.
What I ended up doing was writing a module to scrape all of my api data during the build step, and then just requiring that JSON in my page components. It feels a little hacky, but was pretty ideal for me. I was working with a less than ideal api that returned a _lot_ of junk, other nodes to call, etc. (looking at you, Drupal), so scraping it up front allowed me to prune through and organize it to my liking.
modules/scrape.js
module.exports = function scraper() {
const writeData = (path, data) => {
return new Promise((resolve, reject) => {
try {
fs.ensureFileSync(path)
fs.writeJson(path, data, resolve(`${path} Write Successful`) )
} catch (e) {
console.error(`${path} Write Failed. ${e}`)
reject(`${path} Write Failed. ${e}`)
}
})
}
// Add hook for build
this.nuxt.hook('build:before', async builder => {
// Clean data directory
fs.emptyDir('static/data')
// Empty array to fill with promises
const scraper = []
// One of these for every top level page, a loop for dynamic nested pages
scraper.push(writeData('static/data/index.json', await fetchHomepageJSON()))
// Finish when all of them are done
return Promise.all(scraper).then(() => {
console.log('JSON Build Complete!')
}).catch(err => {
console.error(err)
})
}
}
index.vue
asyncData () {
return require('~/static/data/index.json')
}
nuxt.config.js
modules: [
'~/modules/scrape'
]
There's a bit more, but that's the basic idea. Downsides to this way are that I couldn't figure out how to get Nuxt to trigger the module again when I updated its files, so if I changed the format I was returning my data I would have to exit and build the whole thing over again.
@mingyjongo Your method works great! That said, would you or anyone have any tips to fill a Vuex store with the scraped data, to replace the asyncData
property with computed
properties returning values from the store? Just thinking about whether that's possible, I figure it should be.
EDIT: I've achieved it by simply importing the scraped index.json
file into my store/index.js
as such:
import data from '~/static/data/index.json'
export const state = () => ({
allData: data
})
I do suspect this might present some sort of performance issue, however? I suppose not, as long as I'm not returning the entire state all the time within the asyncData
of each component.
@mingyjongo Hi mate,
I'm trying to do something a bit simpler, but with no lucky yet.
I've a JSON which returns data from the CMS, using async works pretty well during the development. After the nuxt generate command and if I update the that JSON data, the code doesn't show the updated version of the content, but if I uses the NUXT-LINKS and return to the page here if that call shows the correct version (spa mode).
Here my code example:
export default {
async asyncData ({env, params}) {
let {data} = await axios.get('https://api.myjson.com/bins/1g0tjw')
return {data:data}
}
(index.js)
Can you give some advices?
Cheers
@roqsantacruz Did you re-generate the static pages after updating json data? something like this:
npm run generate
(thus re-generate the static html)There are a lot of way to achieve this workflow, webhook is one of them.
Also you might want to read this article: https://www.academind.com/learn/vue-js/nuxt-js-tutorial-introduction/static-site-generation
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
What I ended up doing was writing a module to scrape all of my api data during the build step, and then just requiring that JSON in my page components. It feels a little hacky, but was pretty ideal for me. I was working with a less than ideal api that returned a _lot_ of junk, other nodes to call, etc. (looking at you, Drupal), so scraping it up front allowed me to prune through and organize it to my liking.
modules/scrape.js
index.vue
nuxt.config.js
There's a bit more, but that's the basic idea. Downsides to this way are that I couldn't figure out how to get Nuxt to trigger the module again when I updated its files, so if I changed the format I was returning my data I would have to exit and build the whole thing over again.