Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fetch () is pre-populating static files on nuxt generate #1500

Closed
robyedlin opened this issue Aug 27, 2017 · 14 comments
Closed

fetch () is pre-populating static files on nuxt generate #1500

robyedlin opened this issue Aug 27, 2017 · 14 comments

Comments

@robyedlin
Copy link

@robyedlin robyedlin commented Aug 27, 2017

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.

This question is available on Nuxt.js community (#c1335)
@robyedlin robyedlin changed the title fetch () is pre-populating static files fetch () is pre-populating static files on nuxt generate Aug 27, 2017
@KonstantinVlasov

This comment has been minimized.

Copy link

@KonstantinVlasov KonstantinVlasov commented Aug 28, 2017

have you tried asyncData instead of fetch?

@robyedlin

This comment has been minimized.

Copy link
Author

@robyedlin robyedlin commented Aug 28, 2017

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.

@gridsystem

This comment has been minimized.

Copy link

@gridsystem gridsystem commented Aug 29, 2017

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

@jsonberry

This comment has been minimized.

Copy link

@jsonberry jsonberry commented Aug 30, 2017

@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, a fetch is 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?

@robyedlin

This comment has been minimized.

Copy link
Author

@robyedlin robyedlin commented Aug 30, 2017

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.

@jsonberry

This comment has been minimized.

Copy link

@jsonberry jsonberry commented Aug 30, 2017

I might understand your confusion. 😉


Be Advised
See my follow-up post below from 12/03/17


Static builds

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.


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 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.

@robyedlin

This comment has been minimized.

Copy link
Author

@robyedlin robyedlin commented Aug 30, 2017

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 robyedlin closed this Aug 30, 2017
@jsonberry

This comment has been minimized.

Copy link

@jsonberry jsonberry commented Aug 30, 2017

@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. 👌

@robyedlin

This comment has been minimized.

Copy link
Author

@robyedlin robyedlin commented Aug 30, 2017

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.

@JMacLulich

This comment has been minimized.

Copy link

@JMacLulich JMacLulich commented Oct 10, 2017

@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.

@ByScripts

This comment has been minimized.

Copy link

@ByScripts ByScripts commented Nov 24, 2017

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 ^^

@jsonberry

This comment has been minimized.

Copy link

@jsonberry jsonberry commented Dec 3, 2017

Follow-up

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
}
@bovas85

This comment has been minimized.

Copy link

@bovas85 bovas85 commented Mar 7, 2018

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?

@lock

This comment has been minimized.

Copy link

@lock lock bot commented Nov 3, 2018

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.

@lock lock bot locked as resolved and limited conversation to collaborators Nov 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
8 participants
You can’t perform that action at this time.