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

Vue3 and future of hal-json-vuex #277

Open
usu opened this issue Sep 9, 2022 · 3 comments
Open

Vue3 and future of hal-json-vuex #277

usu opened this issue Sep 9, 2022 · 3 comments
Assignees

Comments

@usu
Copy link
Member

usu commented Sep 9, 2022

Knowing that we don't want to rewrite hal-json-vuex: I still found some spare time to get a bit more familiar with Vue3 and its reactivity system. Instead of just following a random tutorial, I decided to code a simple HAL json consumer. This issues is mainly meant as some inspiration for a 3am brainstorming during the next hackathon and not as a serious code proposal.

Disclaimer: The demo is really simple. No special cases or edge cases are implemented. No proxies to not throw more complexity at it already at the beginning. No updating of resources. No reloading of all already loaded entities.

How to run the demo:

npm install
npm run dev

Variant 1

Available at master branch: https://github.com/usu/hal-json-vue-demo/tree/master

Relevant code in:

Before coding anything reactive, I implemented a async promise-based consumer (main commit at usu/hal-json-vue-demo@c2478f7). This was by purpose to find out the bare minimum necessary for a consumer which doesn't need any reactive data (e.g. print-nuxt or print-react). Pretty straight-forward and clean. More magic could be added with proxies, but does the job for simple use-cases.

Secondly, I implemented a separate module which returns reactive resources (mainly the next 4 commits, probably easier to look at the final code in the master branch). The idea was to keep the 2 modules completely separated, with the idea that this could theoretically even be 2 different npm packages.

A problem I immediately run into, was that api responses can have side effects beyond the requested resource (e.g. I request/load a specific resource and receive data for 10 additional embedded resources). Hence, a way is needed to signal the reactive objects when data in a resource changes. I implemented this with tracking a small dependency-map and with emitting events from the async module, whenever new data for a resource is received.

Nothing spectacular and works well. Plus keeps the 2 modules well separated and minimum dependencies needed for the async module. However, this is for an easy base case only (updating data in a resource). More complexity would probably come with updating relations (=changing a link from one entity to another) or changing collections. My gut feeling says that this is a bit of a rabbit hole and we would end up implementing a lot of functionality that others have already solved better (=reactivity system).

Variant 2

So variant 2 was born: Insteading of using an own dependency-tracking & event-system, this is using the Vue reactivity system to signal updates from the async module to the reactive module.

Visible at vue-reactivity branch: https://github.com/usu/hal-json-vue-demo/tree/vue-reactivity
Main change in this commit usu/hal-json-vue-demo@b222441 (basically removing the manual dependency tracking and making objects already reactive in the async module)

  • Advantage: Works out of the box pretty well. No own implementation of dependency tracking.
  • Disadvantage: Async module now requires vue reactivity. This might not be that severe, as vue/reactivity is now also available as standalone package + for async module users, data could still be unwrapped, such that users of the async module never see a reactive object.

Additional plus: Further features felt natural and straight-forward (would have struggled a bit how to tackle them with variant 1), e.g.:

@usu
Copy link
Member Author

usu commented Sep 10, 2022

Variant 3: relation loading

https://github.com/usu/hal-json-vue-demo/blob/vue-reactivity-resource-loader/src/api/reactive.js
https://github.com/usu/hal-json-vue-demo/blob/vue-reactivity-resource-loader/src/components/ReactiveTest.vue

Allows loading deeply nested relations, e.g.
entity1.getRelation("parent").getRelation("nonEmbeddedRelation");

Still so far without proxies and only bare minimum. No collections.

One caveat: changing relation links would make it necessary to update all already requested subpaths.
E.g. when entity1.getRelation("parent") points to a new parent, then entity1.getRelation("parent").getRelation("nonEmbeddedRelation") will probably also point to a new relation (or might not even exist anymore as a relation on the new parent).

This is not yet working in this demo.

@usu
Copy link
Member Author

usu commented Oct 1, 2022

Some good packages to collect some inspiration (e.g. on internals, on the module's API, on the test cases):

  • SWRV
    Stale-while-revalidate for Vue; returns reactive object and populates with data, when data is loaded (incl. caching)

  • VueUse
    Large collection of various small composition utilities, very good documentation, e.g useAsyncState

@carlobeltrame
Copy link
Member

carlobeltrame commented Nov 22, 2022

Another place to collect inspiration from is React Query, or the Vue version Vue Query.
I hear this blog post series is quite good at explaining the use cases and pitfalls: https://tkdodo.eu/blog/practical-react-query
This library can be used to handle the loading / reloading / caching, while being very open about how the data is actually fetched (axios, localstorage, anything we want). It was described to me as a similar thing to swr, but with more features.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Status: No status
Development

No branches or pull requests

2 participants