How a ‘toolbox’ can streamline web development
… and what should not be encapsulated within your web app’s repository!
In the early stages of Medipass, we were in the middle of deploying web applications for three discrete personas. Our method of project repository organisation was killing our productivity, pretty much copy-and-pasting/using a boilerplate from project to project, which was a pretty big problem for us as it took us days to set up a project.
We were copying-and-pasting stuff like: build config, React components, tooling, styling, ESLint config and more.
We ended up devising a new technique to solve for this problem, which converted our web project setup time from 2 days to less than 1 hour.
What should not be in your web app’s repository
Here are some things that should not reside in your web app’s repository:
- Build config,
- Shared React components,
- Shared tooling,
- Shared styling,
- Pretty much anything shared…
Let me explain:
1. Build config
Configuring your build tools (such as Webpack) should not get in the way of getting started on developing a web app of any scale, nor should your build config be modified if it is set up properly from the start. I feel that Webpack can be a pretty steep learning curve for developers, and it can be hard to get it working the way you want it to. There are plenty of state-of-the-art webpack conventions (such as the Webpack config in create-react-app) that could be used instead. If you have the time, you can most definitely create your own build config, publish it as a public/private NPM package and import it into your project.
But if you are building a new web app and really can’t be bothered (like me) setting up your build config, I’d advise using create-react-app (which already has the build config encapsulated).
However, if you already have an existing project, I would recommend getting inspiration off the react-boilerplate Webpack config and publish your build config to an NPM module.
2. Shared React components
Shared organisation React components such as common buttons, modals, form fields, tables, layouts and other common project specific components should not reside within your app’s repository. If you’re finding yourself copy-and-pasting components between projects, or think a component would be used across several projects I would suggest putting all these common components within an NPM module. To easily develop, test and document your new shared components in isolation from your projects, I would recommend using Storybook or React Styleguidist. At Medipass, we thought React Styleguidist worked best for us since it provides not only a development environment for your components, but also an excellent styleguide.
3. Shared tooling
Shared organisation tooling such as your company’s web-based SDK, common form validation, common environment variables and common helpers should not be in your repository. I would suggest also putting these in an NPM module. At Medipass, we have a web SDK which is our bridge between our API’s and web apps and is in its own ‘@medipass/medipass-web-sdk’ module — whereas all of our other tooling is in another ‘@medipass/medipass-utils’ module.
4. Shared styling
Shared organisation styles (whether it be CSS or some CSS pre-processor) should not be in your repository. My recommendation would be to use a CSS pre-processor (like SASS) to generate stylesheets for each of your components and stylesheets for typography, helpers, and so on. All these styles can also be published as an NPM module and imported within your React components and project. To document these styles, I’d recommend (if you have the time) to make a styleguide for your organisation. If you can’t be bothered developing your own styleguide, a pretty good generator is https://holidaypirates.github.io/nucleus/.
5. And others
And there is so much more that can be isolated such as: ESLint config, CI scripts, etc.
To reduce overhead
You can do two things to reduce overhead for shared stuff in your web app:
- Use create-react-app
- Create a toolbox
Let me explain:
I briefly mentioned create-react-app above, but I definitely recommend using it for any type of React project (small or large scale), because it already comes with awesome build configuration that you don’t need to worry about.
Create a toolbox
Creating a toolbox using Lerna
Here are the steps to set up a toolbox using Lerna:
- Actually understand how Lerna works (pretty straightforward),
- Initialise a toolbox -
- Add your packages -
- Bootstrap your packages -
- Publish your packages -
What is Lerna?
Lerna is a tool for managing projects with multiple packages and extends on the idea of a monolithic repository (a mono-repo). At first, you may be like “omg wtf monolithic? that word makes me sick.” But actually, in my opinion, I think mono-repos for shared organisation web assets is a really smart idea. If your shared packages depend on each other, making changes across these packages can get really messy and hard to track. You have to remember what package depends on what and ensure everything is up to date. Lerna basically splits up your mono-repo into versioned packages (NPM modules), and manages installing/symlinking package dependencies and publishing your packages to NPM and Git.
Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.
Here are some examples of some organisations using Lerna:
Initialising a Lerna toolbox
So you’re like “cool, this sounds dope AF, how do I make a ‘lerna’ mono-repo??”. Well all you need to do is install lerna globally, make a directory for your toolbox, and initialise lerna within it.
Once initialised, you will find a ‘package.json’ file, ‘lerna.json’ file and a ‘packages/’ directory in your project. Lerna also handles initialising a local Git repository for you. But don’t be confused by the ‘package.json’ file as it will not publish the root to NPM — only its packages.
Adding a package
Okay, so we’ve initialised a Lerna ‘toolbox’ and we are ready to add a package! Adding a package is also pretty simple, just make a directory and initialise a package!
The two main functionalities in Lerna is the idea of ‘bootstrap’ing and ‘publish’ing your packages. Before you publish your packages to NPM, you want to ‘bootstrap’ them first. The idea of
lerna bootstrap is that it will install all of your packages’ dependencies and also link cross-dependencies (symlinking). Read more about it here.
When you are ready to publish your packages to NPM, run
lerna publish . This command will publish all the packages which have changed, and ask you what version you want to bump the packages to.
At Medipass, we have a single Lerna toolbox called ‘Medicules’ which manages all of our front-end assets. Within our
packages/ folder, we have:
@medipass/react-componentspackage which encapsulates all of our shared React components and React styleguide,
@medipass/styleguidepackage which encapsulates our web styleguide,
@medipass/utilspackage which stores all of our shared tooling (such as form validation, google maps tools, intercom tools, environment variables and helpers),
@medipass/web-sdkpackage which is the bridge between the Medipass platform and web app (manages user data and API calls),
@medipass/eslint-config-medipasspackage which has all of our ESLint config.
In my opinion, creating a toolbox for Medipass was a great decision. I can’t wait to build it up and allow other developers to easily work from it. We are also starting to create a Lerna toolbox for our platform as well (currently using it to manage our web app and API versioning). I think the idea of creating a ‘toolbox’ for managing an organisation’s shared front-end assets should definitely be a standard in the near future. Please give it a go! If you would like to discuss this post further, feel free to mention me on Twitter @jxom_!
Ok, so who am I and what do I do?
I’m Jake and I’m a software engineer at Medipass, mainly focusing on front-end web development. Earlier in the week, I presented ‘Unifying Modern Web Apps’ to our team and how Medipass managed their shared assets (build config, React components, styling, tooling, etc) between multiple web apps, and I thought I would translate those presentation slides into a blog post. This is the first tech post by Medipass, and also the first tech post from myself, so I hope you enjoyed it and found it beneficial in some aspect!
I wanted to give background on how I gained the motivation to write this post. The Medipass front-end tech ecosystem depends heavily on the React library. Upon early development of the initial Medipass practitioner web app in late 2015; all of its build config, API ‘bridges’, React components, styling and tooling were encapsulated in the one repository. The whole aim of the practitioner web app was for it to be ‘a lightweight claiming web app’ which had the main responsibility of creating claims for patients. At the time, encapsulating all of our stuff in the one app wasn’t necessarily a bad thing, but we knew we would need to rethink the approach when we extended to having multiple web apps that connect not just providers, but patients and funders also.
After the practitioner web app, along came other web apps which had the responsibility of: handling Medipass account invites/resets, enabling health funds to view their Medipass transaction and member insights, enabling Medipass members to view their quotes on an online web experience, and quite a few more.
At this point, we could not just simply ‘copy and paste’ all of our shared assets from app-to-app; we had to devise a method to effectively and efficiently share all of our shared assets between our web apps.