Hi there,
I ran nuxt generate, and pages with the fetch () method are building with the fetched content pre-populated in the static html file. If you are using a CMS, this is problematic because direct hits to the page will load the original content when it was built.
For now, I had to replace the fetch () method with the created () lifecycle hook.
I'm using 1.0.0-rc3, so not sure if this has been fixed. If this is intended behavior, it's problematic, unless I'm missing something.
have you tried asyncData instead of fetch?
Yep, both asyncData() and fetch() seem not to do a request on the first page load. As a test, I loaded a page, got stale data (the html shipped with the build), navigated to another page, navigated back, and got the correct data.
I'm investigating similar setups myself at the moment. Am I right in thinking that
asyncData is intended to e.g. get data via axios and load it into a component's data property, only useful for ssr (not static gen)
fetch is intended to e.g. get data via axios and add it to a vuex store , only useful for ssr (not static gen)
mounted is intended for use as in normal vue e.g. load data after component init and add it to data property/vuex store, useful for static gen or spa
@robyedlin Sorry I'm a little confused
I ran nuxt generate, and pages with the fetch () method are building with the fetched content pre-populated in the static html file.
鈽濓笍 Isn't this expected behavior?
because direct hits to the page will load the original content when it was built.
鈽濓笍 Isn't this also, expected behavior?
Yep, both asyncData() and fetch() seem not to do a request on the first page load. As a test, I loaded a page, got stale data (the html shipped with the build), navigated to another page, navigated back, and got the correct data.
So during generation, afetchis called on multiple pages, data is fetched, and the template is populated.
When you serve up the dist and navigate to one of these pages, the data that is showing in the template is what was fetched during generation? And if you bounce from there and back, there is new data coming from the CMS?
I might be confused too. I guess it depends on what is expected with the term "static."
For pages with a fetch () method, the only expectation I have is that the data loads before the page renders. I wouldn't expect nuxt generate to actually run the fetch () method and fill the static page with the fetched data on build. A CMS or data source will likely override this content, but the static build loads the original data and will be stuck showing that when the page is loaded directly.
I might understand your confusion. 馃槈
Be Advised
See my follow-up post below from 12/03/17
nuxt generate is going to package up your app for a static deployment.
fetch() is a Nuxt convention that allows you to get data and dispatch Vuex actions (there are some other uses, but this is probably the most common one), this is at build time. fetch() will be called during a nuxt generate for any page it exists for. Once the distribution is deployed, fetch() won't be called on routing.
What you might be missing from your mental model is a continuous delivery pipeline. The power behind using the Vue server render library that Nuxt has configured via generate is that you benefit from server rendered content. SEO improvements, page-speed improvements, things of that sort.
If you're using a CMS, let's assume you're using WordPress, a typical setup would be to have some sort of pipeline setup that would be responsible for packaging up a fresh distribution of the site and deploying it to your host, and you setup triggers for the pipeline.
In WordPress there is a hook that's called when posts are published/updated/changed etc, so if a user publishes content then the hook will be called and you can do something like make a POST request to your pipeline to kick off a build.
Check out this comment that I posted on this article on CSS Tricks. The article and my comment should help give you a bit more insight.
Netlify has a neat flat-file CMS setup and CD pipeline plus hosting. At least getting familiar with how it operates should give you a better idea of what it's like to work with static generations.
Gitlab offers a pipeline option that is fantastic, and there are other ones out there too like CircleCI. You could also create a more custom build infra with something like AWS Lambda.
Also, check out the JAMStack site for a little bit more info about what it's like to work with a full server rendered site.
You are not sequestered to generating a static build with Nuxt. You can deploy a different sort of build with something like the SPA build option. If you are looking to deploy your site and have Vue fetch content when your visitors navigate, fetch() is probably not the hook you're looking for.
It sounds like asyncData() isn't working for you the way you expected. As I have primarily worked with fetch() and static builds I'm not yet sure why that hook wouldn't work for you, but maybe that's because you've been doing a static generate. You might want to dig into the production deployment section and also the async data docs.
Thanks @jsonberry and everyone, this makes sense. I think then that this is just a misunderstanding on my part about the purpose of a static build with fetch (). I'll consider this issue closed and think about submitting an issue in nuxtjs.org to improve the docs.
For a headless CMS, I'll commonly be using Nuxt with S3/Cloudfront static build, but a CD pipeline is usually overkill. This is easily mitigated by loading data dynamically every time using the created () method.
@robyedlin True story, but then I think you start to lose the benefits like improved SEO and page loads. For one project I also serve with S3 + Cloudfront, and Gitlab pushes out fresh builds + invalidates the CF cache. 馃憣
True, the best solution for SEO will be to have purely static content. I'm pretty sure google's indexing does wait for the content to be returned now, as long as the content is returned quickly.
@jsonberry thanks so much for that in-depth discussion about fetch and asyncData.
I find the current documentation _really_ _really_ confusing; it isn't clear at all to me what is called for SSR and SPA builds. I've been pushed into using Nuxt for a SPA build and its' very hard for me to detangle from the docs what is for SPA and what isn't. This explanation really helped me.
I would really recommend a good chunk of this comment is added to the current docs for Nuxt. It would be really helpful, if each method is clearly marked as being available for certain types of builds and what isn't.
I also find the doc about fetch and asyncData not clear.
I have the same kind of problem than @robyedlin
I have a dynamic route /users/:id, but when loading it the first time the data about user :id is missing, because it is loaded by aysncData
If I navigate and come back to this page, then this time the data is loaded.
I'm OK with the fact that generate calls asyncData/fetch at generate time (for SEO optimizations), but shouldn't it be logical to fetch "fresh" data when page is loaded?
Because if you don't think it's logical... then why when navigating and coming back to the page, the data is fetched instead of displaying the static content?
Thank you for reading ^^
fetch() will still be called on the client, even if the project is pre-rendered with static generation (nuxt generate). This is true for page components.
If you use the nuxtServerInit() hook in your store/index.js actions, it will be called from just the server side... At least from the testing that I've done, it hasn't been called in my generated projects from the client side.
Be Advised
The number of times nuxtServerInit is called is (calls * N), where N is the number of pages you are generating. This caused some performance issues for me when I had a few http calls associated with nuxtServerInit, and that was temporarily solved with some local JavaScript caching techniques. I'll be investigating proper techniques for solving that issue, which might be using a different pattern for filling the Vuex store... but, the temp caching technique is working really well right now.
Example
_Just an example, not everything here is what I would put into prod_
_This pattern is intended to be used for static generations_
// store/index.js
import axios from 'axios'
const api = axios.create({ baseURL: process.env.BASE_URL })
const requestCache = {
posts: null
}
export const actions = {
async nuxtServerInit ({ dispatch }) {
const posts = await cachePosts()
// now all posts are available in my Vuex store,
// which is accessed from lots of different places in the project
dispatch('posts/setPosts', posts)
}
}
/**
* This is the secret sauce.
* If the data being requested is cached, subsequent API calls will not be made
* During a nuxt generate, nuxtServerInit will be called for every page
* Because of this caching, the API calls will only be done once
*
*/
function cachePosts () {
if (!requestCache.posts) { // if cache doesn't exist, get the data from the API and cache it
requestCache.posts = api
.request({ url: 'posts/all' })
.then(res => res.data)
.catch(err => console.log(err))
}
return requestCache.posts // always return from the cache
}
I've tried that but to no avail
I have only mutations and a single action for nuxtServerInit
How can I chain multiple api calls into that object?
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
I might understand your confusion. 馃槈
Be Advised
See my follow-up post below from 12/03/17
Static builds
nuxt generateis going to package up your app for a static deployment.fetch()is a Nuxt convention that allows you to get data and dispatch Vuex actions (there are some other uses, but this is probably the most common one), this is at build time.fetch()will be called during anuxt generatefor any page it exists for. Once the distribution is deployed,fetch()won't be called on routing.What you might be missing from your mental model is a continuous delivery pipeline. The power behind using the Vue server render library that Nuxt has configured via
generateis that you benefit from server rendered content. SEO improvements, page-speed improvements, things of that sort.If you're using a CMS, let's assume you're using WordPress, a typical setup would be to have some sort of pipeline setup that would be responsible for packaging up a fresh distribution of the site and deploying it to your host, and you setup triggers for the pipeline.
In WordPress there is a hook that's called when posts are published/updated/changed etc, so if a user publishes content then the hook will be called and you can do something like make a POST request to your pipeline to kick off a build.
Check out this comment that I posted on this article on CSS Tricks. The article and my comment should help give you a bit more insight.
Netlify has a neat flat-file CMS setup and CD pipeline plus hosting. At least getting familiar with how it operates should give you a better idea of what it's like to work with static generations.
Gitlab offers a pipeline option that is fantastic, and there are other ones out there too like CircleCI. You could also create a more custom build infra with something like AWS Lambda.
Also, check out the JAMStack site for a little bit more info about what it's like to work with a full server rendered site.
Other types of builds
You are not sequestered to generating a static build with Nuxt. You can deploy a different sort of build with something like the SPA build option. If you are looking to deploy your site and have Vue fetch content when your visitors navigate,
fetch()is probably not the hook you're looking for.It sounds like
asyncData()isn't working for you the way you expected. As I have primarily worked withfetch()and static builds I'm not yet sure why that hook wouldn't work for you, but maybe that's because you've been doing a staticgenerate. You might want to dig into the production deployment section and also the async data docs.