Skip to main content

Open sourcing Contensis React Base

Wednesday, 8 December 2021
NFContensis
Neil FlatleySolutions architect
News and announcements7 min

TL;DR [too long; didn't read] 🤯

The main thing you can take away from this article is that we recommend you always keep @zengenti/contensis-react-base package up to date in your web app.

Today we're open sourcing our Contensis React Base package. Developed over several years of working on enterprise React apps, it's designed to cut the time and effort required to set up and build complex websites. Read on to learn more about what it's for, where it came from, how you can use it and how to contribute to the project.

If you’re a developer new to JavaScript, or an experienced developer starting out with React, you’ll soon find out that most of the information out there isn’t about how to write your application, but more about all the hoops we have to jump through to set up different areas of a project and get up and running.

This snowballs into a mind-bending myriad of development tools, project features, build tools, and bundler plug-ins to configure – all shrouded in unfamiliar jargon and an ever growing list of “npm packages” to understand and keep updated. You may have experimented with some code in another project, but found you spent more time fixing errors or struggling with syntax than actually writing your app. There are probably some things you wish you knew more about before embarking on a serious project.

On the other hand, if you’re an experienced React developer, your project may require a sophisticated arsenal of features that extend beyond rendering some JSX in a browser. Sourcing or maintaining your own project starter that contains everything you need is like keeping a fermented old yeast dough or making a classic spice paste – it’s great, but it is a lot of extra work and will eventually become stale unless it is continually maintained.

So, do you go with one of the well established “create-react-app”, “nodejs starter”, or “react boilerplate” routes, which are well supported and maintained, but can later prove restrictive or complicated to build up and scale out? Or do you go with a niche GitHub repo you’ve found that appears to have most of the application ecosystem that you need, but with zero following or support?

Time, effort, repeat.

Whichever path you take, all of this takes time. Lots of time – and perhaps a little obsessive tenacity – even for the most experienced developers, this process is arduous. In a constantly evolving blend of discrete concepts and methodologies, many developers would welcome opportunities to shortcut some of that time and energy-sapping “project setup”, while still keeping up-to-date and in line with security patches, new features and community best practices.

Sourcing or maintaining your own project starter that contains everything you need is like keeping a fermented old yeast dough or making a classic spice paste – it’s great, but it is a lot of extra work and will eventually become stale unless it is continually maintained.

For us here at Zengenti, most of our customers are primarily focused on delivering websites using Contensis. We help our clients meet their organisational needs with content modelling and this content is later translated into component design. The information architecture – or menu structure to a heathen like me – is constructed separately from content in Contensis using Site View, and all of this data is available via the Contensis Delivery API. If you’re looking to achieve similar goals, this is how we build websites with Contensis.

The base package

To build this typical website behaviour inside a modern JavaScript app we need to fire an action each time the route (browser address) changes. When it does, we either need to match and render a “static route” defined in the app, or send a request to the Delivery API to see if a node exists in site view with an attached content entry at that route. For example a request for “/” might return a “home” content type entry, or “/about-us” might return a “content page” entry. Then, we need to decide exactly what to render if a node is or isn’t found, or even if the API is not available. We call this process “routing”.

It doesn’t sound that difficult to implement in your own app, but what happens when the application grows? What happens when we need to introduce things like:

  • 10 different content types, each with different link depths and field limitations
  • Handling parameterised routes for searching or activating different parts of a page
  • Fetching node ancestors for breadcrumb data, siblings for side navigation, or an entire site tree to build site navigation
  • Requiring authentication for certain content
  • Hooking into a development CMS or read data from another CMS project
  • Writing page cache invalidation headers or custom response handlers

As the requirements increase, so too does the amount of code we have to write, test, and maintain. More code inevitably means more complexity, and this becomes a barrier to easily making changes in the future.

The aim of Contensis React Base is to provide the complex base features and boilerplate concepts so we can offer an easy and reusable way of hosting and rendering our isomorphic React applications.

As well as dynamic routing, for the best experience while hosting and scaling up your modern JavaScript web application you will likely want server-side rendering (SSR), global state management with Redux, code splitting, and the ability to load dynamic components so you don’t ship the kitchen sink with your bundles. Add to this the building of differential bundles to ensure modern browsers get the best performance with smaller bundles while still supporting legacy browsers by serving alternative bundles. And what if you need a clean way to define your different environments and then build targeted server start scripts to be able to start your application connected to any environment? You might even need to write and host your own REST APIs to serve specific integration requirements, or pop in a reverse proxy to prevent CORS errors when consuming resources from elsewhere.

Supporting all of those features requires us to invest time in helping ourselves by putting good development tools in place such as implementing adequate debugging facilities for both server and browser contexts, automated tests to prevent us deploying a bad build, automatic code linting to ensure consistent and readable code…I could go on.

You may need more than one application like this to serve your entire organisation, so you’ll have to copy this code into each application you write, duplicating all that technical debt for each copy that has been made.

The package manages the installation of key production dependencies, a server-side Express application serving an isomorphic web app, handles client-side rendering and hydration, global state management for core features, automatic routing, retrieval of navigation data and server-side cache key generation, ensuring instant cache invalidation when content is updated.

The trouble with duplicated code like this is that it’s frozen in time – remaining exactly the same until someone copies and pastes an updated version of it, despite receiving numerous CMS upgrades in the interim. Or, more often, it gets tweaked over time and mutated to the point it can never be updated and must be painstakingly tweaked again and again forevermore.

We started out our journey with JavaScript and React by writing our apps in this way, and with the combination of over three years’ worth of use and testing this approach and standards implemented, we have grown, evolved and refined the very code that underpins all of our modern web apps for 100s of sites, probably 1000s of hosted containers.

We realised very early on that we needed to capture and package this code to prevent the exponential technical overhead that would be incurred with each copy of these “base” features we took to use elsewhere. We don’t need to reinvent the wheel with every application we write.

And that’s where the package formerly known as zengenti-isomorphic-base was born. We trialled this internally for quite some time and, with some steering from our technology guild, it eventually evolved into what we now call Contensis React Base.

The aim of Contensis React Base is to provide the complex base features and boilerplate concepts so we can offer an easy and reusable way of hosting and rendering our isomorphic React applications. It provides the ability to scale them out to cover more areas of an organisation’s digital strategy or web estate, while incurring the minimum amount of technical debt. And, at the same time, gives us the ability to govern the code that underpins the core of our applications, make improvements and roll out updates so we can grow in parallel with Contensis and the wider community with the minimum of effort.

The package manages:

  • the installation of production dependencies including React, react-router-dom, immutable, and react-redux
  • a server-side Express application which serves an isomorphic web app
  • a client-side sub-package that handles client-side rendering and hydration
  • the creation of Redux store and global state management for core features
  • automatic routing via RouteLoader component which will load entries based on a given URL
  • automatically retrieving navigation data from the Node API to load the Site View into the state
  • automatic cache key generation for any entries and nodes the core app handles, ensuring instant cache invalidation when content is updated

So it's now open source?

We are proud of the product that we’ve created. We use it ourselves to build and host modern web applications in React and JavaScript on a daily basis.

Many of our customers are developers themselves, and as a developer if you are trying to achieve something a little quirky, or follow an unfamiliar path, it can be frustrating if you feel you are working inside a black box. Or, as time goes on, you find yourself looking to exploit or expand certain areas of configuration to use functionality nobody else has needed before.

This is JavaScript after all. It does not compile the source code – it only transpiles. We are hosting our package on npmjs.com and it can be found on their website. It’s available for anybody to use. The transpiled source code is always visible and debuggable (inside node_modules).

With all of that we would welcome input from our users who have found new or better ways of solving common problems and we would be pleased to review a pull request for a fix made to our source code, for example.

Notice how I have said “our” source code - if you’re reading on this far that also includes you!

We would like to officially announce Contensis React Base is officially available on GitHub, it is listed publicly and is the source of truth.

Feel free to clone or fork the repository, have a play and a poke about!

I’m just a normal developer

OK so you might not be that guy, Forky McCloner, a typical 2am open-source contributor.

If your project uses the @zengenti/contensis-react-base package, we strongly urge you to keep this package up to date. We follow semantic versioning, so you can be sure it is safe to upgrade to the latest version. Major version updates will always include one breaking change and you should always check the release notes to understand if that change affects you. We'll keep the Contensis community updated with any such announcements.

The npm page is where you can see all the different versions, view the readme and the GitHub page is where you will find the source code and commit history, the same as every other GitHub project

If you are running on a beta version of the package, you should check to see if that beta version has been succeeded by a version with the latest tag and install that.

We stage all of our changes in npm by publishing a new beta version with every commit to GitHub. Each change is automatically built and published to npm with a prerelease tag through GitHub Actions CI, and you can install the last beta version in your project for testing new unreleased fixes and features by running:

npm i @zengenti/contensis-react-base@prerelease

If your project is running on a beta version and that has been superseded by a greater version number published with the latest tag, you should get back onto the release path - a foolproof way to do this is to install it again:

npm i @zengenti/contensis-react-base@latest

TL;DR

Keep @zengenti/contensis-react-base package up to date!

Important links

Contensis React Base on npmjs

Check the latest version, view the package README and see all published versions.

https://www.npmjs.com/@zengenti/contensis-react-base

Contensis React Base on GitHub

View the source code and commit history and contribute by making a pull request.

https://github.com/zengenti/contensis-react-base

Get in touch

Thanks for reading and consider joining our Contensis Slack community, where you can reach out if you have any specific questions or just to keep up to date with the latest community announcements and event invites.

Join our Slack community
Necessary Cookies
These cookies are necessary for this website to function correctly. They are set when you perform certain actions on the site, such as creating an account, logging in, changing your privacy preferences or submitting a form. You can block these cookies in your browser, but this will stop parts of the site from working properly.
Functional Cookies
These cookies allow the website to provide extra functionality and more personalised experiences. They may be set by us or by third party providers whose services we have added to our pages. If you choose not to allow these cookies, these services may not work correctly.
Analytical Cookies
These cookies record anonymous data on how visitors use our website to help us monitor how well our website works. This data includes how many people have looked at specific pages, how long visitors stay on the site, and what devices they use. We use this data to identify changes that we could make to improve your experience and make our website more efficient.
Marketing Cookies
We set some cookies so you are shown more relevant marketing content. These include cookies from third-party advertising networks to show you different adverts on their services if you have previously visited our site. If you choose not to allow these cookies, you may experience less relevant advertising on other sites.