Invoke is a leading creative engine for Stable Diffusion models, empowering professionals, artists, and enthusiasts to generate and create visual media using the latest AI-driven technologies. The solution offers an industry leading WebUI, and serves as the foundation for multiple commercial products.
The canvas react components pass canvas entity identifiers around, then redux selectors are used to access that entity. This is good for perf - entity states may rapidly change. Passing only the identifiers allows components and other logic to have more granular state updates.
Unfortunately, this design opens the possibility for for an entity identifier to point to an entity that does not exist.
To get around this, I had created a redux selector selectEntityOrThrow for canvas entities. As the name implies, it throws if the entity is not found.
While it prevents components/hooks from needing to deal with missing entities, it results in mysterious errors if an entity is missing. Without sourcemaps, it's very difficult to determine what component or hook couldn't find the entity.
Refactoring the app to not depend on this behaviour is tricky. We could pass the entity state around directly as a prop or via context, but as mentioned, this could cause performance issues with rapidly changing entities.
As a workaround, I've made two changes:
<CanvasEntityStateGate/> is a component that takes an entity identifier, returning its children if the entity state exists, or null if not. This component is wraps every usage of selectEntityOrThrow. Theoretically, this should prevent the entity not found errors.
Add a caller: string arg to selectEntityOrThrow. This string is now added to the error message when the assertion fails, so we can more easily track the source of the errors.
In the future we can work out a way to not use this throwing selector and retain perf. The app has changed quite a bit since that selector was created - so we may not have to worry about perf at all.
Related Issues / Discussions
Offline discussion.
QA Instructions
There should be no functionality changes. The canvas layer list items for each canvas entity are now wrapped in the gate component. Those list items render as expected, which indicates the changes are working fine.
Merge Plan
n/a
Checklist
[x] The PR has a short but descriptive title, suitable for a changelog
Summary
The canvas react components pass canvas entity identifiers around, then redux selectors are used to access that entity. This is good for perf - entity states may rapidly change. Passing only the identifiers allows components and other logic to have more granular state updates.
Unfortunately, this design opens the possibility for for an entity identifier to point to an entity that does not exist.
To get around this, I had created a redux selector
selectEntityOrThrow
for canvas entities. As the name implies, it throws if the entity is not found.While it prevents components/hooks from needing to deal with missing entities, it results in mysterious errors if an entity is missing. Without sourcemaps, it's very difficult to determine what component or hook couldn't find the entity.
Refactoring the app to not depend on this behaviour is tricky. We could pass the entity state around directly as a prop or via context, but as mentioned, this could cause performance issues with rapidly changing entities.
As a workaround, I've made two changes:
<CanvasEntityStateGate/>
is a component that takes an entity identifier, returning its children if the entity state exists, or null if not. This component is wraps every usage ofselectEntityOrThrow
. Theoretically, this should prevent the entity not found errors.caller: string
arg toselectEntityOrThrow
. This string is now added to the error message when the assertion fails, so we can more easily track the source of the errors.In the future we can work out a way to not use this throwing selector and retain perf. The app has changed quite a bit since that selector was created - so we may not have to worry about perf at all.
Related Issues / Discussions
Offline discussion.
QA Instructions
There should be no functionality changes. The canvas layer list items for each canvas entity are now wrapped in the gate component. Those list items render as expected, which indicates the changes are working fine.
Merge Plan
n/a
Checklist