Introducing Twenty Sixteen React and NodeifyWP
As web technologies and mobile devices improve and global internet speeds increase, consumers increasingly expect taps and clicks to deliver results nearly instantaneously; the “app-like” experience has become an expectation in web browsers. To this end, we’ve seen huge strides forward in web platforms and frameworks.
Among its most notable relevant advancements, WordPress introduced a JSON REST API, which opens up new, compelling use cases as a framework and content storage engine, such as headless publishing workflows. However, since WordPress runs on PHP, it can’t be used in conjunction with an important breakthrough: isomorphic applications.
Isomorphic web applications run the same code on the server and client (web browser), providing the flexibility, extensibility, and consistency to build the most modern “app-like” experiences on the web. JavaScript and Node.js are used to create isomorphic applications, since JavaScript runs natively in the web browser and is the foundation for server-side Node.js. (Learn more about isomorphic applications.)
Since we can’t run PHP in the web browser, we have a few options for creating JavaScript-powered “app-like” experiences in WordPress.
- Create a traditional PHP-based theme with a client side layer that refreshes the DOM using something like Underscore templates and the REST API. This strategy achieves the desired effect, but is a bit forced in that we have to create templates in PHP and separate ones for JavaScript. This is tough to maintain, from a development perspective.
- We can discard WordPress’s front-end (PHP-based) theming system completely, and use Node.js and something like Express to serve our front-end, pulling content from WordPress over the REST API. This presents some serious difficulties. External requests for basic data like theme options, menus, and sidebars. Customizer functionality is essentially useless. Previews are very hard to implement. The admin bar is gone. Front-end authentication is problematic. Plugins can’t interact with the front-end. The list goes on and on.
- Some hybrid of the first two options.
In pursuit of a better way, we’re introducing NodeifyWP and Twenty Sixteen React (an example theme powered by NodeifyWP), which we’re extremely excited to open source.
NodeifyWP uses PHP to execute Node.js code on the server. This is made possible by V8Js, a PHP extension for Google’s V8 engine. NodeifyWP exposes WordPress hooks, navigation menus, sidebars, posts, and more within server-side JavaScript. We’ve included a simple API for registering additional PHP “tags” within JavaScript. It also includes a REST API for retrieving route information, updated tags, sidebars, menus (and so forth) as the state of your application changes. With NodeifyWP, we can serve a true isomorphic application from within PHP: we get the benefits of WordPress and the benefits of isomorphic Node.js technologies. No separate Node.js/Express server is necessary.
Twenty Sixteen React is a rebuild of a default WordPress theme, Twenty Sixteen, using the following technologies:
By using popular, new Node.js technologies, we think that developers can make first class, “app-like” experiences with the web’s most popular CMS, WordPress.
Because V8Js and Google V8 can be challenging to set up, we’ve included a fully Dockerized environment within Twenty Sixteen React. Using Docker Compose, you can instantly spin up an environment to run Twenty Sixteen React, or develop another theme or plugin with NodeifyWP.
I will be debuting a full demo of NodeifyWP at WordCamp Denpasar on November 19, 2016.
Contributions are welcome, and we’d love to see—and share—any applications you build with this framework.
Mark Lovett on
Looking forward to seeing the demo, Taylor. App-like experiences are a lot more interesting but it sure does sound complex to build. Way over my head!
Bhargav on
This is coolllll…..
Ahmed Kaludi on
This is so cool! Can you set up an online demo of it? It would be amazing to see it.
I’ll be going through this in the weekend.
Taylor Lovett on
We will probably set up a demo at some point. However, the server side code is what’s really interesting as well as the fully functional customizer, previews, menu manager, etc.
Ahmad Awais on
Hey, Taylor!
This is incredibly interesting; I can’t wait to dig into the code and maybe help contribute towards WP-app like examples. Thanks for open sourcing.
Taylor Lovett on
Would love to get your feedback after you dig in!
Jason on
You left out a better 4th option… Instead of passing the PHP generated WP context off to V8JS, just return that as a json encoded string and access that context over HTTP.
I cede to you the fact that the current WP API is misguided in that it doesn’t account for the data mutations that take place in WP Template Tags through plugins, et al. But trying to render a javascript application in a php process is not a good idea and rabbit hole you should probably try and avoid.
Your current solution prevents the application from being a SPA and only further slows down your php execution time. Nodejs is always going to be better supported, maintained and documented then the V8JS PHP extension.
You should just have WP be a backing service that distributes the WP context you created as JSON over HTTP. But cheers to the generated WP context! Looks great.
pd on
Hey Jason,
Interfacing with WP over pure JSON is ideal, but also requires a more complex server configuration. UsTwo has a nice illustration of their server config, but it’s not for the faint of heart!
A CDN could certainly go in front of the JSON responses with this solution; the advantage I see in V8 is how quickly legacy PHP code can be ported to serve over JSON.
In addition to the performance improvements provided by React, I was excited to find V8 is performant as well. According to this article, Google has put much work into performance. Because V8 compiles JavaScript to assembly code, it benchmarks faster than PHP, Ruby, and Python. Never mind that a CDN can cache the JSON responses as well!
This is great work, Taylor. I’ve not seen other WP/React solutions come close to this in simplicity or feature set. Thank you for sharing your knowledge.
Jason on
Hey PD!
If you want PHP to be able to evaluate a string of javascript, then you should just do it like this:
“`php
‘bar’)));
“`
“`javascript
// test.js
console.log(process.argv);
“`
My point is simple and has nothing to do with servers.
There is a layer of code that sits between your code base and the V8 engine. Whether that code is Nodejs, phpv8js, or even something like Phantomjs, there are slight nuances to how each of them handle that communication.
Nodejs is:
1. Better supported, maintained and documented
2. Most likely already in use building assets
3. Most likely more familiar to the developer (especially ones using redux and functional composition)
PHPV8JS is:
1. More challenging to set up. (the author provides a Docker Image “Because V8Js and Google V8 can be challenging to set up”)
2. Fewer maintainers, fewer documentation, fewer community support. (What looks like 1 maintainer?)
3. Has slight nuances and a slightly different API you have to account for
Why would you want to rely on PHPV8JS instead of using the tried and true Nodejs?
Jason on
// test.php
‘bar’)));
// test.js
console.log(process.argv);
Jason on
https://gist.github.com/jbenesch/bc0c03e7544e89ab2e932b187e9d1e59
Taylor Lovett on
Hey Jason, a few comments
1. Twenty Sixteen React, built with NodefiyWP, is most definitely a SPA.
2. See benchmarks for performance. I don’t think you understand what V8Js is – it connects PHP to V8 which is extremely performant.
3. The JSON option would require something like an Express server and seems extremely messy to me.
Give NodeifyWP a try :)
Carl Alberto on
This is interesting, will be waiting to see this on WordPress.tv
Nicola Peluchetti on
I think that point 1 ( Create a traditional PHP-based theme with a client side layer…) would be much simpler to handle if you choose a templating language which can be run both on the server and on the client, like Twig or Mustache. In that way you don’t have to rewrite templates, you can render both on the server and the client. Of course some complexity remains, as you will need two routers, one on the client and one on the server.
Bernie Reiter on
First of all, it’s great that there’s finally a project that allows writing WordPress Themes in React isomorphically!
I can appreciate the rationale for
PHP.context
, but I still disagree with some of it :-) I’ve recently worked on client-side apps mainly, so my angle on data fetching is a bit different. Calypso started as a purely client-side app, so we were relying on our (WP.com) REST API for data fetching; when we added server-side rendering, we continued to do so, even on the (node) server side (just with an extra layer of caching).It seems a bit inefficient to fetch everything from the server on every click inside the app, and I imagine it won’t scale too well. Furthermore, exposing stuff like posts through a custom WP-API endpoint feels redundant when there’s a core one for that.
My reading of NodeifyWP is that it’s presently taking care of two concerns: plainly being able to run JS on the server side (from within WP), and providing that app with data. For the latter, I’d suggest using the REST API instead; on the client, this would mean using
wpapi
. To work isomorphically on the server, I’d tackle the problem at Redux level: Have a theme’s individual React componentsconnect
to Redux state; usePHP.context
only as initial Redux state; and produce that context on the PHP side as a snapshot of basically all WP-API endpoints (and have it become part of the V8Js snapshot). (The extra requirement of registering stuff to expose viaPHP.context
would also be made obsolete; the REST API would become the only interface.)I think it’s conceivable to put those two concerns into separate WP plugins: one for snapshotting the initial state from REST API endpoints into
PHP.context
, and one just for integrating V8Js with WP. With a well-defined interface, this could allow dropping in alternatives to V8Js, such as a plugin that passes the server-side JS and initial state to a local node installation instead.