Previously, a crash in a lifecycle hook for any reason would throw an
error whose stack trace started from the scheduler and contained only
the place where the hook was called by owl, but not the place where the
hook was registered by the user. This proved very difficult for users to
debug as they cannot really tell which component registered that hook.
This commit alleviates the issue by creating a new Error when the hook
is originally called, and wrapping the registered callback in a try
catch, throwing an error with the correct stack trace instead of the
error in the hook, and setting the error in the hook as the cause of
this synthetic error.
Have a GrandParent which controls whether one of its GrandChildren is displayed or not.
First, the GrandChild is displayed. Then, change the state of the GrandParent in order to kill
the GrandChild.
Before this commit the GrandChild is only removed from the DOM, as bdom correctly works.
But it is not destroyed.
After this commit, the GrandChild is correctly destroyed.
Every use case involving some sort of key set on a component would give birth to a leak in an async context:
- If a key of a component changed, the outdated one was never destroyed.
- destroyed component were never removed from their parent's reference map.
This commit solves both issues, that are tightly linked anyway.
Have a component which does a render in its onWillPatch, onPatched, onMounted hooks.
Before this commit, the result was incorrect: the second rendering was not taken into account.
After this commit, those renderings are correctly applied at the price of a delayed render when the fiber
is in a critical state.
Owl provides a way to manage errors occuring in component lifecycle
methods. However, before this commit, these errors were not always
logged or visible, which is very annoying in the common developer
workflow (doing something, checking it works, seeing no error but a
broken interface).
In this commit, we make sure errors are logged/throws in all cases:
- if an error occurs in a mounting operation => the promise is rejected
(which will log the error)
- if an error occurs after the mounting operation and is not handled by
any error handlers => the error will be logged (with console.error).
Also, in that case, this commit adds a warning to explain that owl
destroys the root component, which will help developers understanding
what happened.
Have a child component on which a render is triggered.
This component delays its willUpdateProps and makes a rendering during the willUpdateProps
Before this commit, renderings of the child were inconsistent across
its parent's renderings.
After this commit, it works as expected.
Before this commit, class inheritance when using the onError hook was unclear nay wrong.
After this commit, error handlers are called from the bottom up in the inheritance hierarchy.
If a handler doesn't rethrow the error, the handling stops there and no other handler is called.
If a handler does rethrow, the handlers declared in a parent class are executed.
In the following situation: A parent of B, B parent of C, with an error
when C is mounted, caught by B and retriggering a rendering in B, then
the onMounted hook of A wasn't properly called. This commit fixes this
problem.
When a parent and a child were rendered at the same time, it was
possible for the 2 renders to decrement the same fiber internal
counter, which meant that the render was stalled.
The slot inner working has been reworked. A prop "slots" is now passed
explicitely to the component. It looks like
{ slotName_1: slotInfo_1, ..., slotName_m: slotInfo_m }
with the objects slotInfo_i with mandatory keys "__render", "__ctx",
and optional key "__scope" and possibly others.
Here is how a slotInfo object can be created:
A slotInfo object is normally created by setting in a template something
like
<div>
<t t-set-slot="foo" t-set-scope="scope" param_1="var" param_2="3">
content
<t t-esc="scope.bool"/>
<t t-esc="scope.num"/>
</t>
</div>
and it will be used somewhere like
<div>
<t t-esc="props.slots.foo.param_1"/>
<t t-slot="foo" bool="other_var" num="5">
</div>
In the above example, the function "__render" produces the block dom
element for the content of the t-set-slot.
The context "__ctx" will have a key "scope" with value { bool: ..., num: 5 }
and "__scope" will be set to "scope".
This commit makes the reactivity system more fine grained and makes it
more eager to stop observing keys or objects when they are modified,
this results in fewer "false positive" notifications.
Before this commit, errors triggered at the level of the fiber (as opposed to at the level
of a component's rendering), were handled as the very top level of the rendering, that is,
in the scheduler.
This was wrong because components below in the rendering tree would not have a chance to handle their
children's or their own errors.
After this commit, error triggered in willPatch, onMounted and onPatched are correctly handled
at the closest component to where they were thrown.
Have a Child Compnent which has one component that succeeds and another
one that fails at its instanciation.
The Child component handles the Errors by rendering itself.
Before this commit, the error handling algorithm made impossible for the scheduler to finish.
This was because the current fiber was still counted as ongoing, when it was actually completed.
After this commit, this use case is handled correctly.
Aim to replace the abstraction "Context" from OWL 1 with the new primitives
"atom" and "useState":
- notification is done only after a batch of modifications.
- observers are notified at most once for a batch.
- an observer of type component is notified (and rerendered)
only if it does not have an ancestor that has to be notified for the
same batch of operations (anywhere in the web of references!).
- notification of components is done on all levels "simultaneously".
Co-authored-by: Aaron Bohy <aab@odoo.com>
Co-authored-by: Géry Debongnie <ged@odoo.com>
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>