aduth / wp-block

Post editor blocks support for WordPress
6 stars 0 forks source link

Comparisons with Shortcake and JS Widgets #1

Open westonruter opened 7 years ago

westonruter commented 7 years ago

I'm curious about how this prototype differs from Shortcake (Shortcode UI) in how it also extends the TinyMCE View. Also the block definition looks quite similar to how widgets are defined in JS Widgets, which have prototype integration with Shortcake. The main difference seems to be that Blocks requires that the display logic require the use of client-side templates, whereas Shortcake (and JS Widgets) use PHP server-side rendering for the display. Something also that JS Widgets has at its core is defining the attributes in JSON Schema so that the widgets (blocks) can interface with the REST API.

Anyway, just wanting to keep lines of communication open, making independent prototypes but also not reinventing the wheel when unnecessary.

westonruter commented 7 years ago

Also, is client-side rendering of blocks something that should be the default? Most of the discussions on this I've seen have tended toward using PHP to render the display of blocks. In your wp-auth, maybe the display callback should return a promise so that client-side OR serve-side rendering could be employed. For back-compat with existing blocks (shortcodes and widgets), server-side rendering is going to be required, whereas for brand new blocks perhaps they could then make use of JS rendering.

westonruter commented 7 years ago

Cross-reference discussion on Slack: https://wordpress.slack.com/archives/core-editor/p1486009284002442

mattheu commented 7 years ago

Client side rendering of the blocks does make it feel much snappier. However we opted for the server side rendering on Shortcake to try and make the preview exactly the same as the way it will be rendered on the front end, with as little effort as possible.

I do like the idea of having the option of providing client side display. Firstly because it makes it render faster, but you can craft a preview for more complex blocks - especially with a lot of JS to render them. Right now in shortcake you end up having to do a bunch of customisation anyway, but don't get the speed advantage of having it all client side.

danielbachhuber commented 7 years ago

I do like the idea of having the option of providing client side display. Firstly because it makes it render faster, but you can craft a preview for more complex blocks - especially with a lot of JS to render them.

+1 to defaulting to PHP rendering, and providing a JS-rendering progressive enhancement API

danielbachhuber commented 7 years ago

Worth noting that Shortcake has a rudimentary forms and fields API.

sirbrillig commented 7 years ago

Since static blocks are likely going to be encoded as raw html in the post content anyway (dynamic blocks will need more consideration, but we're not there yet), then we get server-side-rendering "for free" even though the blocks are rendered in javascript prior to saving.

However we opted for the server side rendering on Shortcake to try and make the preview exactly the same as the way it will be rendered on the front end, with as little effort as possible.

In this case, the preview for the block would be exactly the same as it would appear on the front-end, since the markup in both places is being generated by the JavaScript block.

In addition, if a block can be rendered on the client side then there is less need for the round-trips associated with selective refresh, meaning we get instant previews of changes without any extra code and it can work offline (or with poor connectivity).

aduth commented 7 years ago

Thanks for starting this discussion. It hadn't been my intention to disregard prior art or ignore existing WordPress paradigms. In Slack, I'd expressed some curiosity for how we might reconcile this idea of blocks we're considering for the editor with shortcodes and widgets, so I think we're on the same page in that regard.

For the purposes of this prototype, I'd wanted to find a good balance between both user and developer experience. In doing so, I'd made a few assumptions:

As a user, I think of content in terms of how it appears on my site, not by the individual data it may very well be composed of. I want as few touch points between seeing my content and changing it. The context switch between front-end and back-end may already be confusing enough, so the editing experience should be relatively self-contained.

Given these assumptions, I'd concluded that editing individual blocks of content should occur inline and should have some resemblance to how I expect it to look on the front-end. Presenting a modal or series of fields are unnecessary context switches which add barriers to the user's task at hand.

To achieve this, some amount of JavaScript will be necessary to embed the rendered block in the editor. Changes should ideally occur in real-time, which means we cannot afford round trips to the server to retrieve the updated content. The implementation proposed in this prototype would have a block define its render behavior much like a Controlled Component in React where its visual representation can be determined at any point in time given the current data state.

Now a couple points to concede:

In this first iteration I'd put more weight to achieving a good end-user experience. While I think the above points are solveable problems, I'd be curious also to explore middle-ground options, as mentioned already:

aduth commented 7 years ago

Also, a specific example per the original question. In Screenshot 2 of the Shortcake documentation, I think we should strive to allow a user to click or select any part of the preview text and modify it directly.

Screenshot 2

danielbachhuber commented 7 years ago

In Screenshot 2 of the Shortcake documentation, I think we should strive to allow a user to click or select any part of the preview text and modify it directly.

At some point, it would be interesting to get a spreadsheet going of all potential blocks that could be displayed in the editor, which values of the block that a user might want to edit, and whether value is directly editable within the presentation of the value.

westonruter commented 7 years ago

danielbachhuber: +1 to defaulting to PHP rendering, and providing a JS-rendering progressive enhancement API

This is essentially what customizer has been doing with a hybrid postMessage live preview prior to selective refresh response rendering. See #33738. For example, when you type Hello--"world" in the Site Title control you'll see that displayed verbatim in the preview, but then moments later it gets the PHP-rendered value back from the server and you see Hello—“World” (with filters like wptexturize applied). In other words, it's a low-fidelity instant preview followed by a server-rendered high-fidelity preview.

danielbachhuber: Worth noting that Shortcake has a rudimentary forms and fields API.

I personally think it should re-use the API as provided by the customizer, which is what JS Widgets builds upon (though forms for such may be implemented using other frameworks as well).

sirbrillig: In this case, the preview for the block would be exactly the same as it would appear on the front-end, since the markup in both places is being generated by the JavaScript block. ¶ In addition, if a block can be rendered on the client side then there is less need for the round-trips associated with selective refresh, meaning we get instant previews of changes without any extra code and it can work offline (or with poor connectivity).

@sirbrillig Do you think that client-side rendering should be the preferred rendering approach? From the discussions I've seen it seems that the majority think that server-side rendering is still preferred, if not for SEO than for accessibility (e.g. JS being turned off). Though I see there are arguments to the contrary :wink:

aduth: Given these assumptions, I'd concluded that editing individual blocks of content should occur inline and should have some resemblance to how I expect it to look on the front-end. Presenting a modal or series of fields are unnecessary context switches which add barriers to the user's task at hand.

Yes, that certainly makes for a better user experience! I'll have to get more familiar with React to speak more intelligently about it, but I think that blocks should be framework agnostic. A block should be able to be implemented using any JS framework (React, Vue, Backbone), as long as it is follows the same base interface which is what the Form class in JS Widgets is prototyping. I guess the main thing is that the interface needs to have the hooks to allow for a block to make use of React's Controlled Components in the editor. As long as the render callback passes the block object which contains the state, that should suffice.

At some point, it would be interesting to get a spreadsheet going of all potential blocks that could be displayed in the editor, which values of the block that a user might want to edit, and whether value is directly editable within the presentation of the value.

I'm pretty sure a draft for such a spreadsheet exists at Automattic.

Thanks for the discussion!

sirbrillig commented 7 years ago

Do you think that client-side rendering should be the preferred rendering approach? From the discussions I've seen it seems that the majority think that server-side rendering is still preferred, if not for SEO than for accessibility (e.g. JS being turned off).

If JS is turned off, in my opinion I think it's unlikely someone will be using the editor/customizer anyway. I could be wrong, and I'm sure there's data somewhere that could make the answer clear. But assuming that it is true for the moment, if JS is turned off when someone is visiting the site front-end (eg: an SEO spider), the content has already been rendered into static html by that point so no javascript is needed.

It's for that reason that I think that "client-side rendering" is the better approach. I put it in quotes because the content is still rendered on the server-side when it is displayed on the site front-end. It's only rendered client-side in the editor.

nylen commented 7 years ago

I think that blocks should be framework agnostic. A block should be able to be implemented using any JS framework (React, Vue, Backbone), as long as it is follows the same base interface which is what the Form class in JS Widgets is prototyping. I guess the main thing is that the interface needs to have the hooks to allow for a block to make use of React's Controlled Components in the editor. As long as the render callback passes the block object which contains the state, that should suffice.

This is a good goal, but there is also a lot of value in providing a "standard" set of libraries that people can use, like we do with jQuery.

React+JSX+Redux seems like a pretty natural choice here.

This will help alleviate potential issues like WP sites ending up with 6 copies of React, Preact or other React alternatives, 3 Angulars, and whatever else people might decide to use in absence of a semi-official recommendation.

Updates to the bundled library would be a concern, as we saw recently with Underscore.js.

aduth commented 7 years ago

I think that blocks should be framework agnostic. A block should be able to be implemented using any JS framework (React, Vue, Backbone), as long as it is follows the same base interface which is what the Form class in JS Widgets is prototyping.

In this first iteration, I remained relatively neutral on this point, even remarking in the docs that a display or form function could return markup:

Function which, when passed a set of attributes, is expected to return either an HTML markup string or instance of wp.element.

... meaning that, as-is, a developer could use any framework so long as they're able to generate markup from it.

To @nylen's point though, I do worry about fragmentation and wonder if there's some room for preferred or first-party patterns, especially if we can make a compelling case for its benefits. This thinking led me in the direction of experimenting with aduth/wp-elements. Ignoring any specific framework for a moment, there's a pretty clear consensus on "componentization" in front-end libraries. I explored the motivation for this idea further in the Elements documentation, primarily weighing performance and predictable (testable) nature of declarative components.

API changes from versioning and lock-in are real concerns though, which is why in that initial exporation I was wary of committing to any one library or defining complex APIs. To this point, I think it'll require further prototyping to see exactly what common requirements we'd have in implementing JavaScript-based block components.