openedx / XBlock

Framework for building custom learning components that run in the Open edX LMS!
https://docs.openedx.org/projects/xblock/en/latest/xblock-tutorial/index.html
Apache License 2.0
452 stars 217 forks source link

React Support for XBlock frontends #635

Open kdmccormick opened 1 year ago

kdmccormick commented 1 year ago

Goal

Full completion would mean:

Non-goals:

Prior Work

Enhanced editors for Text, Video, and Problem

https://github.com/openedx/frontend-lib-content-components/blob/main/docs/decisions/0003-V2-Content-Editors.rst

Hackathon: React HTML block student view

Hackathon: React HTML block student view

We (@nsprenkle & @muselesscreator) worked on a proof of concept during a hackaton project. Note that the actual APIs we are calling are probably not the way we want to do this and we also dangerously set inner HTML of a block on the page, but the valuable bit here is we played with having multiple types of render logic from the Learning MFE,

Source: https://github.com/openedx/frontend-app-learning/tree/bw/hackathon

The TL;DR of how we think this should work:

  1. Add frontend components for (or all) of the native edx-platform XBlocks to the Learning MFE. Others could be installed the way we install other frontend components (e.g. Header / Footer)
  2. Create a list of frontend-renderable XBlocks supported by the Learning MFE (we've been calling these FRend blocks).
  3. Update the XBlock backend with an endpoint for returning JSON data, instead of HTML using the xblock.json_handler functionality. An option is to use the student_view_data paradigm used in some other environments (e.g. mobile app).
  4. When the Learning MFE looks at a unit, it identifies if some/all of the content is frontend-renderable (FRendly).
  5. Up for debate on the best rendering scheme, whether we only drop to frontend rendering only when all blocks are FRendly, or a majority, or while under some threshold for un-FRendly blocks on a page.
  6. For each FRend XBlock on the page (or with some other bulk retrieval scheme), call the data endpoints on those XBlocks for the data to render those blocks, render at the block level.
  7. For remaining un-FRendly blocks, create iframes to render the individual/grouped blocks HTML.

Note that this should also probably be configurable per-course as some hacky (but desired by course staff) behavior could be lost with this new pattern.

Other things we learned

  1. A similar pattern was investigated during the development of the Learning MFE, but was dropped because it was considered too challenging to implement all supported XBlock frontends. This option is more iterative and allows us to continue iframeing old-style HTML XBlocks while we implement frontends for the more common components.
  2. The iframe sandbox is both a blessing and a curse. This adds security and separation from the course material and our course chrome but doesn't give us access to that course content from the Learning MFE, blocking features like context-aware annotations.
  3. There is an iframe performance overhead that gets progressively worse for multiple iframes on a page. Suggestion was to think of a rendering scheme that defers to old style unit rendering if there would be too many iframes rendered to the page.
  4. Course staff have lots of interesting hacks and tweaks to XBlocks including custom JS that cross communicate between blocks. I argue this is a bad idea, but staff seem to like it and it is a competitive differentiation. Suggestion was to allow opt in/out for a course / org.

Considerations & Open Questions

Tasks

### Tasks
- [ ] https://github.com/openedx/XBlock/issues/634
connorhaugh commented 1 year ago

Here's a good summary of V2 editors atm: https://github.com/openedx/frontend-lib-content-components/blob/main/docs/decisions/0003-V2-Content-Editors.rst

arbrandes commented 1 year ago

@muselesscreator, in view of our recent discussions around how to get React into XBlocks, I feel it's time to get back into this particular conversation. Since you're the current "man on the ground" trying to find a way to do it, I'd love your take on possible ways to make it happen without compromising architecture or UX.