Recently, I worked on react-config-form, a lightweight npm package for creating forms in React just with a config object. I wrote about it on a twitter thread as well. This being my first npm package, I have learnt a lot in the process of creating the package, publishing it and writing the documentations for it. I'll share my lessons here in this blog, as well as some utility tools for publishing and creating npm packages:
Learning the DX first principle
When you're working on creating a tool for developers, the developer experience (DX) is obviously the first-priority. For me, this was a change of perspective. I now had to constantly think from a fellow developer perspective about the tool, and what feature should be higher in the priority order. Let's say I'm thinking of adding x feature to the package. I'd ask myself a few questions like these:
- Will x feature make for easy integration with projects?
- Will x need any external dependency?
.. and so on.
A few examples about my DX first principle thinking while working on react-config-form:
To help developers write minimal code for forms, I tried to keep mandatory properties to the minimum in the config. One needs two or three minimum properties - the type, the initialValue and the label, to configure a form element.
To an addition, I added some opt-in default styles for forms so the form still looks fine without the developer having to write any styles for a form.
I decided for/against these features just by acting on a DX first principle and asking myself repeatedly about how a certain feature or the way how a certain thing works would make the developer feel while working with the package.
I had to consider a lot of trade-offs along the way for building an npm package. There are multiple ways to achieve similar things when building a feature or tool, and I had to decide against one for the other. For example, should forms come with a default style or not? How easy should it be for the developer to override the default styles, in case a form has some? etc. Again, my thought process for making trade-offs was oriented around the same developer experience thinking.
Would a fellow developer like it x way more, or the y way?
Would it be easier for a developer to integrate with this feature in x or y way?
... and so on.
Few examples about the trade-offs I had to make:
- Whether to inject the built-in styles for the forms by default or make it an opt-in feature. Initially, I injected the styles by default only to realise this makes style customization (overriding the basic styles) hard for a developer. (Basically, one would have to mark all overriding styles as !important to make it work). That's why I removed the default injection for basic styles and made it an opt-in feature (one can import the styles with a css file).
These trade-offs are similar to the DX first approach in the sense that it goes back to choosing the approach keeping the DX in mind. I chose the approach which I thought makes for a better DX.
I know these examples are very specific, but I hope it would help you understand the approach and thought process behind making these choices.
I think as we progress more in our career, the more trade-offs we would have to make and the better we'd get at it!
Writing a useful documentation
I'm a fan of great documentations. I think we learn more about something ourselves when we try to express it in an easier way for others (by writing). Writing the documentation for something I created was a great learning experience for me. I think I became a better writer in the process.
Here are some utility tools for writing docs:
Nextra: If you're building a documentation website in Next.js, Nextra is a great built-in solution that comes with useful features. However, I went with building things from scratch because I wanted to built the functionalities myself.
MDX: MDX is a great way to write markdown in React. I'm currently working on a docs website for react-config-form, built using MDX.
While I was working on publishing the package with the types, I faced difficulties around:
- exporting both the components and the types from the package.
- automating the process of publishing the updated package version to the npm registry
- handling semantic versioning of the package etc.
I found some utility tools for getting around those issues. These tools are very helpful for creating and publishing packages:
TSDX: A great CLI tool to create packages with TypeScript. Comes with a bunch of useful configurations built-in.
semver: An npm package for integration with the semantic versioning system which automates the process of updating the semantic version of your package as you push updates depending on the commit message(s). It follows the angular commit message convention. This helped me learn more about the best practices for writing better commit messages.
Publish automation (CI/CD pipelines): CI/CD stands for continuous integration and continuous delivery. I learnt more about writing yamls and how to automate the process of publishing a package to the npm registry whenever pushing code to a certain branch of the git repository. This video from Bruno was very helpful for working on and understanding this, particularly.
It would be great to know and learn about your lessons from working on developer tooling.
Until next time! 👋🏼
Did you find this article valuable?
Support Sreejit De by becoming a sponsor. Any amount is appreciated!