So you built a component library. Congrats! I am sure it is awesome but did you put the same effort into its documentation? Component libraries tend to have giant APIs, dozens of components, hundreds of props and thousands of permutations. That is a lot of information to unpack.
We could make the documentation very long or... super interactive. We combined component previews, API documentation, props editing and code editing into a single seamless experience. You can quickly explore various settings of each component while watching the code write itself.
This talk will show you how to leverage common tools and concepts such as Prettier, babel and AST transformations to build the documentation that can literally work for you.
Slides - https://docs.google.com/presentation/d/1eniROQoSzMWax1sliB9s_TMgKwn84xXfSXow1sJXesM/edit?usp=sharing
Hello, my name is Vojtech Miksu, and today I am going to talk about documentation. My job is building react component library called Base Web and other tools at the base of our business, implementation of our design system. And we use it across all applications. So let's talk about documentation. It's something that most of us use every single day, and it's absolutely essential. Every day we are sitting at our desks trying to learn things by reading. And only sometimes we pause to write a few lines of code. And there are many different sources of documentation. We have books at the end stack, overflow comments in the code, or we just randomly Google things until we give up and select our colleagues. But what is my real motivation to talk about this today? I joined the company three years ago and this was the proposition given to me. Join us. You'll be building with components that sounded amazing. And I was immediately sold. However, the reality of platform oriented work is slightly different, it looks more like this chart. And frankly, it's a good thing if nobody uses your things, it means if nobody asks you questions, it means nobody uses your stuff and that would be awful. So you could say my team became a victim of its own success. When we started base two years ago, it was barely used and we had a lot of time to just write code. But then the usage spiked. There is now over 600 applications just in Uber, and that translates into almost like a thousand developers. Also, our library has a giant API surface. There are over 60 components and hundreds of props and pretty much endless possibilities. We also have a lot of outside contributors and users, so naturally we spend a lot of time and support. The question was, can we reclaim some of this time back? I strongly believe that if we built an amazing documentation, we can significantly reduce the number of questions in our chat and GitHub issues. Um, also we do frequent surveys, um, and documentation is always the most mentioned topic. So my team now invests a lot of time into experimenting with different kinds of documentation. Hopefully by now I made my case for why the documentation is so important. Here's the agenda for the Thuc. I'll show you some some older versions of our documentation website and explain why it wasn't good enough. Then what we built with reactor view and use today, I'm also going to peek under the hood and show you some concepts and code related to compilers and abstract syntax, threes. And finally, conclusion. So this is the this is the oldest version of our documentation. It's just storybook, it's off the shelf solution. We used it to develop our components, but also to document them. You can see it's pretty much a bunch of examples. And at the bottom, you can see read me there, we document our props. But as we grew the number of components, we wanted to have something more structured and customized. So we launched our own custom website based on next year and MDX now, components are in different categories. The page itself is more structured. Each example has its own source code, that manual everything. And at the bottom, we have documentation generated based on static types. And this works reasonably well up until it just doesn't. Some static types are just too complicated and not really human readable, also, many props are meant to be used internally only when composed by other components, but now we expose them in the public API and that's just confusing. We tries to tweak this many, many times, but it was never, never reliable and not sufficient as the primary source of documentation. Developers can always tell when something is auto generated and they will not exactly love it. Why should they put extra effort into reading it if you put zero effort into creating a. So how about adding a lot of examples, who doesn't like more examples? This is our tech component. It's pretty simple, and yet there are three hundred eighty four different permutations of it. Me display three hundred eighty four examples on a single page. Sure. Is it going to be overwhelming? Absolutely. And the same thing goes for other components. If there is a limited number of examples we can present, do not overwhelm our users, what else we can do? Well, let them toggle and explore these permutations. Let me show what we built. So this is like a playground we built for our components, first of all, we want to display the component itself. Second most important part is probably the source code itself. Um, the nice thing about the source code is you can edit it in real time. And as you type it, like changes the component, if you make a syntax error, we just tell you what's wrong. We also added this this feature where you can hover over different components and see their static types. So this is pretty common feature on a lot of documentation's. But have you ever ask, like, how this actually works in your browser? There is a useful API for creating JavaScript functions from String's, the first argument are parameters of the new function, followed by the body, unlike evol function. This is executed with a global scope only. So and if you want to pass and use in this function, you need to pass as an argument. So now we can dynamically execute any JavaScript from string. But what if he does the only one to blame JavaScript? And actually, we almost never do all of our interviews sex, and you probably saw what happens if you try to run a sex in your browser, you get this syntax error, unexpected token. We can really ask people to type great element instead of jail sex, so we need to introduce some extra step, some extra process. We need to add a compiler. Remember, Babul, most of us use it when we need to compile or applications, but we can also use it in our browser to compile our sex into reintegrates element. We use transform function from Babacar. You load up, react Brisset, we pass it out component and it turns out it returns the react great element instead. So this works pretty good. So now you have the component, we have interactive source code. Let me also added some convenient functions. For example, the developers like to format their code so it's more readable before they copy paste it. You can copy that growth into clipboards. You can get a permanent link. You can get back into the initial state and you can also spin up code sandbox and do even more serious editing if you wish. So this is great, but sometimes you don't even know what other perhaps you can use for this component, so you need some sort of API or perhaps documentation. So we added this additional part. We called Knapp's. So each prop is represented by a single knob and you can also interact with it. So as I change, the smellier you can see it updates the component itself. But most importantly, it also update the source code so this state is synchronized across all all of these free parts and it gets even better. For example, if I change the sky and do secondary, you can see it even change the import. So this is like something you can always copy paste into your application and you get this exact component in this exact state. So not only I can I can interact with these stops, I can also still change the the source code itself. And you can see again, it updates the state here. So this checkbox is now checked and the company is in loaning state. So how does this work? First of all, we need to somehow describe what the properties are butting heads so we can render the Knapp's if created a simple configuration format. Here's the example for each. Perhaps you can set name the type and description. And when we update the code, we now somehow need to extract some pieces of information out of it. We need the proper names and values so we can display them in our Knapp's. The first quick solution would be to use a regular expression like here. Here we are matching six element and getting back the parts with props and children. It works, but it's extremely brittle. What if we have multiple components? What if they are nested? How to tear them apart? Now, the code is just a dumb one long string. We don't have some deeper understanding what it really represents. So we can really do much about it, um, we need a completely different and more powerful approach. We need to turn our code into a tree in the abstract syntax tree. Unfortunately, we already have a duel just for that in our project is Babille in order for Babbo to do anything with your coat, it also needs this deeper insight into it, into its meaning. So it always starts by creating an acidy out of code you pass to it. You can inspect LSD in this very useful tool called as the Explorer, so here is our button. We are using parser and on the right side you can see the the the three representation of our code. Um, now, if I hover over different parts of our code, um, you can see like what node. What it is like being highlighted, so, for example, this pattern now corresponds to this chair six identifier, if I go over the type you can see it is just six attribute and the primary is a string literal. So now I know exactly what each part of this growth is, and I can just be sure I'm getting values. I need to I need to get. So here's the implementation, like first you use the Powers function from Babille parser and you give it your code and this actually generates the three structure you saw. And then we use reverse function to walk these three and we are looking for all six attributes or props. And once we get this type of note, we just save the name and the value. So this is like very simple way, how we can get all the prop names and values from our component. I also demonstrated we can do it in reverse, so I was able to change these snaps and it was actually updating this code. And by the way, we've never written a single line of this code in our examples like this is all generated just based on the on the prop configuration and the state of this playground. So how does how this process works in reverse? How do we actually generate a quote? So as you can imagine, there is some sort of statement perhaps, where you have the list of the names and its values, you know, what the name of component is. So, again, we could try something simple and we could just glue a bunch bunch of strings together. And this will give us the final step. And it works. But again, it gets complicated pretty quickly with all the exceptions and different cases. And it's it's also a very easy way how to produce a code that doesn't work and has some syntax errors. Uh, we already learned similar lessons with regular expressions. And so, again, we need a more reliable approach. I mentioned this already, and it turns out you can also just build them from scratch. So this is a simplified example of function that creates and nasty the abcess element, which can compose notes together to build our own tree from nothing, since all these functions are statically typed, if we are forgetting to pass any value, you will get an error. And now we can be sure that whatever is the final script is it's going to work. So this is, of course, now we have the Asti, but we still need to turn it into the code. So once we have the Asadi, we can we can use generate function from Beppo Generator. And this just turns to Agosti into coat. But there is one glitch. This will result only into single line of the code, which is not super readable. So we can get fancier and we can use like other popular tool called Prettier and prettier is actually using the same as the representation for the code as Babul. So we can just use prettier to print out much nicer code snippet. So there are many other features of this playground I don't have time to show you, for example, not all components are as simple as Button. Sometimes you need to include some. Sometimes you need to use local state to make your examples realistic, be supported. Sometimes you need to know multiple components be supported, or you even want to build a custom prototype and a custom knob for it. We also support that. All this is wrapped in this library called Project View. It's open source and it has its own interactive documentation. So please check it out. Um, and here are some final thoughts, first, documentation is immensely important and a critical part of anything you ship. It helps your customers to use your product, but do it also for your own selfish reasons. You can save yourself a lot of time by not answering questions that can be answered by quality documentation. Second. How can we make documentation much better get your superpowers with abstract syntax, trees and tools like babble and breathe the air, we already use them to build our applications. Um, but we can also use them to do right some boring parts of our growth and build much better documentation and finally to get started. Check out reactor view. It's open source and it covers all examples in my talk and our documentation. And there is one more thing we found another use for having a specification for each component be translated into code snippets. It's a great paper user feature. Oftentimes the developers don't even need to read documentation to produce new code. And what's better than that? If you want to keep up to date, here's my Twitter and thank you for watching.