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

feat(vue-app): support custom fetchKey for full static generation #8466

Merged
merged 17 commits into from
Dec 17, 2020

Conversation

danielroe
Copy link
Member

@danielroe danielroe commented Dec 10, 2020

Previous behaviour

Previously, fetch payloads were assigned to the components that needed them through a sequential method. When a page changed, the payload array was loaded and a global fetchKey was initialised to 0. As components are created and need data, this key increases and the relevant array item is injected into each component.

This posed a problem when components persist between pages, such as when there is a parent/child page, or if a user would like to use fetch in a global layout. In this case, the persistent component never rerenders, and so the component that would normally be keyed 1 was assigned the 0-indexed payload, and so on.

New behaviour

We are improving hydration by:

  1. Keying fetch payloads with a non-numeric fetchKey. This will default to the scope ID (if the component uses scoped CSS), the component name, if there is one, or an auto-incrementing number (as at present).

  2. Allow the user to manually take control of the fetch hydration process, by specifying their own fetchKey

    export default {
      async fetch () {
        this.title = await fetch('/api/title').then(r => r.json())
      },
      // multiple components can return the same `fetchKey` and Nuxt will track them both separately 
      fetchKey: 'site-sidebar',
      // alternatively, for more control, a function can be passed with access to the component instance
      // It will be called in `created` and obviously must not depend on fetched data
      fetchKey (getCounter) {
        // getCounter is a method that can be called to get the next number in a sequence
        // as part of generating a unique fetchKey. 
        return this.someOtherData + getCounter('sidebar')
      }
    } 

Additional context

Will close #7563, #7791, #7799, #8107, #8150, #8193.

Types of change

  • Bug fix (a non-breaking change which fixes an issue)
  • New feature (a non-breaking change which adds functionality)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly. (PR: docs: add documentation for fetchKey website-v2#1087)
  • I have added tests to cover my changes (if not applicable, please state why)
    • generate tests
  • All new and existing tests are passing.

packages/types/app/index.d.ts Outdated Show resolved Hide resolved
packages/vue-app/template/mixins/fetch.client.js Outdated Show resolved Hide resolved
@pi0 pi0 requested a review from Atinux December 10, 2020 14:54
* nb: this may be a deliberate choice users make
@codecov-io
Copy link

codecov-io commented Dec 10, 2020

Codecov Report

Merging #8466 (2e8433a) into dev (5a5161a) will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##              dev    #8466   +/-   ##
=======================================
  Coverage   67.95%   67.95%           
=======================================
  Files          91       91           
  Lines        3916     3916           
  Branches     1069     1069           
=======================================
  Hits         2661     2661           
  Misses       1016     1016           
  Partials      239      239           
Flag Coverage Δ
unittests 67.95% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5a5161a...2e8433a. Read the comment docs.

@Atinux
Copy link
Member

Atinux commented Dec 10, 2020

I do think we will need tests to ensure the correct behaviour for this and avoid any regression in the future, so far great work @danielroe 👏

@danielroe
Copy link
Member Author

danielroe commented Dec 10, 2020

Updates:

  1. Signature is fetchKey (getCounter: (id: string) => number): string (getCounter will return the next number in sequence for the id it is passed)

  2. If a fetchKey function is provided, it is expected that the key returned is unique (and getCounter or another method should be used to ensure this). If a fetchKey string is passed instead, an increment unique to this string will be managed by Nuxt, and added on automatically.

  3. If not passed anything, fetchKey now defaults to the scope ID (if using scoped CSS) or the component name.

@danielroe danielroe marked this pull request as ready for review December 12, 2020 23:53
danielroe added a commit to nuxt/website-v2 that referenced this pull request Dec 15, 2020
@drewbaker
Copy link

PLEASE PLEASE PLEASE merge this! Solves so many problems for us at https://github.com/funkhaus

@pi0 pi0 merged commit 92018e5 into dev Dec 17, 2020
@pi0
Copy link
Member

pi0 commented Dec 17, 2020

Merged. Should be available soon on nuxt-edge and 2.15.0 release.

@drewbaker
Copy link

@pi0 Thanks for doing this! Is there a guide or tips on how to use nuxt-edge? Because I get get all sorts of webpack build errors using it (for the first time just now).

@pi0
Copy link
Member

pi0 commented Dec 17, 2020

@drewbaker Simply remove nuxt from package.json and use yarn add @nuxt/core-edge@2.14.13-26803446.5318172. It is possible BTW that edge release is broken with some dependencies. Would be nice if can make an issue with errors and current config.

@drewbaker
Copy link

@pi0 Thanks. Just opened this issue about the build error I'm seeing. Doubt it's related to this PR, but figured I'd mention it: #8508

@drewbaker
Copy link

This no longer works in 2.15.0-26876193.fffb1a19.

@katerlouis
Copy link
Contributor

katerlouis commented Apr 21, 2021

OMG this solved my issue (and probably many others more where I had to go for workaround)! Thank you so much @danielroe

I've now spend 3 full days on solving this, because even after many learnings nuxt SSG and SSR is pretty much still a blockbox for me.

So feedback from a noob:
One central resource or deep dive on what acutally happens in SSR and SSG.

That includes questions like:

  • Why, how and when is the fetch() hook called and cached?
  • Do I even need async with the fetch() hook? It works without and fetch() isn't blocking page or component rendering, right ? Who's waiting on fetch()?
  • What are all these js files like dist/_nuxt/4d03682.js?
  • And whats dist/_nuxt/static/my-site/payload.js? and state.js?!
  • Does my vuex store get cached/rendered/payloaded (you see the terminology is an issue for me :D)? Is there maybe even some kind of tree-shaking happening so only the used store data gets cached?

If there is a resource going in depth on this, I apologize and would kindly suggest to make it more prominent. I personally expected something like Build on the same level in the docs as Features and Concepts.

EDIT: I'd gladly act as a punching ball or sparring partner, if you guys like. You want to know what noobs think? I have all the noob questions!

pi0 pushed a commit to nuxt/website-v2 that referenced this pull request Jul 8, 2021
* docs: add documentation for `fetchKey`

* relates to nuxt/nuxt#8466

* docs: add link to PR
@codetheorist
Copy link

PLEASE PLEASE PLEASE merge this! Solves so many problems for us at https://github.com/funkhaus

That was an absolutely shameless plug.

imgbot bot pushed a commit to nuxt/website-v2 that referenced this pull request Jan 10, 2023
* docs: add documentation for `fetchKey`

* relates to nuxt/nuxt#8466

* docs: add link to PR
@danielroe danielroe added the 2.x label Jan 18, 2023
@imzedi
Copy link
Contributor

imzedi commented May 31, 2023

@danielroe @Atinux
If my component is imported using lazy import, fetch hook inside this component is called on both sever and client. i tried to add fetchKey but fetchHook called twice.

@chz
Copy link

chz commented Apr 22, 2024

@danielroe @Atinux If my component is imported using lazy import, fetch hook inside this component is called on both sever and client. i tried to add fetchKey but fetchHook called twice.

Same problem... @danielroe @pi0 any help?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Full-static payload gets mixed up using nested fetch() hooks inside dynamically loaded components
9 participants