-
Notifications
You must be signed in to change notification settings - Fork 12
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
Use an AddonsApplication
to manage load/reload of all addons
#504
base: main
Are you sure you want to change the base?
Conversation
Additional elements shouldn't be needed in our structure. This is how we can use ContextRoot with `document.html` as the context root for providers/consumers of the config context.
Everything is loaded by the `application.js` file now.
a090d72
to
6887d85
Compare
This is to be able to use our own event without defining the META HTML attribute on every single page. We don't depend on a specific API response.
This is required to be able to dynamically update the URLs from the versions in the flyout when the page is changed using `history` object (without reloading / SPA) as Docusaurus does. In that scenario we cannot use the HTML META tag because it was injected with the old value by CF Worker. Note that the CF Worker is not run after the initial request on SPA. The addons frontend will use this attribute to update those URLs accordingly when the URL changes. Required by: * readthedocs/addons#504
We cannot use the META HTML tag because it's added only on the first request. See readthedocs/readthedocs.org#11940
I was able to make everything work here 🎉 and I'm very happy with the solution I arrived at. It's a lot simpler than the original proposal. This PR is ready for review. |
63c3a6b
to
fb64f99
Compare
Hrm, I'm a bit confused on this pattern, there seems to be a few patterns mixing here. Why use the context API at all here? The context API is specifically for reactive element properties, so if this context isn't read from each addon element ( What you have here doesn't seem like it will give a reactive property to each addon -- if we update With this approach, we also don't need a It's a little difficult to follow but it feels like what you have here could be simplified down to executing this logic in |
Yes.
Currently, without the code of this PR, the Addons API is fetch only once when the page is loaded. If the user clicks on another page that doesn't perform a full reload (eg. as Docusaurus does) there is no new request to Addons API and addons are not re-initialized. That means that all the URLs from the flyout are out of date and point to the wrong page. You can try the current behavior following these steps:
|
The question is: can we use We don't require a reactive property on each addon -- we only need to subscribe as a |
It seems that's not possible. I gave it a quick try and I got the error:
|
ecef590
to
4ee0573
Compare
Boom! 💯 Lit Context are not required at all for what I want to do, actually. Thanks for your comment, it helped me to understand the workflow a lot better. I'm using just events to communicate internally and pass the I re-wrote the code to remove everything related to Lit Context. The structure was correct (using a manager class, like Let me know your thoughts! I think it's very clear now. |
4ee0573
to
237aa0d
Compare
AddonsApplication
to manage the ContextRoot
globallyAddonsApplication
to manage load/reload of all addons
I want to deploy this implementation since we are promoting more and more new documentation tools and some of them are SPA: docusaurus, markdoc, vitepress, etc... |
…11940) This is required to be able to dynamically update the URLs from the versions in the flyout when the page is changed using `history` object (without reloading / SPA) as Docusaurus does. In that scenario we cannot use the HTML META tag because it was injected with the old value by CF Worker. Note that the CF Worker is not run after the initial request on SPA. The addons frontend will use this attribute to update those URLs accordingly when the URL changes. Required by: * readthedocs/addons#504
We do still need a reactive I found the pattern here a bit hard to digest, it seems at odds with how Element properties work normally. On our elements, I guess this feels odd because this has created a secondary layer for a reactive This does feel like it could open us up to odd side effects from While I think the context API is much clearer in what it's accomplishing, this should at very least avoid recreating/finding elements unnecessarily. Once we initialize
I've shown an example of using Lines 11 to 21 in 1c3032b
I did get a similar error using
Looking at the code though, this error is unavoidable as the error happens in the constructor. However, it's still possible to use |
Thanks for your feedback here. After trying different pattern for this, I personally found the one from this PR the easiest to follow, understand and implement. I wrote about the problems/cons I've found with
I understand this. However, one of the big downsides of making In our context, I see the change in the Also note than moving the validation checks inside
I wasn't able to trigger the side effect you mention here (the logic we have in the Addon Summarizing, from all the patterns I've tried/implemented here, the one I feel more comfortable with and the one that I was able to make it work is this PR. I know that it's not the best one and it can be improved, but I wasn't even able to finish the work using That said, I'm happy to continue exploring a different pattern if we want to; but I prefer to move forward with the current one as it's working and finished. I wasn't able to arrive at at working pattern with all the other things I've tried. This PR won't affect how users interacts with out addons, so I propose to merge this PR and open a bigger conversation/discussing where we can continue exploring different/better alternatives without blocking the feature and giving a solution to those users using SPA documentation tools. @agjohnson what do you think? |
The `AddonsApplication` keeps a list of all the addons instances created when the page was loaded (`AddonsApplication.addonsInstances`). Then, when the `READTHEDOCS_URL_CHANGED` event is fired, we check if we already have instances created and, in that case, we call `addon.loadConfig(config)` to re-configure those instances with the new `config` object --without creating new ones. This commit includes some refactor as well: - Share all the `constructor()` method all accross addons - Override the `constructor()` for those addons that are not LitElements - Create `loadConfig()` methods for those addons that are not LitElements - Remove code commented out
Before dispatching the URL changed event, we check for the third argument (url). If it's passed it means that we are changing the URL and we trigger the event in that scenario. This avoids hitting the API twice on each page change.
I went ahead and implemented this. Now, we call |
We are immediatley calling `.loadConfig(config)` that changes the `config` reactive propertly, which will trigger a render automatically.
Yes, already saw that previously. I described above using the context API from the *Addon classes instead of from our elements which I think avoids most of the concerns you listed.
I wasn't describing moving validation logic into This would still use a reactive property
Side effects will happen without us noticing or knowing what to watch. Logic beyond validation and updating the element That is why if we only need validation and to update
This is safer for now. If we're able to use the context API, the code will look similar to this -- we won't reinitialize each addon again. |
// We cannot use `render(this.elements[0], document.body)` because there is a race conditions between all the addons. | ||
// So, we append the web-component first and then request an update of it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you describe this in more detail here? What race condition?
I feel this should be a solvable problem, but likely comes from using promises to initialize addons asynchronously? If we truly want promises handling the addon initialization, we can structure the promises to respect initialization order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't write that note. I just copied and pasted from another addon while doing the refactor. I think you wrote it when you started with the flyout work 😄
In any case, I tried using render()
and it doesn't work 🤷🏼
Cool! I will keep this in mind and keep experimenting with Context API in future iteration. I think it's still useful to give it a try if we can remove all the complexity I found myself limiting moving forward with that. I suppose we can change the "base event handling at |
Check if from/to URL are different after removing `?readthedocs-diff=` attribute because we don't want to trigger the even when the user enabled docdiff in the current page. Closes #506
…ns into humitos/lit-context-app
This PR follows the approach exposed in #491 (comment). Basically, it manage all the
ContextRoot
logic in one place and update all the addons as needed.This approach is a lot simpler and easier to follow than the one originally done in #419. It also requires less code changes.
Closes #157