Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comparisons with Shortcake and JS Widgets #1

Open
westonruter opened this issue Feb 2, 2017 · 13 comments
Open

Comparisons with Shortcake and JS Widgets #1

westonruter opened this issue Feb 2, 2017 · 13 comments

Comments

@westonruter
Copy link

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
Copy link
Author

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
Copy link
Author

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

@mattheu
Copy link

mattheu commented Feb 2, 2017

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
Copy link

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
Copy link

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

@sirbrillig
Copy link

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
Copy link
Owner

aduth commented Feb 2, 2017

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:

  • Defining blocks by a schema allows for it to be agnostic to its render context. By exposing it through the REST API, other clients (e.g. mobile app) can become aware of and have distinct rendering implementations for managing blocks.
  • A typical WordPress hosting environment would not have the tools to be able to render a block on its own if defined in JavaScript, meaning we rely on the markup having been generated in the client prior to saving.

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:

  • Allow block rendering to be a resolveable promise to enable server-side rendering if so inclined
  • Consider JavaScript rendering implementation to be an enhancement atop a well-defined schema (with fallback auto-generated UI)

@aduth
Copy link
Owner

aduth commented Feb 2, 2017

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
Copy link

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
Copy link
Author

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 😉

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
Copy link

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
Copy link

nylen commented Feb 2, 2017

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
Copy link
Owner

aduth commented Feb 3, 2017

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants