Package Compatibility in RoC Engine #425
andy-haynes
started this conversation in
Implementation
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Motivation
NPM package support in RoC Engine is almost entirely contingent on a package's compatibility with the Engine's iframe-based container architecture. Accordingly, pure JS packages (
lodash
,uuid
) function without issue, while React UI libraries (@chakra-ui/react
,@radix-ui
) tend not to function at all.In exploring compatibility across the packages in the latter category, two prominent compatibility-breaking characteristics emerged:
@radix-ui
,@mui/material/*
@chakra-ui/react
,react-bootstrap
,@nextui-org
These behaviors are described in detail below, along with their underlying causes and potential remediations.
JS Bundling
Context
RoC Engine relies on
esm.sh
, a CDN for NPM packages, to source external dependencies. Package CDNs likeesm.sh
orjsdelivr
are an essential source of bundles, as browser-side bundling solutions are largely experimental and a server-based approach introduces new complexity while negatively impacting decentralization.esm.sh
is unique in that it supports URL parameters to rewrite import specifiers, the crucial component in Preact compatibility. This is what lets us swap outreact
andreact-dom
references withpreact
andpreact/compat
, enabling use of Preact within iframe containers, which in turn is necessary to facilitate Component lifecycle across containers. Without this functionality, packages with React dependencies could not be rendered.While many NPM packages (including React-based packages) work with this method, testing revealed that several popular UI libraries have broken bundles in
esm.sh
. The dynamic nature ofesm.sh
makes it possible for directly-imported packages to have broken nested dependencies, which cannot be determined without attempting to resolve the package's dependencies viaimport
. When this resolution fails, container initialization does not complete and Components in that container (along with its descendants) cannot be rendered.Findings
Since different packages exhibit different bundle failures (e.g. bad import paths, transpilation issues), it's difficult to draw general conclusions from this behavior. Without a deeper examination of individual packages and a more thorough understanding of exactly how
esm.sh
constructs bundles, it's not clear whether this is a systemic issue.Ostensibly there is nothing about these packages that makes them fundamentally incompatible with Preact. If that is the case, then some combination of the following should be possible:
esm.sh
can update its bundling/import rewrite logic to produce valid bundlesNon-Interactive/Unstyled Components
Context
Rendering in RoC Engine works by sending updates to the outer application when Preact nodes are rendered. This covers the Component lifecycle (hooks, rendering from
props
updates), but does not capture "side effects", i.e. changes to the iframe document made outside the scope of Component lifecycle are not reflected in the outer DOM. Similarly, usage of thewindow
object in package code will not reflect that of the topwindow
in the outer application.In addition, coupling rendering to the Component lifecycle fails to implement React functionality outside the conventional render flow. React Portals in particular appear to be impacted by this, which are often used to facilitate advanced functionality prevalent in React UI libraries.
Findings
While this exploration has uncovered deficiencies in the Engine's rendering, they can largely be shored up by extending the current implementation to cover a wider scope of interactions. It's still not clear exactly to what extent parity could be achieved, given the limitations of the container architecture. However, these deficiencies can be addressed systematically to yield progressively better compatibility. Based on behaviors observed across packages, priorities should be in roughly the following order to maximize impact:
<Box />
)ref
implementation, it's likely that RoC Engine could support this functionality.<Tooltip />
).window
ordocument
may be required to shore up other kinds of functionality.requestAnimationFrame
.Conclusions
The most promising path toward supporting a subset of popular libraries (e.g.
@chakra-ui/react
) would be to focus on widening the scope of captured DOM changes beyond the Component render lifecycle. This should enable most of the styled Components supported by compatible packages. Implementing React Portal, likely a more complex task, should enable much of the remaining functionality for advanced DOM interactions. These tasks can be addressed in parallel and should enable a substantial subset of Components provided by compatible React UI libraries.Packages found to be incompatible due to broken bundles likely need to be addressed individually. In some cases, this may be a fix on the
esm.sh
side while in others it may be an issue in the package's bundling configuration. If the source of a broken bundle can be determined, then the issue can likely be addressed by the upstream provider. However, there may be other options available (e.g. forking, injecting pre-bundled packages) if an upstream fix is not viable. Ultimately this is a hard boundary to compatibility and touches on the tenuous nature of RoC Engine package imports.cc @mpeterdev @thisisjoshford @charleslavon
Beta Was this translation helpful? Give feedback.
All reactions