Hi community, I find this a fascinating topic - and I know some of you are excited about it too. Maybe you already have experience with the topic.
I thought I would put my notes here publicly for anyone in the community to comment on or contribute to.
Note: I use Angular and React in the title, but this topic applies to all frontend frameworks (FF).
First things first: theres a lot of complexity here, the FF is javascripting and manipulating the DOM. The Page editor is doing the same thing. A really convincing solution may take a lot of work, or could be a "fools errand".
Alternatives
Maybe you should do something different then trying to build an FF app with Magnolia components!
Go headless
Create a completely separate FF app outside of Magnoila, and simply call content from Magnolia via REST.
In this scenario the page editor is not used.
Entire FF app in one template
It is easy to place an entire FF app in one template (either a page or a component). Then, an editor can place that FF app anywhere in the project.
(There's a good example of an Angular 1 app in a page template here: https://github.com/magnolia-cms/angular-travel-demo)
Approaches
How could we pull this off?
Placeholders in the editor (Simple)
For each component, render it in two different ways. Render a "placeholder", a non-javascript version when you are in the page editor, so that the JS does not collide with the editor. Render the full FF javascript version when not in the editor. This can be achieved with the system state helpers in FTL. https://documentation.magnolia-cms.com/display/DOCS/cmsfn#cmsfn-Systemstatehelpers
cmsfn.isEditMode() cmsfn.isPreviewMode()
Several customers take this approach.
Component by component
The FF has a special bootstrapper that can connect the framework to multiple DOM elements, instead of one single DOM element. The bootstrapper looks for a special element name, class, or attribute. (maybe such a bootstrapping mechanism already exists in the FF - maybe you need to find or create one.)
If that FF boostrapper exists, then it is a simple matter to have each Magnolia component generate that expected DOM element's HTML.
Magnolia then renders as normal on the server side, then the bootstrapper JS is run on the client side and many FF JS components are instantiated bound to the separate DOM nodes in the page.
Various techniques can be used to then manage state across those components if required.
Pros | Cons |
---|---|
|
|
Some existing libraries and demos for this approach:
React-Habitat
Bootstraps many elements into React (basically each one delivered by a component).
https://github.com/DeloitteDigitalAPAC/react-habitat
Then if you want them to talk to each other, you can use a react state container like Redux or Cerebral (https://github.com/cerebral/cerebral).
Great example of this in action with Magnolia: https://github.com/burning-duck/rehace-github-magnolia
Angular multi-loader
This is not a library, but a demonstration / working PoC I put together of this approach in Angular:
angular-multi-loader-demo
A demonstration of bootstrapping multiple angular components on different elements. It takes a similar approach to "react-habitat".
https://github.com/topherzee/angular-multi-loader-demo
Caveat: does not support magnolia areas in components - so - no nesting.
(And a Magnolia light module demonstrating it: https://github.com/topherzee/angular-magnolia-demo)
Page Editor Hooks
Compose an App with the page editor
Working Proof of Concept:
https://git.magnolia-cms.com/projects/SERVICES/repos/front-end-concept/browse
Approach:
Tweak the FF to output the Magnolia "page editor HTML comments" for components and areas.
The page editor will attach to these and add its "Green bars" where appropriate. The page editor then works as normal and provides dialogs and saves content to JCR.
A simple approach to load the content from JCR is to supply an special endpoint which returns the entire JCR content of a page in JSON form. So it contains which components are in each area as well as the content stored via dialogs in each of those components. (there could be other approaches to this to load fragments of the content dynamically based on useer activities.
Tweak the FF to both
- Dynamically instantiate FF components based on the JSON.
- Provide the content to each instantiated FF component as "props" or "arguments".
Background:
The Magnolia page editor uses a seemingly clunky - but actually really powerful and flexible mechanism to attach the Page Editor UI to a webpage. In the context of the Page editor, the templates insert HTML comments which include all the meta information the page editor needs to do its job. (the type of template, the available templates in an area - ect). Do a View Source in the page editor to see what I mean. The Page Editor JS scans the page for these comments and then based on them: adds the "Green bars" of the page editor where appropriate.
Pros | Cons |
---|---|
|
|
What else?
Have you thought of or tried another approach?
Additional Resources
Conference talk from Agido's Morit Rebbert
https://www.slideshare.net/Magnolia_CMS/magnolia-angular-js-an-approach-for-javascript-rias-delivered-by-a-cms
https://www.youtube.com/watch?v=_V9uBt_jJQo
Ways to integrate React with magnolia. (but not composing an App with the Page editor)
https://www.magnolia-cms.com/blogs/christopher-zimmermann/detail~&don-t-manage-the-content-of-your-react-app~.html
https://github.com/magnolia-cms/react-demos
Research
See this sub page for some research notes which could be helpful if you are digging deeply into this topic:
Research for FF page editor integration
And you?
What do you think? What approaches have you tried? I invite you to edit this page or add a comment.