Improving Developer Happiness with Preview.js

Rate this content
Bookmark

A look into Preview.js, an open-source extension for Visual Studio Code, IntelliJ and WebStorm that lets you preview individual React components instantly, updated as you type.


21 min
21 Jun, 2022

Video Summary and Transcription

Francois, a developer happiness engineer, discusses the challenges of slow builds and their impact on productivity. He explores the implementation of showing unavailable menu items in a food delivery app and demonstrates the use of Storybook for component design. Francois introduces Preview.js, a tool for previewing React, Vue, and Solid components, and explains how it simplifies the development process. He also highlights the benefits of using PrivyJS with Storybook and VIT for faster and more efficient development.

Available in Español

1. Introduction to Developer Happiness Engineering

Short description:

Hi, I'm Francois, a developer happiness engineer. I work on refactoring, fixing tests, and creating tools to make engineers faster. Today, I'll talk about Preview JS and the challenges of slow builds and its impact on productivity.

Hi, my name is Francois. I'm a developer happiness engineer from Sydney, Australia. You might be wondering, what is a developer happiness engineer? What it means is that I'm a regular software engineer who likes to work on refactoring stuff or fixing flaky tests, or making CI faster, but sometimes it's also about creating new tools to make other engineers faster.

So one of these tools is called Preview JS, and I'm going to be talking about that now. You might be familiar with this XKCD comic. I think it was thrown quite a while ago, but it's still somewhat relevant today. I'll give you a few seconds to read through it.

So this, I think, was especially relevant back in the days of a lot of programmers using C++ or some other really, really slow language, where you had to wait for five minutes, maybe 10 minutes, maybe even an hour for your code to recompile. It's not that relevant today for JavaScript, or is it? It's actually not that uncommon these days to work on a large codebase that uses maybe an old version of Webpack or a misconfigured version of Webpack, that takes a couple of minutes to run the build. Maybe even worse, maybe you have to wait 30 seconds every single time you make a change to the file, which is, if you think about it, when you add that up over a day every single time you want to see the impact of a code change you made, that's quite a while just spent And not only is it waiting, but also breaks your flow, so you're usually going to switch context, going to start doing something else and then you go back and it's just, you kind of lost track of what you were trying to do or whatever was in your mind is just kind of not there anymore. And it's not very good for productivity or for engineering happiness.

2. Handling Unavailable Menu Items

Short description:

Let's take the example of a food delivery app called Humbry. Users have provided feedback that they are surprised when the menu doesn't contain expected items. Currently, if an item is unavailable, it is completely removed from the menu. However, the app designers have received a feature request to show unavailable items but make it clear that they are not available. The first way to implement this is by running the app locally.

So let's take this example, this is a food delivery app that I called Humbry and it's really just for the purpose of this presentation. So here we have a bunch of restaurants and let's say I feel like some French crepes, so I'm going to say crepes.

Okay, there's a restaurant called Crêperie François and I'm going to go there and check out. Okay. So there are some really yummy things, caramelized banana and chocolate. That sounds good. Fresh and candied orange. Okay. That sounds good. Okay. That sounds good. Okay. That too. Okay. I'm going to get everything, maybe two of each. Cool. Great. This is pretty much what you would expect from a delivery food app. And we're in the early days of releasing that to users.

And the first piece of feedback that we get is that some users are surprised that sometimes the menu doesn't contain the items that they expected. So that's because sometimes if an item is unavailable, right now the API just removes it from the menu. So let's say this restaurant ran out of chicken. This first item, Kung Pao chicken, will actually be missing entirely. Which surprises users, because they're like, well, did this restaurant remove this from the menu forever? Should I just completely boycott this restaurant because they removed my favorite item? No, that's not the case. It's just unavailable today. And really that's our responsibility as designers of this app, to make it clear.

So instead, we get a feature request from our product manager, which says, now we should still show unavailable menu items, but just make it clear that they're not available. So you know how here we have this counter, instead of this counter, we'll just say, unavailable today, right? This should be a lot less confusing for users. Of course, the first way that we can implement this is by just running the app locally. Right? So we're going to go to our terminal, run Yarn Dev, and wait a little bit.

3. Modifying API and Code for Unavailable Menu Items

Short description:

I'm running the app locally and waiting for it to spin up. I need to find a restaurant with an unavailable menu item, but the API doesn't return unavailable items. I can either change the API to return them or mock it up in my code base. I'll modify the code to mark a menu item as unavailable and update the component to display it as such.

Okay, so it's running at local host, cool. I do need to wait a little bit for this to spin up. I'm actually not entirely sure why, but it's something in here that takes quite a while. This is exactly what I meant by spending the time that you spend waiting. Like I might just go on Twitter and completely forget about this and go back here and just maybe have to wait again because I need to reload the page or something.

Okay, cool. So that's our app. It's running. Now I need to find a restaurant that has a menu item that is not currently available, so I'm going to go through and try to find one. But wait, I said earlier that the API actually does not return menu items that are not available, so that's not going to work. All of them are by definition available because they're returned by the API. So I have a couple of ways to approach this. One is if I'm myself an engineer who works on the API, then I might change the API to return unavailable items, although I have to be careful not to return them to versions of the app that don't support that yet. Or if I don't know anything about the API, I'm going to have to mock it up. I'm going to go into my code base, and find... Okay, so it's the restaurant page... Oops, restaurant page, and I'm going to go into that. Okay, so that's using this restaurant details page state, which is a MobX state. At the end of the day, all it does is fetch. Okay, so it's fetching that, it's getting the data, it's restaurant details response. Cool. At least this is well-typed. And that returns a menu item, and menu item has an available which is an optional Boolean.

Okay, so I'm gonna hack this up and say, data.menu.zero.unavailable equals true. And I'm gonna go back to here. And so, this first one, because number zero should be unavailable, but of course we haven't implemented this, so right now, it still shows the counter. And now, I do know that this component is called restaurant menu item, so I'm gonna go in here and say... Okay, so here, instead of the counter, we want to say that if unavailable, then we show unavailable instead. So, menu unavailable, unavailable. Cool.

4. Running the App Locally and Using Storybook

Short description:

Nice. Cool, done. Running the app locally is a lot of times the right solution. Option two, we could use Storybook. It's pretty much a gallery app for all of your UI components. Each story is a specific version of your components.

Nice. Cool, done. That's it. Now, of course, I need to remember to remove this because if I don't remove this, it's gonna break the experience for users, but other than that, we're done.

So, luckily, this is a pretty nice good base to work with. Thank you Next.js. And yeah, we're pretty much done.

So, running the app locally is a lot of times the right solution, right? It's super straightforward. It doesn't require any additional setup. The only thing is that mocking data can be hard depending on what is the specific use case that you're working with. And iteration speed can be slow, again, only if you're working on a really complex code base or something that is not very well configured. But that's more common than you would think.

Option two, we could use Storybook. In case you're not familiar with Storybook already, it's pretty much a gallery app for all of your UI components. It's called Storybook because you define stories for your components. Each story is a specific version of your components. So in our case, for example, we have the unavailable story and we have the available story.

So let me show you what that means. I'm going to go in here and run your Storybook. And this can take a while depending on how many components you have. Okay. In this case, very fast, cool. And you can see, okay, we have this counter story. We have the no match story, the restaurant header story, restaurant list, and so on and so on. So what we're interested in here is restaurant menu item where we have two different stories, default and picked. So you can see that when it's picked and there's already a counter created. And I can go back in here and let me show you how that's implemented. So we have this file next to restaurant menu item, which is the restaurant menu item to the stories. And it has a little bit of boiler plate for storybook. And then each story is this.

5. Creating a Story for Unavailable Menu Item

Short description:

We define args for stories, such as default and picked. We want to create a new story called unavailable with an unavailable menu item. After simulating the experience, we revert the change to try another approach.

So we have args that we define for story. So here we have two stories, default and picked. And default and picked are here. So you can see the difference is with the args that we pass, which are pretty much the props. So our case, we want to create a new story called unavailable with a menu item that is of course unavailable. Oops, forgot a comma, available, true. That's pretty, okay. And now it should appear. Okay, perfect. We have it here. But of course we haven't reverted the change already. So let's do that again. Just simulating the experience from scratch, menu item.unavailable, unavailable. Okay, perfect. And it updated pretty quickly which is great. And let me revert that again because we're going to do this again yet another way.

6. Benefits of Storybook for Component Design

Short description:

The nice thing with Storybook is that it encourages a good design, not just from a UX design perspective, but also from a software design perspective. It pushes you to create dumb components that are agnostic of the state, making them easy to test and reuse across code bases.

Cool. The nice thing with Storybook is that it encourages a good design, not just from a UX design perspective, but also from a software design perspective. So because you want stories for each of your components, you need to think about what components you want in the first place and how you want them to be designed in terms of props that it takes, etc. And the way that Storybook structures stories kind of means that you are kind of pushed in the direction of creating dumb components that are kind of agnostic of the state, so they're not capable to redux or anything like that. And usually that's a pretty good thing because it means that your components are really easy to test, really easy to reuse as well across code bases, so lots of good things there.

7. Preview.js for React, Vue, and Solid

Short description:

Storybook acts as documentation and allows you to preview components. Option three is to have a preview for React components like markdown previews. I couldn't find a suitable solution, so I built Preview.js. Preview.js works with React, Vue, and Solid, and is available on VS Code and IntelliJ.

It also acts as documentation, which again, is super useful, so for, if you want to say, tell your UX designer, hey, I have this component that is currently in this particular implementation, you can check it out at this URL. That's really super useful and reconciling that versus the box that your designer is working with. It can be a little bit slow to spin up in that it depends on how many components you have, and really is something that a storybook team is working on improving anyway, so it's not really something I would worry about too much.

It does require a little bit of boilerplate, so we saw that you really can only look at components that have stories defined for them, so first you need to define the stories. If you find a component and you're wondering what it looks like and there's no story for it, you're going to have to write a story first.

Cool. Is there an option three? You know how when you write markdown in your ID, let's say in VS Code, you can actually see a preview of it. Let me show you. Let's create a readme and say, hello world. I'm on a max. I'm going to press command K and V, I think. Yep. Just going to say this is instantly updated with a nice preview. Now I can see this is pretty cool. Cool. So what if we had something like that, but for React components. And I kept looking for that, but I never could quite find the right solution. There were a couple of contenders, but the problem is that they only work with components that don't take any props or that are like super, super simple. So I decided to build it. And it's called Preview.js. It was actually earlier called React Preview. Because it was for React components. But then I realized that it could also work with other frameworks like Vue and Solid. So I renamed it to Preview.js. And also in the process, pretty much all of it. So Preview.js works with React, Vue 2, Vue 3, and Solid. It's available on VS Code and IntelliJ. So let's look at what Preview.js looks like. Let's go back to VS Code. We have our Restaurant Menu item here, which I reverted back to the previous state.

8. Previewing Restaurant Menu Item in Preview.js

Short description:

I can see a preview of the open Restaurant Menu item in Preview.js without writing any code. It automatically generates a valid value based on the props and type of menu item.

And I'm going to here have this button, open Restaurant Menu item in Preview.js. So I'm going to click on that. And oh, proof! That's pretty cool, okay. So I can see a preview of that. And I, again, did not have to write any code for this. This is just out of the box. Basically, what it did is it looked at the props of this. It's, so, oh, okay. This specific, first, this is a React component, and therefore I can't show this thing. But also, it says, okay, that takes menu item count on update. And it can actually look at the type of menu item and kind of generate a valid value for it. Well, this, as much as it can guess.

9. Implementing the Unavailable State

Short description:

Let's make it more realistic by implementing the unavailable state. I provide an example value and instantly see the live updates. With instant feedback, I make it prettier with padding, rounded corners, drop shadow, and a red border. Despite the typos, it's cool.

So here, let's make it a little bit more realistic. So let's say brownies. And let's use cute kitten pictures. Although we're not gonna eat the kitten. So, yep, this is really just for illustration. And now, this is a little bit more realistic. Now, we want to implement the unavailable state.

So what I'm gonna do is provide an example value. Okay, unavailable true. And now, I should be able to see what it looks like. So, div unavailable. Oh, cool. That actually updates live. That's pretty cool. And I'm gonna make it prettier, then, given I have instant feedback. That's pretty cool. Okay. A bit of padding, maybe rounded corners. Yep. Maybe a drop shadow. Drop shadow, yep, cool. Maybe a border, as well. Border 2, border red. Oops, sorry. Typos, lots of typos. Okay. That's what you get for recording a presentation at 11 pm. Okay. Yep, one more typo. Okay, cool.

10. Using PrivyJS with Storybook and VIT

Short description:

I keep pressing save when I actually don't even need to save because PrivyJS doesn't require you to save. PrivyJS works well with Storybook. They don't compete with each other. PrivyJS is possible thanks to VIT, which is faster and simpler than Webpack. Use VIT.

I keep pressing save when I actually don't even need to save because PrivyJS doesn't require you to save. Okay, so that's pretty cool. Okay, unavailable right now. Okay. How does it look when I make it wider? Okay, cool. That's fine. Okay, maybe just unavailable. Okay, cool. Done. That's PrivyJS in a gist.

Now, you might wonder if you use PrivyJS should you still be using Storybook? And the answer is yes. Storybook is pretty much still a great tool for documenting your components and making sure that you have documented every variant of it. In fact, PrivyJS actually supports displaying your stories. If I go into restaurant menu item stories, you can see that I see the same preview link for each of the stories, and I can see them like that, which is perfect. I can also look at the restaurant header, all these different things. So if you're just exploring a code base that uses Storybook and you use PrivyJS, you have it set up, you probably don't even need to spin up Storybook. And this would probably be a lot faster to just use that instead. Just like that.

In a future version of PrivyJS that I'm hoping to release in June or July, there will actually be also a feature to save your props as a new story. Although I'm probably going to make that part of the PrivyJS Pro version, which is paid, just because at the end of the day I would like to be able to make a little bit of money from that so I can spend all my time working on PrivyJS as opposed to having to squeeze that in my free time. But that's the gist. PrivyJS works really well with Storybook. You can use both. They don't compete with each other. PrivyJS is only possible thanks to a couple of recent web tooling innovations, especially one called VIT, which is pretty much an alternative to Webpack that is significantly simpler to set up and as well, significantly faster. Your developer experience with VIT is that you update a file and within literally milliseconds, it will update. That's why PrivyJS is able to do Privy as you type. The only reason that's possible is because it uses VIT under the hood. If you want to take one thing out of this talk, aside from use PrivyJS, of course, it's use VIT. Try it out.

11. Setting Up PrivyJS and Configuring Components

Short description:

PrivyJS is easy to set up and can save you many hours per week. Use Visual Studio Code as the compatible IDE and configure a wrapper component to display your components properly. Make sure to import styles.globals.css for a better appearance. If you encounter bugs, report them on GitHub. Visit PrivyJS.com for more information and follow me on Twitter for feedback.

It's easier to set up than you would think, and it might save you literally many, many hours per week. If you want to set up PrivyJS with your project, there are a couple of steps to go through. To be honest, right now, it's not the smoothest experience, unfortunately. Unless you use Create React App or something super simple, in which case it should hopefully just work out of the box.

The first thing is make sure that you use an IDE that is compatible, so either Visual Studio Code or IntelliJ slash WebStorm. If you are not sure which one to use, use Visual Studio Code because the IntelliJ version is kind of buggy, to be honest. Working on that.

And then the next thing is you have to configure it to display your components properly, because by default, what PreviewJS will do is just display the component in a completely empty app, which is not exactly perfect. If, for example, you need some global CSS to be there. The way that you do that is by configuring a wrapper component. And let me show you what that looks like in my hungry app. It's here previewjs.wrapper.tsx, and that's pretty much all the config that we have. That's it, that's all the config. The important thing here is this import styles.globals.css. Without this, it would look super ugly, so let me just show you what I mean. Okay, so I have this, and I'm gonna remove that just for fun. And it's gonna be, yep, really broken. Because, of course, in globals or TSS, in this case, I have all of Tailwind set up. And I also have a wrapper that sets up a screen container, so I'm just adding a little bit of margin to make it prettier. But you might, for example, need to set some react context, some, you know, initialize your redux state, or whatever else you need. And if you use aliases, you know, import aliases, you might also need a couple of lines of config as well.

As I mentioned earlier, PrivyJS is quite new, it just came out in January. So, if you run into any bugs, please consider reporting them on GitHub. I'd really appreciate that. I'm expecting after this talk maybe a couple of hundred bug reports. Hopefully not that many. Go to PrivyJS.com if you want to check it out. If you're on Twitter, you can follow me and share your feedback. I really hope that PrivyJS can make your daily workflow a little bit better and a little bit faster.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

JSNation 2023JSNation 2023
29 min
Modern Web Debugging
Few developers enjoy debugging, and debugging can be complex for modern web apps because of the multiple frameworks, languages, and libraries used. But, developer tools have come a long way in making the process easier. In this talk, Jecelyn will dig into the modern state of debugging, improvements in DevTools, and how you can use them to reliably debug your apps.
JSNation 2022JSNation 2022
21 min
The Future of Performance Tooling
Top Content
Our understanding of performance & user-experience has heavily evolved over the years. Web Developer Tooling needs to similarly evolve to make sure it is user-centric, actionable and contextual where modern experiences are concerned. In this talk, Addy will walk you through Chrome and others have been thinking about this problem and what updates they've been making to performance tools to lower the friction for building great experiences on the web.
DevOps.js Conf 2022DevOps.js Conf 2022
31 min
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
You will learn about one of the most popular package managers for JavaScript and its advantages over npm and Yarn.A brief history of JavaScript package managersThe isolated node_modules structure created pnpmWhat makes pnpm so fastWhat makes pnpm disk space efficientMonorepo supportManaging Node.js versions with pnpm
GraphQL Galaxy 2022GraphQL Galaxy 2022
31 min
Your GraphQL Groove
Building with GraphQL for the first time can be anywhere between daunting and easy-peasy. Understanding which features to look for in your client-side and server-side tooling and getting into the right habits (and ridding yourself of old habits) is the key to succeed with a team of any size in GraphQL.

This talk gives an overview of common struggles I've seen numerous teams have when building with GraphQL, how they got around common sources of frustration, and the mindset they eventually adopted, and lessons learned, so you can confidently stick with and adopt GraphQL!

Workshops on related topic

React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
React Advanced Conference 2021React Advanced Conference 2021
168 min
How to create editor experiences your team will love
Workshop
Content is a crucial part of what you build on the web. Modern web technologies brings a lot to the developer experience in terms of building content-driven sites, but how can we improve things for editors and content creators? In this workshop you’ll learn how use Sanity.io to approach structured content modeling, and how to build, iterate, and configure your own CMS to unify data models with efficient and delightful editor experiences. It’s intended for web developers who want to deliver better content experiences for their content teams and clients.