This is an experiment that uses the Mitosis compiler to create Gutenberg blocks using the Mitosis syntax and compile them to both React for frontend and a Liquid template to be rendered on the server in PHP.
This approach tackles both the problems of duplication of logic between the PHP and JS parts of the block. It also addresses the issue of hydration of blocks as the final JS that hydrates the block is generated by the compiler.
-
Clone this project inside your
wp-content/plugins
directory or you can usewp-env
. -
npm start
. -
npm run compile
- This will compile theblock.mitosis.js
component to both React and a Liquid template and place them insrc/_generated/
. You'll have to run this manually after every change toblock.mitosis.js
.
If you'd like to see the server rendered output, you can toggle the request blocking in your browser's DevTools like:
Even though this repo was created with @wordpress/create-block
, there is no
reason why we could not generate files on the fly in the same way as Blocky
does. This way, we could define our block with just a plain block.json
file and a
block.mitosis.js
file and the rest could be generated dynamically.
I think it would also be interesting to be able to provide custom "loaders" in PHP,
which could be a bit similar to
getServerSideProps()
in Next.js or Loaders in
Remix.
Of course, this would not provide any additional functionality but rather simplify creation of blocks by requiring only the following files to create a block:
block.json
block.js
- in the Mitosis format, or whaterver other format we might finally settle on.loader.php
- the file that defines a single "loader" function which has to return props in a JSON format. Under the hood, this function is used on the server side to pass the props to the generated template.
I could imagine that while for now those "loaders" would return JSON, they could also in the future return React Server Components!
Yup, Mitosis could output code for Vue, Svelte, Solid and a couple other frameworks.
Ok, this is nice, but I'm concerned about javascript bloat. Like, when I create 5 blocks, I will generate 5 bundles and each one of them will include React?
Good point. Currently, each block does its own bundling which means that yes, you would include React 5 times on your page. You could configure webpack to output shared libraries to shared chunks if you are the author of each of the block. However, if you'd like to just use third-party blocks where you don't control the bundling, you're out of luck.
I think the real solution (which is beyond the scope here) would be to output ESM and import maps which has started being discussed in WordPress/gutenberg#36716.
-
The compiled output is far from perfect. The generated react component does not actually work out-of-the-box and needs a few search-and-replace regexes in order to run fine (look in the
./compile.sh
file). Mitosis also does not generate the correct Liquid tags if we pass a more complex expression to<For each={} />
like e.g.<For each={someObject.items.concat(otherItems)}>
. -
For some reason, Mitosis wants to by default handle state with
mobx-react
and CSS with Emotion. I see no inherent reason for that, but I'm sure it could be configured to output more vanilla components. -
Mitosis syntax is meh. The syntax is similar to React but it's not React and it kinda shows. It's definitely a bit more tedious to define your components this way and there are some gotchas, too.