This article is inspired by the amazing experience of using modern JavaScript ecosystem tooling to re-implement the Kernelics website for marketing and hiring purposes. Kernelics is a company that creates remote software development centers for startups.
When the company started in the first quarter of 2020, we were really busy making new business connections and working with sales agents to attract new clients.
Marketing was not something we focused on, and the website was just a “nice-to-have” thing. We were just thinking like: “Huh, this is strange for a software development company not to have a website”.
The decision was to outsource website development to our partners who are extremely experienced in the WordPress ecosystem.
After almost 2 months of traditional development workflow, we’ve got the first corporate website version rolled out, and we were happy with the quality from UX and content management aspects.
This was really great to make small changes in the admin panel and get a new content-rich page, without any development activities at all.
It was a satisfying approach for the company’s first year. Then we’ve started to experience real problems:
- There were UI/UX issues for several types of content. A typical thing when designers and developers don’t handle edge cases.
- It was hard to extend the website with new features and pages. If you’re familiar with WordPress development, then you are familiar with its template system. You should deal with a mix of HTML and PHP. In our case, we’ve additionally had some Vue.js mixins for interactive parts like sliders, forms, etc. So, the code was really hard to manage.
- Our focus moved to the JavaScript ecosystem organically, as the result of company growth and business development. PHP and WordPress were totally not our target technologies. It means that we need to be supported by initial developers, some other company, or a contractor. Any of these options was not advantageous for us, because of the high prices for such kind of support. Moreover, we were confused about the fact of having a lot of JavaScript-engineering capacity, which could be potentially able to help with the website, and not having anyone with the website stack in-house.
- Website UI became outdated.
- With the company’s growth, we’ve started to think about common development practices and reusable solutions in our stack.
- Sales and marketing departments were initiated. A corporate website is one of their work channels. We’ve accumulated a lot of changes requests in our backlog.
One day, we’ve made a radical decision to completely re-implement our website using a modern stack to serve the real company needs.
And here we go with our experience of it.
Frontend
We chose React because it is the key frontend focus of our company. Is this enough to just use CRA and start the development? Well, if you develop a website for any marketing or sales purposes, you need it to meet at least these requirements:
- It should be fast. “Fast” could mean anything, but you can rely on common parameters like Google Lighthouse scoring metrics.
- It should be customizable. Your marketing department will constantly demand more and more changes. From adding another text line to run A/B tests during a marketing campaign.
- It should support SEO for each page.
- A content part must be backed by a content management system. This is not a preference. You don’t want any content changes to cost as much as development.
How can you deal with all of these? Well, you can achieve it even using an old plain CRA. This is good for tiny websites. But for projects of a larger scale, you will face a lot of issues, from making a lot of optimizations to handling SEO support.
If you ask yourself, what page is the fastest one, you will come to the ridiculous answer — a plain HTML + CSS webpage, which already contains all the structure and styles to be rendered.
But wait, when using a traditional React approach, your virtual DOM will be transformed and rendered to a browser DOM on every page load, using the computational power of your device.
It means that you have an additional set of heavy tasks, which the browser should fulfill before a user gets a UI.
And the frontend world has a great answer to this question. Use server-side rendering! With server-side rendering, your React components are being transformed to an HTML and CSS slicing before they are sent to the client. For your browser, it is the same as getting just a static markup, which is really fast to process and display.
You can make your own implementation of SSR using a simple Node.js server and ReactDOMServer from the react-dom package.
The approach of using server-side rendering and statically generated websites has grown into a new architecture called Jamstack. You can read more about it on these two websites: Jamstack and JAMstack WTF.
The true power of Jamstack is revealed in the existing frameworks, such as Next.js, Gatsby, Nuxt, and a lot more, combined with platforms supporting them natively: Vercel, Netlify, AWS Amplify, and others.
Coming back to our case, we’ve decided to move with the following stack:
- Next.js with TypeScript;
- SCSS as the styles preprocessor;
- Styleguidist to document components;
- Vercel to develop, preview and ship our application.
Backend
Before making a 180-rotation on the backend side, we’ve tried to get as much as possible from our existing WordPress admin panel.
We’ve experimented with both REST, which is supported out-of-the-box, and GraphQL, which requires more hustling around to make it work.
REST has resulted in a kind of good option, but the preference was to use GraphQL with all its benefits.
The problem appeared to be in our complex entity data structure. Almost everything was built using Advanced Custom Fields, which WP GraphQL plugins seemed to be loosely supporting.
The whole experiment with an existing admin panel has resulted to:
- REST was working okay, but we didn’t want to get that meta-information waste in each response;
- GraphQL, which was preferable, was failed to configure and use.
Moreover, the following circumstances brought us to another round of thinking:
- Making changes to data scheme requires a good amount of time, even with the usage of Advanced Custom Fields;
- We were constantly getting negative feedback from potential content managers about the current admin panel UX — it was absolutely not intuitive and required a lot of time to learn;
- We have had just one instance of WordPress running for a production website and no instructions on how to deploy it to another environment.
The decision was to re-implement the admin panel with a tool written in Node.js instead of PHP. That would be more aligned with our current stack focus and easier to change and extend in the future.
After short research for proven solutions and best practices within Jamtstack, we’ve figured out that Strapi and Directus are the best headless CMS to choose between.
Both have their pros and cons, but Strapi has the following advantages, particularly for our case:
- It is a trustworthy player on the market with regular updates;
- Has a large community, which is actually developing a lot of extensions;
- Supports a number of storage providers;
- Provides an amazing experience of designing entities and getting ready-to-use REST & GraphQL APIs for them. Available even to non-technical people. With no development skills needed at all.
Infrastructure and development approach
We still needed to decide on a cloud platform for running admin panel instances and a file API supported by Strapi.
Choosing between all the offers on the market we stopped on:
- Heroku to handle development environment — both application and database instances. In the majority of cases the hobby plan, which costs 0$/month will be enough. Remember, that Heroku hibernates applications, which have no active traffic for 30 minutes. To resolve this issue, use this tool;
- Render to handle production environment;
- Cloudinary as file API and CDN compatible with Strapi.
We’ve created 3 frontend application environments — DEV, DEMO, and PRODUCTION with their own unique domains, to make QA life easier.
DEV environment is connected to the development admin panel instance on Heroku.
DEMO and PRODUCTION environments are both connected to the production admin panel instance on Render.
Both Next.js frontend and Strapi backend use a git-flow-like pipeline. Each environment has its own epic branch in Git — develop, demo, and main in the frontend; develop and main in the backend.
Vercel supports the atomic deploys model — that means we have a unique version of Next.js app for each commit. It makes it possible to review PR by checking the code in action directly just by the link attached by Vercel automatically.
For the admin panel, we’ve enabled automatic deploys from develop and main branches on each push.
As the result, we have perfectly working continuous delivery with almost zero time spent on configuration, allowing us to focus on development.
Result
We finally have a new, fast, and easily customizable website.
Our marketing team has already requested several new versions of it, and we’ve successfully made them, even with different development team compositions.
I hope this article will be helpful if you are a fan of the JS ecosystem and want to build a modern Jamstack application!
Vladimir Levenko, Co-Founder & CTO at Kernelics.