Open ItsJonQ opened 4 years ago
Had a wonderful chat with @griffbrad today!
One of the things we talked about was this ContextSystem x Adapter strategy. Brad had pointed out that these mechanics are similar to that of "feature flagging".
I thought that was a wonderful way to look at it.
Yes! Indeed. ContextSystem x Adapters enables use to "feature flag" our way to safely integrating G2 in Gutenberg π
Let's use the Button
component as an example. Within Gutenberg, in the button/
component directory, we can add a next.js
file:
/button
|- index.js
\- next.js
All of the logic and G2 Component "rigging" can happen in that file.
For example:
// components/src/button/next.js
import { withNextComponent as withNext } from '@wordpress/ui.context';
import { Button } from '@wordpress/ui.components';
function adapter(props) { ... }
export function withNextComponent(current) {
// current - Current WP Button
// Button - The G2 Component Button
// 'WPComponentsButton' - Namespace to register into the Context System
// adapter - Adapter to bridge the props between current Button -> G2 Button
return withNext(current, Button, 'WPComponentsButton', adapter);
}
Finally, in the current Button
index.js
file, we just need to import this withNextComponent
HOC and export the wrapped component.
import { withNextComponent } from './next';
function Button (props) { ... }
export default withNextComponent(Button);
With this technique, there's a clear division between:
Chatted with @griffbrad today! In addition to the technical implementation, @griffbrad had suggested the idea having guides for developers. Developers who have existing 3rd party block code, and devs who want to build something brand new.
I don't think we necessarily need to write a details walkthrough/guide, at least not in the beginning. However, I think we should have a ~good~ solid sense of what the migration path would be like for both core and 3rd party devs.
Expanding a bit on the Context/HOC strategy above.
It seems like the current plan is to add the G2 packages into Gutenberg as separate packages (e.g. @wordpress/ui.components
... maybe).
This would certainly make it clearer which parts of the system you're working in (e.g. @wordpress/data
).
The question is, should we globally export and expose the G2 component code?
So that @wordpress/ui.components/Button
exports to window.wp.ui-components.Button
.
I would say no.
I propose that G2 Components is surfaced throughout the project, as well as globally (window
), via @wordpress/components
.
There will be a (long) period where we'll have 2 component codebases.
Overtime, as we've completely migrated over to G2 Components, we'll be able to move the @wordpress/ui.components
code into @wordpress/components
, and move the current code into (maybe) into legacy.js
files - similar to how G2 code exists in next.js
files in the current integration proposal (above).
In short, G2 Components should ultimately become @wordpress/components
.
We're just working out the details on how to do it :)
And these details should define and influence how we approach best practices and developer guidelines/tutorials.
It seems like the current plan is to add the G2 packages into Gutenberg as separate packages (e.g. @wordpress/ui.components ... maybe).
Why a separate package? I'd personally prefer a folder in the same package instead. This ensures it's organized properly and at the same time only exposed internally and not externally (through wp.*)
button example
In the Button example above, I believe it means we keep both components working right? How does one consumer switches? Also can't we instead remove the legacy component and have a "prop adapter" instead (rewriting props, triggering deprecations for deprecated props) but still use the G2 components for both usage?
Why a separate package?
At the moment, G2 Components has about 8 primary packages (about 6 if you exclude packages that are basically dependency aliases):
animations
(aka. framer-motion
)a11y
~ (can be dropped for reakit
)components
context
create-styles
gestures
(aka. react-use-gesture
)styles
substate
utils
I'd personally prefer a folder in the same package instead.
Just double checking. Is your suggestion for all of these packages to be moved directly into @wordpress/components
?
For context, these packages do very different things (not unlike how many of the current @wordpress/*
packages are split/organized).
It's also valuable to be able to use/share styles from certain G2 packages (like utils
, state
or styles
) in code beyond the components package. Based on my experience with (current) Gutenberg and more recent experience with G2 Components, I'm very certain things that fall into the "Design Tools" category will benefit greatly from this shared code.
(e.g. Performant state management/syncing, unit parsing/serializing)
In the Button example above, I believe it means we keep both components working right?
Correct!
How does one consumer switches?
With this strategy, there are two primary ways to render the new Button.
Inline version
prop:
<Button version="next">...</Button>
Or, with a ContextSystemProvider
:
<ContextSystemProvider value={{ WPComponentsButton: { version: 'next' }}>
...
<Button />
...
</ContextSystemProvider>
(Note: We can change the version
prop to anything we want. That's just the prop I've chosen for my initial tests)
Also can't we instead remove the legacy component
Unfortunately not, mostly for style conflict reasons.
For example, the Button
. It's being used in many (many) places, some of which have custom styling (e.g. Toolbar).
Replacing the current Button
with the G2 Components Button won't break (JS) component rendering (assuming all props are adapted), but it would break CSS styling rendering.
Having the feature-flag like control of the ContextSystemProvider
allows us to incrementally upgrade things while (hopefully) reducing unexpected side-effects (again, mostly from CSS related conflicts).
That being said, I'm 100% open to alternative strategies. This incremental context-based "chunking" migration strategy was something I've used in the past (with great success).
Hope this helps! Really appreciate your thoughts @youknowriad ! β€οΈ
Just double checking. Is your suggestion for all of these packages to be moved directly into @wordpress/components?
I see, I think it seems there's value in these packages being separate (maybe not all, we'll have to see). The important thing though is that they stay as "bundled modules" (like @wordpress/icons and @wordpress/interface right now) to avoid having them leak as public APIs in WordPress.
for the components one (I guess the highest level one), I think we should avoid the temporary package and just use a folder in @wordpress/components
to start with.
Inline version prop:
π I wonder if we should mark this prop as unstable, since it's only useful during the migration.
Unfortunately not, mostly for style conflict reasons.
So you're saying, once we migrate all buttons usage in our codebase, we can remove the old implementation. that seems reasonable.
The important thing though is that they stay as "bundled modules" (like @wordpress/icons and @wordpress/interface right now) to avoid having them leak as public APIs in WordPress
Wonderful! icons
and interface
are the ones that come to mind for how I'd imagine these G2 packages working - especially icons
as those bits of code can be accessed in many other parts of the Gutenberg codebase.
for the components one (I guess the highest level one), I think we should avoid the temporary package and just use a folder in @wordpress/components to start with
I'm open to that. Although, I think there's value in separating the newer G2 Components code in same way. If all of it goes into @wordpress/components
, I feel like they should live in a directory labelled __next
(or something similar).
Perhaps like this:
src/
βββ button/
β βββ __next/
β βββ index.js
βββ card/
β βββ __next/
β βββ (other files)
β βββ index.js
βββ hstack/
β βββ index.js
βββ etc...
I feel like the structure above can make code easier to find (since the G2 code is scoped locally to it's named directory), while encapsulating and signifying the "next" version of code that's being worked on.
In this above example, I've included HStack
(one of the new layout-based primitive components), specifically because it currently doesn't exist within @wordpress/components
.
For cases like this, I think it would be okay organize the files without using a __next/
directory.
π I wonder if we should mark this prop as unstable, since it's only useful during the migration.
I'm happy with that :). I think using __unstableVersion
(or something similar) is a good signifier that stuff is being updated.
So you're saying, once we migrate all buttons usage in our codebase, we can remove the old implementation.
That's my hope π . That these G2 Components eventually become @wordpress/components
.
Since we can migrate things incrementally, that means that we can also remove the old implementation incrementally as well - rather than waiting for the day were we remove all of the old code in one-shot (which, we can do if that's a better strategy).
Once all of the previous implementation is removed, all that remains of it are the (now) legacy component APIs.
At that point, we can decide if we want to deprecate these component APIs in favour of newer ones that make sense to the ecosystem.
cc'ing @saramarcondes
Going with out Context System based integration strategy, we need to create a series of "adapters" to bridge the props/markup between the current WordPress components UI and the G2 components UI.
Using the Typography Design Tools as the potential G2 launch candidate/vehicle.. I've identified a list of components we need to pay attention to.
βοΈ Required G2 Components
π Existing WP Component equivalents
If we want to bring the G2 Typography tools experience (in it's entirety), we'll need to ensure the above listed components (under π) are π― adapted.