Travis Arnold - Omnidoc, Restyle, JSX UI
devtools.fm
September 1, 2024
{/ TAB: SHOW NOTES /}
This week we talk to Travis Arnold, a developer who is working on a new tool to make managing typescript documentation easier.
Omnidoc is a tool that allows you to build a fully customized documentation solution, and the examples are event type checked.
We also talk about his other projects, Restyle, JSX UI, and the future of React.
- https://x.com/souporserious
- https://souporserious.com/
- https://jsxui.com
- https://x.com/omnidocdev
- https://x.com/jsxui
- https://omnidoc.dev/collections
- https://www.restyle.dev/
Episode sponsored By MUX (https://mux.com)
Become a paid subscriber our patreon, spotify, or apple podcasts for the full episode.
- https://www.patreon.com/devtoolsfm
- https://podcasters.spotify.com/pod/show/devtoolsfm/subscribe
- https://podcasts.apple.com/us/podcast/devtools-fm/id1566647758
- https://www.youtube.com/@devtoolsfm/membership
{/ LINKS /}
{/ Paste show notes /}
{/ TAB: SECTIONS /}
[00:00:00] Introduction
[00:02:29] Introduction to JSX UI
[00:10:04] Ad
[00:11:14] Performance and State Management in JSX UI
[00:15:46] Introduction to OmniDoc
[00:22:17] Challenges and Solutions in Documentation Tools
[00:25:02] Server Components and Performance Enhancements
[00:30:15] MDX Content and Performance Challenges
[00:33:18] Rendering and Type Checking with Collections
[00:40:18] Introducing Restyle: A New Styling Solution
[00:50:36] Future of React and New APIs
[00:54:47] Conclusion and Final Thoughts
{/ TAB: TRANSCRIPT /}
Travis: the new latest product I've been working on is called OmniDoc. And that really is a solution for documentation for JavaScript, uh, code basis specifically, or TypeScript, if you're using TypeScript, um, and that allows you to build a fully customized documentation solution.โ
[00:00:20] Introduction
Andrew: Hello. Welcome to the DevTools FM podcast. This is a podcast about developer tools and the people who make them. I'm Andrew and this is my cohost, Justin.
Justin: Hey, everyone. Uh, we're really excited to have Travis Arnold on the podcast with us today. Um, so Travis goes by super serious on Twitter, um, really love following his Twitter feed. So, uh, you should definitely check him out. Um, and Travis, you've worked on a lot of really interesting tools. Uh, I think the most recent thing that I was following as you're working on was restyle, restyle.
Justin: dev, but you've also got, uh, JSX UI, which we're excited to talk about and, uh, OmniDoc, which we're People may have known previously as MDXTS, and we'll talk more about the relationship and how all that's evolved. But before we dive into that, uh, would you like to tell our listeners a little bit more about yourself?
Travis: First, thank you for having me excited to be here and talk to y'all today. Uh, my name is Travis Arnold, like you said, and I've been a designer and engineer for Uh, I started off in high school with a t shirt company and, and was selling t shirts and got into screen printing, had a screen printing business, got into just kind of full multimedia, um, development started doing video, uh, just kind of went, you know, like my young career, uh, the whole, just like multimedia route and throughout that, I started dabbling in, in web, uh, doing WordPress sites, themes of that nature, uh, back in the day, right.
Travis: to learn PHP at least and post about it on Stack Overflow and then got into Sass. You know, really, I saw that design careers weren't really making that much money. And so I saw engineering salaries were a little bit better and kind of piqued my interest cause I was, I was into engineering. And so. Yeah, it went kind of full, full heads down in that.
Travis: And naturally I think went into design systems work for, for a long period of time, uh, just seeing how to try to scale design systems across organizations was really interesting to me. Um, and yeah, that kind of brings me to today and the work I've been, been working on, been really into react the last like decade.
Travis: So since react came out, I was kind of on the scene there.
Andrew: And you've gotten really into making tools for react recently.
[00:02:29] Introduction to JSX UI
Andrew: My first interaction with you, or just like seeing you on the internet was your work with JSX UI. Uh, it seems like a really interesting project and it's been going for a very long time at this point. So can you tell us what JSX UI is?
Travis: Yeah, absolutely. So JSX UI is a play on Swift UI really. Um, when Swift UI came out, I was really fascinated with that and. That's just something, that's something I would say everybody should do is look at other tools in the ecosystem, uh, to see how other folks are innovating. And it, yeah, I just wanted that for JSX.
Travis: I don't, I love the web and I don't want to leave the web. And so, uh, I wanted to bring that kind of to the JSX, uh, more React ecosystem, but also JSX in general, cause I I'm looking like decades out. I don't know how long React will last. I think it'll be around, but I feel like JSX is a really great primitive, Uh, and maps really well to design tools, honestly, like that, like coming from a design background and and working in design tools, the declarative nature of react.
Travis: Um, yeah. So yeah, going to getting to JSX UI. Um, It was kind of like a, uh, pet pro not a pet project at first. Um, and wanted to be like an idealization of a design system I had created like for six years, you know, just poured blood, sweat, and tears over it. And I let that go. Cause I, you know, moved on from that company and I realized like, Oh, I would do all these things different.
Travis: And so I wanted to, yeah, have something that was performant, you know, easy to use, just kind of fix all the problems that we see in, in front end development of it just being hard to put components together, compose them together. Uh, and yeah, stay with performance and things like that.
Justin: This is a this is a fun like thread that we all share is that we've all done a lot of design systems work And and are interested in that My time at Artsy, we used, uh, Bryn Jackson's styled, uh, styled systems, uh, which itself used styled components and the API for that was nice because it was like very declarative and we could come up with sort of our own primitives like spacing, uh, and use that, like, You know, just by props.
Justin: And we even had like types and everything for it, but performance was the big thing that suffered. It was like that we got this like really nice design API and even had it like synchronized with, uh, our actual designs and sketch and then Figma. Um, but. The performance really wasn't there. So how did you tackle this performance problem with JSX UI and maybe kind of for the people who haven't worked in this space a little bit, could you kind of explain like tactically what you were trying to tackle with the library?
Justin: Like how, how are you trying to approach this problem?
Travis: Yeah, absolutely. Um, I'd say the, the biggest problem I'm trying to tackle really is performance and not even just performance, but also making it feel first class like it doesn't, I feel like the tools we use often don't feel first class or a more holistic experience like everything is working in unison, which I think leads to bad performance because we're attacking all these different libraries together.
Travis: And going back a little bit, talking about that library I had made, I used Glamour out of the gate, which was great, shout out to Sunil, love, love that library. The CSS and JS movement was fascinating to me that we could capture dynamicism, um, with CSS and also just provide a better API. And getting to JSX UI, I, I wanted to figure out how can I, mainly for layouts, I think layouts is a big one.
Travis: And so when you try to calculate. Any sort of custom layout, which comes up fairly often. If you think about just really drag and drop, you have a little like split windows or something like window management, uh, responsiveness, opening a menu and needing to move items over all these things like cause performance issues.
Travis: And so layout is probably like the biggest thing. I'd say I focused on with JSX UI and helped form the API. And through that, I came up with a few different, um, paradigms that are, are similar to things that are out in the industry. And it's funny to see how some of these things have evolved over time.
Travis: And I was like, Oh, wow, I'm like working on something similar to that. So like variants, for example, um, which in style system, right. They have this like variant system and a lot of people have kind of like evolved. And then you have tailwind that's got like this. Version of variance and all this, but those don't capture the entire story, which is, is kind of unfortunate.
Travis: So I think I don't want to get, maybe we can get into that as far as, as like, I love tailwind, I think the idea is great, but it doesn't capture everything. And that's kind of the hard part here is like, sometimes you need to capture a value or measure values. And that's right. When you run into a performance issue is, Oh, I need to measure this thing.
Travis: Maybe I'm doing layout thrashing and it's just really chuggy. Yeah, so those are, that's kind of like the biggest thing as little, little tangent,
Andrew: So like what, what layout primitives did you add? Cause like, I think from your stuff, I, like from your tweets, I saw like H stack and B stack like years and years ago. And I've added those into like all the things that I do, but what did you add here for JSX
Travis: Perfect. Yeah, totally. It's been a while since I've like worked on some of those things. So, uh, yeah, I appreciate the, uh, Reminder.
Travis: So HStack and VStack for folks that don't know comes from SwiftUI. So that's probably a direct, um, comparison. They also have ZStack. Uh, and those were, uh, I'm very like idealistic.
Travis: And so I was like, that's a little weird. Like why call it H stack or Z stack? And I'll, I'll spend way too long and get philosophical on what do you call this API? Like, how could someone use it to their full potential? And I landed on column and row because it felt like that was the, that was the primitive that most people I think know.
Travis: And. We have grid layout that's come out and I wanted something that was just a uniform way to, to build user interfaces truly. Um, and so I landed on the three components for, I think, four components for layout, um, and just kept it to that, to keep it very simple. And so there's a grid primitive, a column primitive and a row primitive, and that allows you to compose pretty much any UI you can think of.
Travis: And I was trying to bring some of my design roots into this while I was making it of like, Let's throw everything away, go back to first principles. If I could just start right now and create the best UI framework for someone to create a user interface that's performant, uh, how would I do that? And so that's kind of where all these, uh, these ideas have come from and why the project's taken a really long time.
Travis: I, I kind of put it on pause in a sense and, and, Made the repo private because it wasn't to like where I want it to be. And so you can't really see anything about it right now, publicly. Um, I'm hoping within like the next year I can, can release that and we can get into the evolution of like why that's not out yet.
Travis: Um, but yeah, just trying to really just solve, solve layout. I think that's the biggest. issue you can see across multiple industries truly. So just to let, I know this is a front end focused podcast. If you look at other industry, well, yeah, I mean, I guess dev tools do, or just in general, um, if you look at, uh, across the industry, like in Swift UI, they've run into, that's a brand new framework and they've run into layout issues.
Travis: It's a really hard problem. So, um, just, yeah, I've been just very curious on how to solve it. I guess is, is this JSX UI project and. Yeah, I don't know. I think digging a little bit into why you need to, to understand, uh, all the like layout primitives to make that work.
[00:10:04] Ad
Andrew: We'd like to thank our sponsor for the week, Mux. Mux is a really cool platform that makes it super easy to add video to your platform. Video is a place where you usually need a team of experts. Luckily, Mux comes in with some awesome APIs to help you out.
Andrew: if you've ever gone down this rabbit hole, video is something that can be really hard to add to your app. Whether it's all the different types of video formats, streaming it, progressively uploading it, creating a video player, there's so many odds and ends to think about when trying to create a really good experience.
Andrew: But with Mux, you don't have to worry about any of that anymore. It's a turnkey solution for adding an amazing video experience into your app within hours.
Andrew: With video, there's so many new things to learn about how those files work. With mux, you largely don't have to. Recently, they announced that they have a new feature to make encoding simpler. They just released this really cool new feature that makes video quality just a click of a button. You can choose between basic or plus quality. The plus quality does dynamic bitrate encoding on the fly using AI analyzing the video. That's super cool, something you might not think about, and something that'll make playing video in your app so much better.
Andrew: To learn more, head over to mux. com.
[00:11:14] Performance and State Management in JSX UI
Justin: Yeah, I think this is, this is just like a common vein and it goes back to, Just layouts are hard. And it's not just like, I think it would be simple if you just had to build one static layout, like in the days of print media, where, you know, exactly where it's going to go and you need to design one layout.
Justin: And it's like, that's an easy enough thing to do, but we were talking before we started recording and it's like, one of the hard things to do these days is like, You have, you know, dynamic resizing. So we've been talking about responsive design for many, many years now, but that still is really hard. And in the React world, it's like, it's really easy to fall into, Oh, I'm just going to do things logically on client side, uh, which completely breaks down when you start doing server side rendering.
Justin: Um, and you know, there's all these like challenges that come into play and, you know, not to mention how you do layouts can affect performance. Quite a bit. Uh, so ton of challenges in this space.
Travis: Yeah. It's, it's, it's interesting cause it's, it's easy to take it for granted that it's not, um, it, that how hard it is until you get into like this death by a thousand cuts situation truly. And I found, yeah, so the, the, the, To get into, like, why it's such a hard problem, I think, is because you need to know every single piece of state that's going on.
Travis: And so, going back to the Variants API, I've experimented with a few APIs, and again, went on this philosophical journey of, like, what's a modifier? What is a variant? How do they coexist? Are they the same thing? And in JSX UI, there is a system, a modifier system, and a variant system. And the way I've, I've, Describe these is that a variant is a representation of props.
Travis: Um, so you have essentially different states. You can think of like a state chart. That's your variant and modifiers will modify the actual output of it. Um, which is they are very similar, but in the sense that. Modifiers come from SwiftUI, again, gleaning a lot from SwiftUI. Also not SwiftUI, though, as well, there's Jetpack Compose.
Travis: I don't know if folks have heard of that. It's like the equivalent to SwiftUI on Android. And so just trying to pull a lot of learnings from those. And with these systems, you can Pretty much like if you're strict about it, you have a strict system. You can infer the full tree of what's going to happen. I can look at every single state.
Travis: So it's almost like embedding a state chart into JSX is kind of how I think about it. Um, so folks like David Korshid promote state charts and love it. And I love the benefits of state charts. I think the reason that adoption maybe is not as. like, you know, the value of what a state chart does and what the benefit it brings, but it feels like I'm not, not enough people are using it.
Travis: And so JSX UI for me is trying to meet people where they're at. And you don't even know it's like a state chart behind the scenes. That's kind of running everything and there's a strict mode. And I think I won't have a strict mode possibly. So, um, but yeah, we'll see.
Andrew: I've actually been like solving this exact problem in my side project right now. So like, are you saying that JSX UI kind of like through that JSX pragma is creating a state chart behind the scenes that like knows all about the layout and can like do it performantly because of that.
Travis: Yeah, exactly. So, the current, um, writings and, and, uh, what I put out on JSX UI is pretty dated. That's, it's kind of, there's a lot of stuff behind the scenes that I've worked on that I'm eager to get released out. Uh, but that's, I kind of, that led me into this compiler concept of, of compiling away design and kind of just trying to find the right level of what JSX even is.
Travis: Um, Because once you have that representation, it's almost like a design tool. You think of like a design tool and moving through, they have a, probably JSON representation, something like Figma, uh, and they spit out all this garbage and it's not garbage, but you know, it's, it's, it's their API. It's, it's how they are able to interact and, um, understand like what someone's intent was.
Travis: And I think that's the biggest thing. I'm trying to capture is that all of this is intent, really, uh, as a designer, I I'm trying to mock up this thing and show you how it should work. Uh, that should be expressed through our code. And I think JSX is just a really good vehicle, uh, to be able to do that.
Andrew: I, I find that super interesting and we'll definitely be digging into those ideas after the podcast, but maybe moving on here a little bit.
[00:15:46] Introduction to OmniDoc
Andrew: Uh, you haven't been working on JSX UI for a while. You got sidetracked on another big project. So what is that big project?
Travis: Well, you know, as one does with a developer
Andrew: Yeah.
Travis: have 20, 000 ideas, you're like, I'm going to do the next one right away before the other one's finished. Uh, no. So the, the new latest product I've been working on is called OmniDoc. And that really is a solution for documentation for JavaScript, uh, code basis specifically, or TypeScript, if you're using TypeScript, um, and that allows you to build a fully customized documentation solution.
Travis: So, looking at other things in the industry, I've just never really been. Happy with like this, the off the shelf solutions. And so I, and really just any company I've worked at, I worked at frame IO, which is a video collaboration company. And the bar there for creating like really good user interfaces and experiences is really high.
Travis: Like we would record a video and scrub through, you know, every single frame, trying to make sure that it was just, everything's on point. And to carry that quality through to our documentation was really hard. And so. I helped build a custom doc site there and I built custom doc sites prior. So when I worked on this larger design system before I built a Gatsby site, which was, took forever to do because I'm trying to learn GraphQL.
Travis: And I'm like, why am I learning GraphQL to build a doc site? Thankful for it in some sense, I guess, uh, because I was able to, uh, get exposure to those things. Uh, and it was just always hard. It was really hard to build a custom doc site. I think. me being a designer as well. And I think a lot of folks, they want, you want to do something custom.
Travis: You want to add personality to even your doc site. You want to carry your brand through to your documentation site. And so this is something I've been very passionate about and wanted to solve. And kind of why I put JSX UI on hold. I wasn't able to get what was out in my head enough or be able to iterate quickly enough, uh, to, to get the, to formulate these ideas and.
Travis: I think documentation is a really great place for that. You get to, it's a reflection of like what your code base is doing. And so, yeah, to get into like what OmniDoc specifically is doing is, is providing a way to type check your code blocks. So that's as far as like running the TypeScript compiler across all of your code blocks, and this is to make sure you don't show someone code that's not, that's not going to work.
Travis: And we've all done this where you're like, Oh, I didn't, I didn't. I had to get this PR out or whatever, and I forgot to update this one property that I changed. Uh, just like we type check our code, it will type check your code blocks. Uh, and then another like large feature is just automated API references.
Travis: So, I went deep on the TypeScript compiler to like figure out how to build a automated API reference. I think, again, like things off the shelf were just a little either too constrained or they didn't do enough. So if you've ever used like React, React doc gen, um, they give you enough information and it's great, but then these projects will die off or people aren't maintaining them.
Travis: And it's totally understandable. Open source is really, really hard and you're not getting paid for it, like probably not getting paid for it. And so, Uh, it was just kind of trying to fill that gap in the industry, especially for the projects that I've been working on, um, and to dog food myself. That's something I, I get to use every day and OmniDoc is built with OmniDoc.
Travis: And so I get to make it better in that sense and then work with folks as well.
Andrew: As, as a maintainer of one of those poorly maintained, uh, react doctrine, uh, packages, I can definitely relate. Uh, so what, what, what did you find lacking in those other than maintenance?
Travis: Hopefully I don't say anything that's too, no,
Andrew: probably the worst open source person ever. I do not check my notifications.
Travis: don't wait. No one does it. There's too many. No, I'm just kidding.
Travis: Uh, yeah, the, I think the biggest thing I wanted to solve was, Compared to other solutions was just again, like meeting you where you're at as a developer. A lot of folks are capable of, of, of building solutions. And I've even found, I just redid, I did a re a major release of Omni Doc, uh, to help fix these, my own issues of, of trying to get, uh, like a good API out for folks to use.
Travis: And I think that's the hard part about API design. You just have to iterate on it. And I think you should try to really find this most simple solution. That doesn't do too much, but it does just enough. And so that's kind of what I'm trying to find with OmniDoc is that it's just a tool set that you can pick individual pieces.
Travis: If you just want the code block component, just use the code block component. If you want to use, um, what I'm calling collections, you can use collections and Uh, collections are specifically just a way to, uh, you can think of like storybook, for example, storybook allows you to map over all of your examples, and there's kind of a DSL.
Travis: They're like a custom API. And I wanted to get rid of those things. Like, I don't want. A custom DSL as much as I can help it. And so in this case, in OmniDoc collections really are just a little bit of sugar around modules. And so it allows you to query a set of modules. You pass a file pattern and you get back data about your file system.
Travis: And it's kind of the implicit rules that We follow, if you go, if you work in a design system, Hey, we use an index. ts file and maybe we don't, I don't like to use index. ts files. And I want to use a button. tsx explicitly or something like that. You know, we, we all come up with these like implicit rules and then people don't follow them or the code base gets out of hand, et cetera.
Travis: And so this, with this new architecture, I'm really excited about, uh, being able to not just type check. your front matter, for example, you can type check just any export that's coming out of a, uh, a module. So, uh, this allows you to grab a, um, I think a perfect example is, is examples, which is funny. Um, you can grab examples in your code base, similar to like storybooks, or if you want to call them stories still, I don't really, I don't care as the, as the library.
Travis: And then you can type check to say like, Hey, every example should. Attach this sort of information to it, or these examples should be formatted in a particular manner. And you're really just using what you already know. Like, you know, you can use the types that you already know, and that'll throw a type error or it'll throw an error if it doesn't find a front matter export.
Travis: And so this moves beyond MDX or, uh, and kind of goes across like the whole system. And so, uh, trying to really just solve that, that portion of it. Um, yeah.
[00:22:17] Challenges and Solutions in Documentation Tools
Andrew: When I first read the name, I thought that it was like, you were fully type checking MDX. Cause this is a problem that I've encountered many a time when authoring content is I want to use MDX. I also really like TypeScript and I like static analysis, but seemingly, I can't type check my whole MDX file just to like, make sure that it's what I intend, especially if I'm using components that I've imported.
Andrew: So does MDX aim to help with that problem at all? Or is it like lower level?
Travis: Uh, it's a little bit lower level now. So it, prior for folks, it used to be called MDXTS. It's now called OmniDoc, no worries at all. Uh, and that's the, the whole reason for the rename is I realized I wasn't capturing or the project kind of just grew. It was really just about type checking your code blocks at first.
Travis: Um, and then grew out of that. And I, I do want to mention that there are solutions out in the industry, as far as I think Sheiky2 Slash will, is a project that will help you do similar things. But what you run into is when you're trying to do API references with the TypeScript compiler, and then they're doing their own type checking with code blocks, you just, you've run into performance issues like this.
Travis: Pretty immediately, especially in an enterprise situation. And I used to have frame. I would, I remember my first pass on things. I would just like timed out our, our Netlify bill builds. And so it was just like 15 minute builds because the type checking was just, it's really easy to be naive with some of these solutions.
Travis: Pulled React doc gen off the shelf and put it XJS application. So, you know, get static props is calling this thing. But it's using a new instance on every, like, it spins up the TypeScript compiler every single time. And so you need to be very careful about how you use these, um, tools while being very powerful.
Travis: Um, just trying to, yeah, help, help type check those things. So
Justin: Is this really sort of built for, uh, cases where you're like using react specifically, you're building a product with react or an API with react and you're trying to document that, or is, is it just like, it's broader than that, but like handles that use case particularly well,
Travis: it does handle the react use case particularly well, like mainly because of server components. So I'm utilizing server components in a lot of the components that you get. Uh, whereas, and I, I straddled this line because, Right. There's, this is applicable, especially this new collections concept I have is applicable outside of, of react.
Travis: You don't need react to use this. It's just helping you gather modules and render the, like the output of them. Um, but similar to JSX UI, I kind of want to lean fully into the. A language or a framework to get the most out of it. And so it's been, yeah, straddle of that with OmniDoc for sure.
[00:25:02] Server Components and Performance Enhancements
Travis: Um, But yeah, I want to get into, uh, Just like expressing this new paradigm of server components that we have.
Travis: Like we just got a new tool and we can go back to first principles. And what are, what are all these new things that we can do with this? And I found a lot of use cases, particularly in documentation. I was, I was in the middle of almost being done with this project, server components came out and I stopped and rewrote it because I didn't want to put this thing out that I didn't, you know, full wholeheartedly believed in.
Travis: And I saw that server components could help fill a nice gap here of. Of the performance, like things of like performance issues or, and right. We're not shipping a bunch of client stuff, like client code. And so, yeah.
Andrew: Yeah, I've, I've on and off been rebuilding storybook also, uh, and had almost the exact same thing happened to me. I rebuilt, I built this thing entirely on Vite, leaned into the bundler system there, no server components. And as you can imagine, things like. Property documentation generation, all of those like heavy things just slowed the build process down, made it super complicated.
Andrew: Rebuilding with server components was like a breath of fresh air because it was like all of these hard problems where I was communicating between computer A and computer B, and like having to think about all of it with server components. It's just like, Oh, I want property documentation. Uh, make a component that does it, put it in a suspense boundary and voila, we have data sharing between the front and back end, and it's not all that slow when you're in dev mode.
Travis: Yeah, that's a perfect, uh, a call out as far as using, being able to use suspense for this. And so this refactor that I just did, this large refactor, I baked in, I wanted to make it really easy for you to use, to document, that's like the whole point of this project. And I had like exported types on, on this field that you get.
Travis: You, you created a source before, and then you get back the source and it gives these exported types. I was running into similar problems though. I'm like, crap, this thing is slow as shit. Like it is so bad. I don't want to put this out. And I really haven't even talked about it on, on X or Twitter, formerly Twitter, uh, about these things because.
Travis: You know, a little bit embarrassed. I'm like, I'm trying to, to put this thing out and I want to make it performant. And so I went back and did a large refactor of, of this, this TypeScript analysis. And now everything's on a separate thread, which, and the beauty of it is it uses suspense. locally. And so it's something that I don't think a lot of folks probably care about or even talk about, but we all, we're all focused on production and using these with APIs.
Travis: This is essentially an API. I'm talking to the TypeScript compiler. It's, it's essentially a language service that I've built like a custom language service for it. And so now it can communicate off thread and everything is extremely snappy. It's where I've always like imagined this library to be. It looks a little wonky right now, at least in, in dev, because you move around and the code blocks, aren't syntax highlighted yet, but that's because they're using suspense and so it'll just show plain text and that's, that allows you to like move really quickly in local dev or, module update.
Travis: Like. Replacement, uh, and, and yeah, suspense works beautifully there. I have a fallback state yet, which again is plain text. And then they just kind of all come in as, as the server is able to respond, uh, once it's under pressure. So yeah, I love it.
Justin: that's awesome. Um, so. Just kind of like looking at what you're building here. You also have like sort of built a lot of components that sort of come out of the box with OmniDoc. Um, so what, like which of these components do you think is really interesting? We talked about the sort of like typed code blocks a little bit, but are there any other things that you think are like really valuable?
Justin: Um, and like what other sort of problems are you trying to solve here?
Travis: Yeah, definitely. I think the, the beauty of the component model is that you can just grab a component and pull it from off the shelf. Uh, and especially with server components. I found a really nice pattern that I've tried to take from just previous experience of working in just regular React for, for so many years of we want composability, right?
Travis: With these things. And there's some primitives still, I feel like lacking or maybe just creative ways to try to get around this problem of there's no context concept of context in, uh, server components, which is sort of a bummer. They had create server context and they got rid of it. I understand because again, like this is not really the use case, building like a dev only like experience with it.
Travis: Um, but this allows these, uh, these code blocks. It's like, I, I, the code block, for example, allows you to fully compose all the tokens and things like that. Like I abstract away all of this complexity for you, but give you full customization. To make the code block however you want. So it's pretty much a headless code block if you want it to be.
Travis: So out of the box, I provide full styling for you. You can just use the code block if you want, but if you want to dig in and start to make, customize everything yourself, or maybe you want the file name to be on the right side, et cetera, these, these things, uh, you can, you can do that and then not sacrifice performance.
Travis: So I think that's like the golden, like place where we all want to land with these libraries or design system engineers is like, I want to give you a set of really good building blocks. And not sacrifice anything if I can.
Andrew: Yeah.
[00:30:15] MDX Content and Performance Challenges
Andrew: I think server components has really like changed the game on a lot of these things. Like, uh, when I was implementing my stuff, MDX, like every MDX library out there, like almost doesn't make sense in the new paradigm because they all do all this like crazy juggling of like, Oh, I'm going to do some stuff over here.
Andrew: And then now you have a bundle I pass to another thing and it does. All this stuff. It's just everything is kind of just so wonderfully simple in a server components context where it's like, I have my content, make it into components, stream the thing.
Travis: Yeah, it's great with the, like being able to, so that's another component in, in OmniDoc is you get, it's called MDX content. And if you need to just render MDX content, which in the case of, uh, kind of going back to, to where like these tools get complicated, cause they're all trying, they're either not working together or they're trying to take all these concerns for themselves.
Travis: Uh, I use this MDX content component within the quick info that you get. from the TypeScript compiler. So the TypeScript compiler will give me back your JS doc information. So if you have a description and most people will put Markdown in that, we need to render that Markdown out. And so, you know, these solutions are doing that for you on the other side.
Travis: You don't know, but that all like starts to add up to these performance, uh, hits and where it can get just really like tedious, uh, to build these things. And so you can just use this MDX compiler. Content component and render a little bit of MDX. Um, and then going back to the collections, you can hit a wall with that too, with MDX, trying to render MDX specifically with server components where you don't have your.
Travis: Bundler anymore. So now when I need to import images or not even import images, import another component, you kind of lose out on all those, those niceties of it. And that was something when I was at frame again, like my product manager, he was like, I want to, Important image here. And I was like, well, we don't do that because, you know, we're just rendering MDX then I was like, but I'll figure it out, you know, I'll figure out how to do it.
Travis: And so then I'm trying to like get ES build to run and bundle everything and it just becomes a mess. And so that's why I'm with OmniDoc. I'm really just trying to find a nice balance of. Of again, meet you where you're at. If you, if you want to work within your module system, you can, and you can get all the benefits of image optimization that like Next.
Travis: js gives you or whatever Vite can give you, things like that. I don't want to constrain you too much and just, yeah, help, help facilitate you writing documentation because we need everybody to write good documentation.
Justin: so you can render these code examples, but I didn't find anywhere in the docs that's like, kind of like running them. So like, can you also run the code examples or is it just like strictly display?
Travis: I did have a preview component is what I was calling it. And I pulled it out for now just because it wasn't, um, I was running into performance issues with that as well, trying to figure out like a nice balance there. And so I'm telling people to go to use like their module system for this, for this very, thing to like render out an example.
Travis: And so the way you do that is with a collection.
[00:33:18] Rendering and Type Checking with Collections
Travis: A collection gives you back some of your module data and you get back like the default export if you want it. So if you're trying to render MDX, for example, you can point it to a file pattern and say, go grab all of these posts in a directory and it will give you back a, a helper method that.
Travis: Is a, is what is called a source and in a source, you can get your default export. You can get a named export. So that's how you can target front matter. So if your MDX is exporting a front matter, uh, variable, which there's some tools for this, like, uh, rehype plugins that you can, or I think remark plugins that will take your front matter, get rid of it, and then re export it as a variable.
Travis: Now that's a named export that's coming out of that module. And so you can use this, this collection mechanism. To type check that front matter. And you can also use it to, to render that front matter, however you see fit. And so this is where it becomes really powerful compared to, I think other solutions, like I'm working with your module system, so now you can, it kind of was like a epiphany to me as I was building it, I was like, Oh, whoa.
Travis: Like now I can type check anything. I don't have to just type check my front matter. I was trying to bake these concerns in before and realize that it wasn't, um, It was fine. It's, it's like similar solutions though. I was like, well, I'm just kind of building the same thing that exists out there. And so, uh, again, yeah, trying to find that nice, uh, API layer where, uh, it can empower folks rather than, than hinder you at all.
Justin: When you're talking about type checking here, like specifically for the front matter, is it sort of similar to how Astro defines collections and that you like to find like a Zod schema or something, and then it's using that to check it, or are you actually doing something to like pull that information out and like actually feed it directly to the TypeScript compiler?
Justin: Like how's that like mechanically work?
Travis: Yeah. So it's, it's very similar to Astro's, uh, collections. Um, but it does not use Zod. So it uses TypeScript to do that. And I think I'll have some sort of schema mechanism there. So our validation mechanism that you can plug in Zod if that, uh, if you're using that, um, but right now I take the, you, there's a generic argument that you can pass.
Travis: And so talking about collections again, that's where you can type check your, uh, your content. So you can say, Hey, my front matter. Or again, any export for that matter looks like this shape. If it doesn't look like that shape, throw an error. And I do use the TypeScript compiler to do that. So I make sure that it's not, um, like it will type check against those things.
Justin: That's really cool though. That's, that's pretty huge actually, because, um, this is like a general problem and something I've wanted better from TypeScript and like overall is, you know, I know we're talking about like. Having an MDX file here and you have some control transformation. So you can just do more things with it.
Justin: You can like have an intermediate step where you transform it to a kind of TypeScript or something, and then run the compiler against it. But I wish like you could just write a type definition for a module file in TypeScript. Um, That would be so huge because there's oftentimes where you're like, yeah, look, you can give me a module, but I want a module of this shape, but there's not an easy way right now to like actually do that in TypeScript.
Justin: Um, there are like things you can do that are kind of like hacks and workarounds, but, uh, it would be really nice, uh, where that, uh, where that thing. So this, this approach is, sounds really, really interesting.
Travis: Yeah. I mean, to your point there, that's exactly what it is. It allows you to type your module. And so, uh, and make sure that it's, it's expecting exports from it, or maybe if there's a default export and you shouldn't have a default export, you can throw an error on that. And so it was kind of this thing that I landed on in the midst of iterating through this API, trying to just make it a little bit easier to use.
Travis: And I was like, well, I still can type check front matter. And then I was like, Oh, Crap, like yeah, I can, I can type check the whole module now. Like I can make sure, um, one thing I was saying, like with the stories or examples, you want to render an example of everything I can make sure there's. just only named exports in this file.
Travis: And if there's a default export, or even with your story, like if you still want to use storybook, um, like their DSL for how they, uh, is it the component story format, you could strongly type that and make sure that it follows a certain, uh, paradigm. So I'm really excited about this, like new collections, uh, concept that is, that's emerged from this.
Andrew: So one last thing before we move on to restyle, another library that fell out of your open source work, the common story we all have, but one thing the docs seem to call a lot is routing. So like, how does routing, uh, like play into all of this and why is it such a hurdle to get over?
Travis: Yeah, that's a, that's a good point. Um, so the collection back to the collections, uh, This allows you to build those, those routes. So, uh, and this is just to, to give you full flexibility of how you want to architect your site. It's really hard, you know, next JS is wonderful and I love it, but it kind of doesn't meet you where you're at with content authoring and.
Travis: You've reached for these solutions and you're trying to find like, Oh, well, I can render it in MDX or using MDX remote or all these, these, uh, different plugins. And so, uh, this collections paradigm allows you to just grab a module, get like the siblings of that module. So again, back to the, these implicit rules that we kind of come up with, like, or maybe not even implicit.
Travis: There's some things where like an index file in node is going to look at the direct, like, that's like, Talking like about the directory. It's like meta information about the directory. And so if you look at some of these doc solutions, they, they come with like. Very specific just APIs, like new APIs, I guess, a new thing I need to learn.
Travis: And so I need to add a meta file to like change the title, or I have to add this config file at the very top. Um, I didn't even talk about that. That's something I'm really trying to. Fight against is there's no configuration file for OmniDoc. You just use your code and you import your code. And I will infer as much as I can off of that.
Travis: So everything is co located. That's like something, a strong principle I really believe in is that we should keep things co located because you can find, you know, where it's at. You're not trying to go search through this like maze of where, where does something exist. Uh, and so, yeah, uh, th this will build these, uh, give you utilities to move through your file system, however you see fit.
Travis: So you can, there's a depth parameter, for example, and you can just get the siblings at like one level if you want to go deeper into those siblings. So like your next and previous navigations will like start to dig into that, like examples, um, you can do that. And so, yeah, it just kind of gives you a framework to build, uh, uh, A documentation site, really.
Travis: And even like a content site, if you just needed to do a blog or something like that, it works great for that.
Justin: Yeah, that's awesome. I think the, the no configuration thing is a, is a big point because that. I mean, there'd be dragons, right? That's all sudden you end up like getting way in the weeds with configuration. Um, so yeah, I'm excited to see how that plays out.
[00:40:18] Introducing Restyle: A New Styling Solution
Justin: Um, maybe let's transition on and talk to, and talk about restyle.
Justin: I'm actually really excited about this. I, I stumbled across restyle a little while back and, and it just like, seems really, really interesting to me. So, uh, this is something that like. Came out from you're like building OmniDoc and you're like, Oh, I'll need to handle styles in this specific way. And Restyle was born.
Justin: So can you tell us more about the story and like what you're trying to accomplish with Restyle?
Travis: Yeah, absolutely. Uh, so restyle, yeah, was born from OmniDoc. Uh, I was in the midst of OmniDoc working on the code block component and trying to figure out how to, I think it was a bug someone filed. There was a scroll bar issue where like a scroll bar was showing all weird. And I was like, dang, I need to like style this scroll bar.
Travis: Well, I can't, I was doing everything with like inline styles and it's kind of wonky just to try to make it like a, I don't want to impose any opinions on you on if you want to use tailwind or what have you, but I need some styling to get this out of the box. And I needed CSS for this thing. And I was like, well, what am I going to do?
Travis: Like, this is the like problem everyone faces when they're trying to build a component that has styling that ships with it. It's why we see all these headless libraries that come out. And I just got into react conf. And they had announced that they do this new style hoisting thing. And I was like, what the heck is this style?
Travis: This is amazing. Like, Oh my gosh, I can write styles in my component and they manage, uh, putting that in the head when I need to with suspense. If you've looked or followed any of emotion styled components, they all have ran into these issues. Where just the new paradigms of react are emerging now that we have suspense fully and concurrent rendering and you run into all these issues.
Travis: So to see that react had given us a solution, I was just like, Oh my gosh, I need to go, I need to use this. And so I built it into OmniDoc initially and realized really quickly, like, Oh, this is like. Territory for a library, which again, I think this is where we all end up and you can go on a tangent and go too far.
Travis: And I gave myself a constrained amount of time and I was like, let's just see what we can get out from like the implementation I had built in there. And, and yeah, that's kind of where restyle was born. And I was able to utilize this new, um, style hoisting feature and it gives you a, a kind of an atomic CSS solution.
Travis: And so restyle is I think most comparable to. Um, do I, I don't even know, like some of the atomic solutions off the top of my head right now. I'm blanking, but, um, yeah, it just, it will generate your, uh, the CSS that you put in and give you a single selector out for that, that CSS, and then it de dupes them across the client and server, which is really cool.
Andrew: Yeah, it reminds me of, uh, stitches and, uh, The one from Facebook, they just put out stylex a little bit like that.
Travis: Yeah. Okay. That's a great, yeah. Great example of style X. Um, Yeah, that like generating those atomic class names, but you can put however many rules in and then it de dupes them. So you don't ever generate exponential class names based on, on what you're doing. Um, and a real, like a really unique part of restyle that I think is easily like lost is the dynamicism part of it is that you can capture dynamicism in your component and it will render the styles.
Travis: That you, you were trying to like author. So going back to layouts that we were talking about earlier, this kind of, and unlike first principles blew my mind with like the JSX UI stuff I'm trying to do. I was like, Oh my gosh, I built a full compiler to try to understand this full, like statically understand what the application is doing, which in all cases you can't do, like sometimes you just, it's truly dynamic and you don't know.
Travis: What's going on this restyle library captures that because react is going to handle it like they know What I want to render at that time and they'll put it in the head and I don't have to worry about it. And so um, yeah, I haven't i've run into a little bit of issues there of like trying to figure out how to use this new primitive as Best as possible, but um, I really hope it works out and is it is what I want it to be Like hope for it to be as far, as far as like capturing this dynamicism.
Travis: Uh, because it's just extremely powerful. It's how you can build like a layout component and render a grid, um, like children and place them wherever you want, because it's dynamic. So it's really exciting.
Justin: That's awesome. I love to see more exploration in the space for sure. Cause I feel like, especially as like React has evolved and the solutions have evolved. There are a lot of the solutions that people have relied on for a long time that are just like. They don't really work the same way. Uh, and then also like a lot of new thinking has come along I think a lot of people are still investing pretty heavily in tailwind and that becomes a thing but Um, you know, there are new areas of exploration and it's nice to see like, okay What does it look like in this new world?
Justin: What things can we do now that used to be really either impossible or slow or whatever? Um, so it's it's fun to see
Travis: Yeah. It's, it's, it's the best time to be a react developer. That's for sure. I mean, if you've been around, like you, we didn't have class components, like classes, weren't even a thing in JavaScript and you had this create class mechanism. You couldn't return a raise. Like that was the hardest thing in the world.
Travis: Portals didn't even exist. Like, it's a really good time to be a react developer for sure. Um, and just very exciting. Yeah. Like these, these new paradigms are still emerging and I know the react team. I'm sure has a very large, bigger goal here. That's I'm going to play out the net this next decade and very excited to see, see where it all goes.
Andrew: Yeah, I'm interested to see how this new style construct like just changes react because like historically react has had zero opinion on styling and now that it's baked in like this, I'm really excited to see what people come up with. Using this new API. Was there any like weirdness? Like, I can't even imagine what it's like.
Andrew: Does it like merge things for you? I see it has like this precedence prop.
Travis: Yeah. So I didn't even know how the precedence prop worked. I was like, I, I'd filed an issue even on like the react repo, because I was like, Hey, like I'm trying to use this precedence prop. And they're like, Oh, you could just come up with any name for it. Cause I thought it was following like this strict, like low high, um, uh, yeah, mechanism, but you can just kind of come up with any name that you want to identify, uh, these styles with and the way it works.
Travis: It's a little tricky. I hope there's a little bit more, um, Configuration possible with it, but right now it's, once it first sees a style, it will generate the style for it, like, and push it into the head. And so you can end up in a situation where. it will create like a ton of style tags. If you have like a dynamic thing going on, um, in your components.
Travis: So if you're using this strictly on like the client, I've seen that if you do a server side, render pass, or it's in a server component, it will group all those styles, which is really nice. And so that's where like this atomic thing works out really well. Because you'll just get one style tag and all of the, the styles are, are in that.
Travis: Um, but the biggest gotcha I think is just, yeah. Trying to work around these, um, This, this like constraint of, Oh, sorry. Uh, once you create a style, it doesn't go away. Like you don't have control over that style. And so that's why I landed on an atomic solution for this. I was like, okay, if I can dedupe these CSS rules, maybe they'll hang around too long, but it shouldn't be a big deal.
Travis: And it will allow it like this weird kind of constraint to, um, to be able to play out, uh, Okay. So, and I found it to be okay. Yeah. So I'm using it in OmniDoc and the code block component has these like scroll bar styles, it de dupes all the tokens, which is amazing. Like that was a really hard problem.
Travis: Like if you try to figure out how to solve that, you're creating CSS either yourself and so now react just takes care of everything, which is amazing. So, um, you can look at like the OmniDoc site and, uh, if you look at the styles for it, they're all de duped. Like, so all the tokens. Um, like the colors, right.
Travis: All those colors come up again and again are all de duped, which is great. And so, uh, yeah, I have a lot to do there with like theming and playing around with stuff and, and folks have been like asking me about like, can you add a variance API to match this? And I'm like, I don't like, you can build a variance API if you want with it.
Travis: So I don't know if I want to add that into the core yet.
Andrew: You're like, please don't send me down that
Andrew: multi year long rabbit hole.
Travis: exactly. I'm like, I got JSX UI coming. And so hopefully. You won't care about that.
Andrew: so, uh, wrapping up here a little bit, uh, what's, what's on your roadmap next? Uh, we know you have the big rename coming, but are there any like cool components or other paradigms you want to introduce before going V1?
Travis: so we are at V1. So this will be, Yeah.
Travis: V2 is, is this rename and OmniDoc and this new, um, more performance solution. Uh, some component, like things I'm really interested though, or just digging like even deeper into documentation now, like now that I have a good baseline and it feels like everything's performant, it's kind of like most of like what you would expect to be able to just query things on the file system and render documentation for it.
Travis: Um, that stuff's a little like boring to me. Like I, I wanted to get to this, this spot because now I have a ton of other ideas to expand this. And so something I really want to do next is, uh, type checking. Inline code blocks. And so using like you, right. We reference, uh, code within our pros content. And so capturing those things.
Travis: So similar to, um, I think it's like a rehype pretty code does something. It doesn't do any type checking, but it does, it like kind of ties your, it ties these things together. Like they they're truly symbols. Right. And we don't treat them like symbols. And again, that's something where things can break down.
Travis: And if I have an inline code block, like that's similar to a regular code block, I want to type check that I want to make sure it's actually referencing something that exists. Uh, eventually I'd like to look into like. Tools with the CLI for helping rename those things, or maybe even a VS code extension, like far in the future, where you do like a renamed symbol and it goes across all your code blocks and it goes across all these inline code blocks and pros content.
Travis: to help just like fix these things because it's just so easy to mess these things up. And just kind of from my systems background, I want to like systematize these things to make sure that one, I don't do it and you don't do it as well because I'm probably reading your documentation. And so, uh, I want to make sure that, uh, things are up to date and interactive.
[00:50:36] Future of React and New APIs
Justin: So, uh, wrapping up, we always like to ask a future facing question. And I think one of the themes of this is that, uh, especially when it comes to react, you've seen a lot of these new API's come out and you sort of seen immediate applications on the open source libraries that you're working on and sort of how you can improve those to leverage this new functionality.
Justin: So I guess a future facing question for you is like, uh, for any features that have, that are out now, is there more things that you think that we can rethink? So using, for example, servers components to change how we write React code, or, uh, is there something that you have your eye on in the future that you think might be make another sort of paradigm shift like react server components has.
Travis: Ooh, that's a good, yeah, good, great question. I think the new use hook is really interesting and I don't think enough people are maybe. Like there's been so much focus on server components that this use hook has kind of fallen under the radar. And it's, it's a really great, great primitive. I mean, now you pretty much have asynchronous client components.
Travis: But you just, you like use is like, you're a weight, like you can think of use as an await. And so you pass a promise to it and it will resolve the component. And so I think some interesting things like this are shoe from, um, uh, the next JS team put out a view transitions, uh, Library around next JS and the way it's like using like why you should go check out that library and look at how it's actually using this use hook and it pauses like the suspense boundary and keeps it like keeps the promise alive until the transition finishes and then it resolves the promise and it's using this use hook.
Travis: I think the name is awful, honestly, because we're all used to it being like a hook and it's. I just called it a hook. It's not a hook. It's a, um, it's just this new primitive. I really hope they, they land on asynchronous client components. So that's my, my, my hope is that. I don't know if there's like just weird implications there.
Travis: I think there might be, but if we could just write like async in front of your component, I think that would, Just to help again, like you use the things you already know. I don't need to learn this weird use hook. It doesn't conflict with prior knowledge of hooks. I just like to write an asynchronous component like I do in server components, because it's the best thing in the world when you can just, uh, yeah.
Travis: Right. An asynchronous component and wrap it in suspense with the fallback boundary.
Justin: Yeah, that's really cool. I've been doing some research on on continuations and maybe that's the kind of thing that they're going for because it's like async await definitely has some problems and like some of the ramifications of using it
Justin: so it'll be interesting to see what they do with it for sure.
Travis: Yeah. Very excited.
Andrew: Hopefully they don't add generators. I don't, I don't want that.
Justin: I don't think they necessarily have to just because so much of their stuff is, you know, they already have, they're sort of like, they already have sort of like a threads or a continuation system, fibers, whatever, like under the hood. So they're already doing a lot of that stuff, just hiding it away from us.
Travis: That just made me think of something it's, it's really interesting. I just, I just, uh, posted about this of, um, if you have an iterable, you can just render that in react. And it's fascinating. Like, I think there's just like these new things, like it handles so many like primitives of JavaScript that it's really becoming like JSX is like blurred in this line of JavaScript that you're writing.
Travis: I think again, why I want like client components just to be able to write async code, because. You don't have to think about too much. You're just like, oh, I don't have to await I don't know. I don't know if like, I need to do promise that also I've posted about this too of like, do I need to do promise at all?
Travis: Cause I can just return, uh, an array of promises. And I'm hoping that react is like handling that for me, like the promise that all situation, so it's not, um, sequential, I'm sure I should probably still use promise at all. Uh, but yeah, back to like, we couldn't return a raise before now we can return an iterable and react will render it.
Travis: That's fascinating to me that, um, yeah. Yeah, we can just write more declarative code. And I think that's the whole goal about all of this is, is just being able to write more simplistic UIs in a complex world, because if you have complex code and things are already going to be complex,
Travis: it's, it's a bad time.
Andrew: I wholeheartedly agree.
[00:54:47] Conclusion and Final Thoughts
Andrew: And with that, that wraps up our questions for the episode. Thanks for coming on, Travis. This was a super fun conversation for me because I've basically been building almost the same things on the side. So it was really fun to connect on these topics.
Travis: Yeah, absolutely. Thank you so much for having me. It's been a pleasure.
Justin: Yeah, thanks, Travis. Great for having you on. Uh, you're working on really cool stuff. I'm really excited to see how OmniDoc evolves and restyle is really how I'm a radar of like interesting CSS solutions to check out. So, uh, yeah, great work.
Travis: Awesome. Thank you.
Discussion in the ATmosphere