Skip to content
Dane Grant

AUTHOR

Dane Grant

Senior Software Engineer

JavaScript developer building things on web, native, and server environments. Free time filled with reading, cooking, dog, sports, comedy, and music.

Select...
Select...
Level up your REST API's with JSON Schema cover image

Level up your REST API's with JSON Schema

Explore JSON Schema, a powerful tool for ensuring data consistency and interoperability in REST APIs....

Building interactive forms with TanStack Form cover image

Building interactive forms with TanStack Form

Discover the power of TanStack Form, a new headless form library that simplifies building complex, interactive forms....

Deploying apps and services to AWS using AWS Copilot CLI cover image

Deploying apps and services to AWS using AWS Copilot CLI

Learn how to leverage AWS Copilot CLI, a tool that abstracts the complexities of infrastructure management, making the deployment and management of containerized applications on AWS an easy process...

Testing a Fastify app with the NodeJS test runner cover image

Testing a Fastify app with the NodeJS test runner

ant to simplify your testing process? Our new blog post on Node.js' built-in test runner is a great place to start. Learn how to test Fastify apps, including practical examples for testing an API server and SQL plugins....

Drizzle ORM: A performant and type-safe alternative to Prisma cover image

Drizzle ORM: A performant and type-safe alternative to Prisma

Introduction I’ve written an article about a similar, more well-known TypeScript ORM named Prisma in the past. While it is a fantastic library that I’ve used and have had success with personally, I noted a couple things in particular that I didn’t love about it. Specifically, how it handles relations with add-on queries and also its bulk that can slow down requests in Lambda and other similar serverless environments. Because of these reasons, I took notice of a newer player in the TypeScript ORM space named Drizzle pretty quickly. The first thing that I noticed about Drizzle and really liked is that even though they call it an ‘ORM’ it’s more of a type-safe query builder. It reminds me of a JS query builder library called ‘Knex’ that I used to use years ago. It also feels like the non-futuristic version of EdgeDB which is another technology that I’m pretty excited about, but committing to it still feels like a gamble at this stage in its development. In contrast to Prisma, Drizzle is a ‘thin TypeScript layer on top of SQL’. This by default should make it a better candidate for Lambda’s and other Serverless environments. It could also be a hard sell to Prisma regulars that are living their best life using the incredibly developer-friendly TypeScript API’s that it generates from their schema.prisma files. Fret not, despite its query-builder roots, Drizzle has some tricks up its sleeve. Let’s compare a common query example where we fetch a list of posts and all of it’s comments from the Drizzle docs: ` Sweet, it’s literally the same thing. Maybe not that hard of a sale after all. You will certainly find some differences in their APIs, but they are both well-designed and developer friendly in my opinion. The schema Similar to Prisma, you define a schema for your database in Drizzle. That’s pretty much where the similarities end. In Drizzle, you define your schema in TypeScript files. Instead of generating an API based off of this schema, Drizzle just infers the types for you, and uses them with their TypeScript API to give you all of the nice type completions and things we’re used to in TypeScript land. Here’s an example from the docs: ` I’ll admit, this feels a bit clunky compared to a Prisma schema definition. The trade-off for a lightweight TypeScript API to work with your database can be worth the up-front investment though. Migrations Migrations are an important piece of the puzzle when it comes to managing our applications databases. Database schemas change throughout the lifetime of an application, and the steps to accomplish these changes is a non-trivial problem. Prisma and other popular ORMs offer a CLI tool to manage and automate your migrations, and Drizzle is no different. After creating new migrations, all that is left to do is run them. Drizzle gives you the flexibility to run your migrations in any way you choose. The simplest of the bunch and the one that is recommended for development and prototyping is the drizzle-kit push command that is similar to the prisma db push command if you are familiar with it. You also have the option of running the .sql files directly or using the Drizzle API's migrate function to run them in your application code. Drizzle Kit is a companion CLI tool for managing migrations. Creating your migrations with drizzle-kit is as simple as updating your Drizzle schema. After making some changes to your schema, you run the drizzle-kit generate command and it will generate a migration in the form of a .sql file filled with the needed SQL commands to migrate your database from point a → point b. Performance When it comes to your database, performance is always an extremely important consideration. In my opinion this is the category that really sets Drizzle apart from similar competitors. SQL Focused Tools like Prisma have made sacrifices and trade-offs in their APIs in an attempt to be as database agnostic as possible. Drizzle gives itself an advantage by staying focused on similar SQL dialects. Serverless Environments Serverless environments are where you can expect the most impactful performance gains using Drizzle compared to Prisma. Prisma happens to have a lot of content that you can find on this topic specifically, but the problem stems from cold starts in certain serverless environments like AWS Lambda. With Drizzle being such a lightweight solution, the time required to load and execute a serverless function or Lambda will be much quicker than Prisma. Benchmarks You can find quite a few different open-sourced benchmarks of common database drivers and ORMs in JavaScript land. Drizzle maintains their own benchmarks on GitHub. You should always do your own due diligence when it comes to benchmarks and also consider the inputs and context. In Drizzle's own benchmarks, it’s orders of magnitudes faster when compared to Prisma or TypeORM, and it’s not far off from the performance you would achieve using the database drivers directly. This would make sense considering the API adds almost no overhead, and if you really want to achieve driver level performance, you can utilize the prepared statements API. Prepared Statements The prepared statements API in Drizzle allows you to pre-generate raw queries that get sent directly to the underlying database driver. This can have a very significant impact on performance, especially when it comes to larger, more complex queries. Prepared statements can also provide huge performance gains when used in serverless environments because they can be cached and reused. JOINs I mentioned at the beginning of this article that one of the things that bothered me about Prisma is the fact that fetching relations on queries generates additional sub queries instead of utilizing JOINs. SQL databases are relational, so using JOINs to include data from another table in your query is a core and fundamental part of how the technology is supposed to work. The Drizzle API has methods for every type of JOIN statement. Properly using JOINs instead of running a bunch of additional queries is an important way to get better performance out of your queries. This is a huge selling point of Drizzle for me personally. Other bells and whistles Drizzle Studio UIs for managing the contents of your database are all the rage these days. You’ve got Prisma Studio and EdgeDB UI to name a couple. It's no surprise that these are so popular. They provide a lot of value by letting you work with your database visually. Drizzle also offers Drizzle Studio and it’s pretty similar to Prisma Studio. Other notable features - Raw Queries - The ‘magic’ sql operator is available to write raw queries using template strings. - Transactions - Transactions are a very common and important feature in just about any database tools. It’s commonly used for seeding or if you need to write some other sort of manual migration script. - Schemas - Schemas are a feature specifically for Postgres and MySQL database dialects - Views -Views allow you to encapsulate the details of the structure of your tables, which might change as your application evolves, behind consistent interfaces. - Logging - There are some logging utilities included useful for debugging, benchmarking, and viewing generated queries. - Introspection - There are APIs for introspecting your database and tables - Zod schema generation - This feature is available in a companion package called drizzle-zod that will generate Zod schema’s based on your Drizzle tables Seeding At the time of this writing, I’m not aware of Drizzle offering any tools or specific advice on seeding your database. I assume this is because of how straightforward it is to handle this on your own. If I was building a new application I would probably provide a simple seed script in JS or TS and use a runtime like node to execute it. After that, you can easily add a command to your package.json and work it into your CI/CD setup or anything else. Conclusion Drizzle ORM is a performant and type-safe alternative to Prisma. While Prisma is a fantastic library, Drizzle offers some advantages such as a lightweight TypeScript API, a focus on SQL dialects, and the ability to use JOINs instead of generating additional sub queries. Drizzle also offers Drizzle Studio for managing the contents of your database visually, as well as other notable features such as raw queries, transactions, schemas, views, logging, introspection, and Zod schema generation. While Drizzle may require a bit more up-front investment in defining your schema, it can be worth it for the performance gains, especially in serverless environments....

State Management with React: Client State and Beyond cover image

State Management with React: Client State and Beyond

Introduction State management has long been a hotly debated subject in the React world. Best practices have continued to evolve, and there’s still a lot of confusion around the subject. In this article, we are going to dive into what tools we might want to use for solving common problems we face in modern web application development. There are different types of state and different types of ways to store and manage your application state. For example, you might have some local client state in a component that controls a dropdown, and you might also have a global store that contains authenticated user state. Aside from those typical examples, on some pages of your website, you might store some state in the URL. For quite a while, we’ve been leaning into global client state in single-page app land. This is what state management tools like Redux and other similar libraries help us out with. In this post, we will cover these different strategies in more detail so that we can try to make the best decisions going forward regarding state management in our applications. Local and global client state In this section, we'll discuss the differences between local and global client state, when to use each, and some popular libraries that can help you manage them effectively. When to use local client state Local client state is best suited for managing state that is specific to a single component or a small group of related components. Examples of local state include form inputs, component visibility, and UI element states like button toggles. Using local state keeps the component self-contained, making it easier to understand and maintain. In general, it's a good idea to start with local state and only use global state when you have a clear need for it. This can help keep your code simple and easy to understand. When to use global client state Global client state is useful when you have state that needs to be accessed by multiple unrelated components, or when the state is complex and would benefit from a more carefully designed API. Common examples of global state include user authentication, theme preferences, and application-wide settings. By centralizing this state, you can easily share it across the entire application, making it more efficient and consistent. If you’re building out a feature that has some very complex state requirements, this could also be a good case for using a “global” state management library. Truth is, you can still use one of these libraries to manage state that is actually localized to your feature. Most of these libraries support creating multiple stores. For example, if I was building a video chat client like Google Meets with a lot of different state values that are constantly changing, it might be a good idea to create a store to manage the state for a video call. Most state management libraries support more features than what you get out of the box with React, which can help design a clean and easy to reason about modules and APIs for scenarios where the state is complex. Popular libraries for global state management There are a lot of great libraries for managing state in React out there these days. I think deciding which might be best for you or your project is mostly a matter of preference. Redux and MobX are a couple of options that have been around for quite a long time. Redux has gained a reputation for being overly complex and requiring a lot of boilerplate code. The experience is actually much improved these days thanks to the Redux Toolkit library. MobX provides an easy-to-use API that revolves around reactive data/variables. These are both mature and battle-tested options that are always worth considering. Meta also has a state management named Recoil that provides a pretty easy-to-use API that revolves around the concept of atoms and selectors. I don’t see this library being used a ton in the wild, but I think it’s worth mentioning. A couple of the more popular new players on the block are named jotai and zustand. I think after the Redux hangover, these libraries showed up as a refreshing oasis of simplicity. Both of these libraries have grown a ton in popularity due to their small byte footprints and simple, straightforward APIs. Context is not evil The React Context API, like Redux, has also been stigmatized over the years to the point where many developers have their pitchforks out, declaring that you should never use it. We leaned on it for state management a bit too much for a while, and now it is a forbidden fruit. I really dislike these hard all-or-nothing stances though. We just need to be a little bit more considerate about when and where we choose to use it. Typically, React Context is best for storing, and making available global state that doesn’t change much. Some of the most common use cases are things like themes, authentication, localization, and user preferences. Contrary to popular belief, only components (and their children) that use that context (const context = useContext(someContext);) are re-rendered in the event of a state change, not all of the children below the context provider. Storing state in the URL The most underused and underrated tool in the web app state management tool belt is using the URL to store state. Storing state in the URL can be beneficial for several reasons, such as enabling users to bookmark and share application state, improving SEO, and simplifying navigation. The classic example for this is filters on an e-commerce website. A good user experience would be that the user can select some filters to show only the products that they are looking for and then be able to share that URL with a friend and them see the same exact results. Before you add some state to a page, I think it’s always worth considering the question: “Should I be able to set this state from the URL?”. Tools for managing URL state We typically have a couple of different tools available to use for managing URL state. Built-in browser APIs like the URL class and URLSearchParams. Both of these APIs allow you to easily parse out parts of a URL. Most often, you will store URL state in the parameters. In most React applications, you will typically have a routing library available to help with URL and route state management as well. React Router has multiple hooks and other APIs for managing URL state like useLocation that returns a parsed object of the current URL state. Keeping URL and application state in sync The tricky part of storing state in the URL is when you need to keep local application state in sync with the URL values. Let’s look at an example component with a simple name component that stores a piece of state called name. ` The general idea is to pull the initial value off of the URL when the component mounts and set the state value. After that, in our event handler, we make sure to update the URL state as well as our local React state. Moving state to the server Moving web application state to the server can be beneficial in several scenarios. For example, when you have a complex state that is difficult to manage on the client-side. By moving the state to the server, you can simplify the client-side code and reduce the amount of data that needs to be transferred between the client and server. This can be useful for applications that have a lot of business logic or complex data structures. In most cases if there’s some logic or other work that you can move off of your client web application and onto the server that is a win. Conclusion State management is a crucial aspect of building modern web applications with React. By understanding the different types of state and the tools available for managing them, you can make informed decisions about the best approach for your specific use case. Remember to consider local and global client state, URL-based state, and server-side state when designing your application's state management strategy....

Full-featured User Authentication Made Easy with Clerk cover image

Full-featured User Authentication Made Easy with Clerk

Intro Authentication is hard. It’s just another example of one of the things we deal with as web developers that can be solved in 100 different ways, and requires a well-thought-out decision. Thinking and decision making: my week in a nutshell. The first decision you need to make is whether you are going to roll your own authentication or use a third-party provider. If you decide to roll your own, you have a whole lot more thinking and decision-making ahead. There are a lot of considerations and specialized security-related knowledge required for this path if you intend to build an application that is secure. This post is going to cover a newer third-party provider option named Clerk. Clerk overview Clerk has been gaining popularity because it offers a fantastic developer experience. It comes with a first-class React integration that includes most of the popular React Frameworks. These integrations are powered by a full-featured, modern authentication service. Auth features Clerk offers an impressive array of authentication features that cater to a wide range of use cases and security requirements. Let's dive into these features and explore their benefits. - User management: Clerk provides a comprehensive user management system that allows you to easily manage and monitor user accounts, including registration, login, and profile updates. This saves you time and effort in building and maintaining a custom user management solution. - Organizations: The Organizations feature enables you to group users into separate entities, such as companies or teams. This is particularly useful for applications that require different levels of access or collaboration among various groups of users. With Clerk's Organizations, you can easily manage permissions, roles, and billing for each organization, streamlining your app's administrative tasks. - Email and SMS authentication: Clerk supports both email and SMS authentication, allowing users to securely authenticate using their preferred method. This flexibility enhances the user experience and helps to ensure that your application is accessible to a wider audience. - Password-less authentication: With Magic links and one-time passwords, Clerk offers password-less authentication options that eliminate the need for users to remember complex passwords. This not only improves the user experience, but also enhances security by reducing the risk of password-related attacks. - Social login: Clerk's Social login feature allows users to authenticate using their existing social media accounts, such as Google or Facebook. This simplifies the registration and login process for users, while also potentially increasing conversion rates for your application. - Multi-factor authentication (MFA): MFA adds an extra layer of security by requiring users to provide multiple forms of identification during the authentication process. With Clerk, you can easily enable MFA for your application, ensuring that your users' accounts are better protected against unauthorized access. - Multi-sessions: Clerk's multi-session feature allows users to be logged into multiple accounts simultaneously, similar to popular apps like Figma. This is particularly useful for users who need to switch between personal and work accounts frequently, providing a seamless and efficient user experience. - Device management: Device management is a powerful feature that allows users to view and manage all the devices they've used to access your application. This level of control is typically found in solutions provided by tech giants, and its inclusion in Clerk's feature set demonstrates their commitment to providing a robust and secure authentication experience. - Password leak protection: Clerk's password leak protection feature informs users if their password has been detected in a data breach. By proactively alerting users to potential security risks, this feature helps to protect your users' accounts and further sets Clerk apart from its competitors. Organizations, Multi-Sessions, and Device Management are features that really set Clerk apart from a lot of their competitors. If I’m working on a new application that requires any of these, I would be looking to Clerk as a top choice. React framework integrations Clerk’s React and NextJS integrations are extensive. I’m not going to do a walk-through on setting up a new React/NextJS app with Clerk because their website already offers a bunch of quick-start guides for many of the popular frameworks. Instead, we’ll just check out some of the important parts of their APIs that make it such a popular choice for React apps. They also offer support for React Native and Expo as well in case you’re planning on building a native application. The React API consists of pre-built components that can be directly imported into your application and a hook-based API. React Component API Clerk provides a set of pre-built components that can be directly imported into your React or Next.js application. These components are designed to handle common authentication tasks, such as sign-up, sign-in, and password reset forms. By using these pre-built components, you can save the time and effort of creating your own custom UI components for authentication. Some of the pre-built components include: - SignIn: A sign-in form that handles user authentication with email, password, or social login. - SignUp: A sign-up form that manages user registration with email, password, or social login. - UserButton: A button that displays the current user's profile picture and opens a dropdown menu with user-related actions. - UserMenu: A dropdown menu with user-related actions, such as signing out or account management. - UserProfile and OrganizationProfile: Easily display and manage user and organization information. - OrganizationSwitcher: Simplifies multi-tenant applications by allowing users to effortlessly switch between organizations and manage their memberships within your application. The component API comes equipped with themes that you can use out of the box to help match your website and also allow configuration for customizing the style even further. ` React Hooks API Clerk's React API also includes a set of hooks that allow you to interact with the authentication system programmatically. These hooks provide a simple and intuitive way to manage user authentication state and perform actions related to user accounts. Some of the hooks available in Clerk's React API include: - useClerk: Provides access to the Clerk instance, which allows you to interact with the Clerk API directly. - useUser: Returns the current user object, allowing you to access user data and monitor authentication state. - useSignUp: Provides methods for managing the sign-up process, such as creating new user accounts or handling social logins. - useSignIn: Offers methods for managing the sign-in process, including authenticating users with email, password, or social login. - useSession & useSessionList: The useSession hook provides access to the current user's active session object, allowing you to manage and monitor the user's session state within your application. In contrast, the useSessionList hook returns an array of all active sessions for the current user, enabling you to implement features like device management and session monitoring by displaying and controlling multiple sessions across different devices and browsers. - useOrganization & useOrganizationList: The useOrganization hook offers access to the organization object associated with the current user, enabling you to manage organization-related features and permissions, especially in multi-tenant applications. Meanwhile, the useOrganizationList hook returns an array of all organizations the current user is a member of, allowing you to implement features like organization switching, role management, and billing by managing and displaying multiple organizations or teams within your application. By using Clerk's pre-built components and hook-based API, integrating authentication into your React or Next.js application becomes a much more straightforward process by using these higher-level APIs. ClerkJS API Yes, Clerk’s React Component and Hooks APIs are really awesome, but you don’t need to be using React to take advantage of Clerk’s fantastic feature set. They do have a vanilla JavaScript API that can be used to implement your authentication using the Clerk in any client-side JavaScript environment or framework. It’s pretty similar to the React Hooks API with methods for sign-in, sign-out, user profile, sessions, and organization management. So even if you are not using React, you can still easily use Clerk for a great user and developer experience. Server-side APIs Their base server-side API client is pretty straightforward and includes methods for managing users and organizations. There are other backend APIs and features made available through the Backend HTTP API. The Node server API specifically includes a few more of these features. Clerk Node The Clerk NodeJS API has methods for managing clients, user invitations, sessions, users, and organizations. It also has methods for creating emails, SMS messages, and managing Allowlists. Clerk Backend API There’s quite a bit in their Backend API documentation so I’m not going to go over everything, but it’s good to know that it’s available if your backend is using a language that doesn’t yet have an API, or doesn’t include certain features. They also include some beta features that are available for use in this API. SAML Connections is an example of one of them at the time of this writing. Webhooks Webhooks are an essential aspect of Clerk's server-side integrations, allowing developers to receive real-time updates about authentication-related events. Clerk supports a variety of webhook events, such as user creation, user updates, and session events. By configuring webhooks, we can automate processes and integrate them with other services, like sending welcome emails, triggering notifications, or updating CRM systems. Serverless database integrations Clerk also has integrations with several different serverless database providers like Supabase and Hasura to name a couple. This is a really nice feature if you’re using a service like this that will allow you to secure access to your data. You can easily do things like only allow the original author user to edit a post, like when your app has some sort of social feed. Another common example might be just protecting certain queries from being ran without being authenticated as a user in your application. Conclusion It’s clear that the team over at Clerk has worked really hard to ship a really fantastic service for user authentication with some of the best APIs and integrations you could hope to find. It is a top-tier developer experience that allows you to ship user authentication and management to your app in literal hours without compromising on user experience along the way. They have 3 standard pricing tiers that include a very generous free tier that you can get pretty far on. If you’ve read this article and want to give it a hands-on tryout, I suggest jumping over to their quick-start guides page. There are a bunch of great guides here that quickly take your app from 0 to authenticated....

NextJS App Router - Examining the First RSC Implementation cover image

NextJS App Router - Examining the First RSC Implementation

What is the NextJS App Router and why is it important? Why are we talking about the NextJS App Router? What’s the big deal about another application router in the React ecosystem? On the surface level, it doesn’t seem that important or interesting, but it turns out that it’s not just another run-of-the-mill routing library. Until now, React has been a client-side library that concerned itself only with the view layer. It has avoided having opinions on just about everything that isn’t rendering your UI. But with React Server Components (RSC) on the horizon, it’s become more difficult for them to not have a concern with some of our other application layers like routing. If React is now going to have a hand in our server it’s going to need to be more integrated with our stack to be able to coordinate work from the server all the way back to the client side of the application. So what is the plan for this? Instead of shipping a router or an entire full-stack framework, they are going to provide an API that framework authors can integrate with to support Server Components and Suspense. This is the reason why the React team has been working closely with the NextJS team. They are figuring out the API’s that React will provide and what an implementation of it will look like. Queue drumroll… Meet the NextJS App Router. So the App Router isn’t just your grandpa’s router. It’s the reference implementation of an integration with the new RSC architecture. It’s also a LOT more than just a routing library. Glancing at the documentation page on the Next beta docs it appears to span across almost all concerns of the framework. It turns out there’s a lot of pieces involved to support the RSC puzzle. Pieces of the App Router puzzle On the getting started page of the NextJS beta documentation, there’s a summary list of features in the new App Router. Let’s take a look at some of the important pieces. Routing This seems like the most obvious one given the name “App Router”. The routing piece is extremely important to the RSC implementation. It’s still a file-based routing setup like we’re used to with NextJS with some new features like layouts, nested routing, loading states, and error handling. This is truly where the magic happens. The docs refer to it as “server-centric” routing. The routing happens on the server which allows for server-side data fetching and fetching RSC’s. But don’t worry, our application can still use client-side navigation to give it that familiar SPA feel. With nested routing, layouts, and partial rendering a navigation change and page render might only change a small part of the page. Loading states and error handling can be used to apply a temporary loading indicator or an error message nested in your layout to handle these different states. Rendering Since the App Router is RSC based, it needs to know how to render both client and server components. By default, App Router uses server components. Client components are opt-in by placing a use client directive at the top of a file. One of the main selling points of using RSCs is that you don’t have to ship JavaScript code for your RSCs in your client bundles. You can interleave server and client components in your component tree. Your pages and components can still be statically rendered at build time or you have the option for dynamic (server) rendering using either node or edge runtimes. Data Fetching One of the main selling points of RSC is being able to collocate your data-fetching with your components. Components are able to do data fetching using async/await using the fetch API. This will probably end up being a point of controversy since according to the documentation, both React, and NextJS “extend” the built-in fetch primitive to provide request deduping and caching/revalidation. The docs recommend that you do your data-fetching inside server components for several different reasons. Some of the main ones being: - Reducing client-side waterfalls. - Possible direct access to databases. - Aggregating your data-fetching in requests to a single server call (think GraphQL resolvers). This pattern is definitely becoming the norm in newer frameworks. These are similar benefits that you would reap when using something like data loaders in Remix. The big difference is that you will be able to do the fetching directly from your server components which is a nice win for co-location. Caching We touched on part of this in the Fetching section. It’s one of the reasons why NextJS is extending the fetch primitive. It’s adding support for caching your data using HTTP. If you’re used to client-side React, and tools like React Query, you can kind of think of this as the server version of that. If the data from a particular fetch request is already available in the cache, it will return right away, instead of making a trip to the origin server to get it. The other piece of the App Router caching story has to do with server components specifically. NextJS App Router stores the result of RSC payloads in an in-memory client-side cache. If a user is navigating around your application using client-side navigation, and encounters a route segment that they have visited previously, and is available in the cache, it will be served right away. This will help to provide a more instantaneous feel to certain page transitions. Tooling (bundler) We still haven’t covered the entire App Router, and RSC story because in order to support RSC, you need a bundler that understands the server component graph. This is where Vercel’s new Webpack replacement Turbopack comes into play. It’s built on a modern low-level language named Rust. This provides improved build times and hot-module-reloading (HMR) times in development, which is fantastic. Since it’s a Webpack replacement, it will be able to handle a lot of different concerns like styles, static files, etc. Goals of RSC and NextJS App Router In this Twitter thread, Vercel CEO Guillermo Rauch highlights what he believes NextJS App Router brings to User Experience. The first one is that less JavaScript code gets shipped to the client. I don’t think anyone is arguing that this is not a good thing at this point. He also mentions fast page/route transitions that feel more like a SPA, and being able to quickly stream and render above-the-fold content like a hero section while the rest of the page below finishes loading. I’ve heard a counter-argument from some RSC critics that aren’t as confident about these gains, and believe that RSC trades off UX for better DX (things like co-locating data fetching with components). Since RSC and NextJS App Router are still largely untested beta software, it’s really hard to say that this new, novel idea will be all that they are hyping it up to be. There’s a major paradigm shift currently occurring in the community though, and there are a lot of new frameworks popping up that are taking different approaches to solving the problems brought on by the proliferation of large client-side JavaScript applications. I, for one, am excited to see if React can once again push some new ideas forward that will really change how we go about building our web applications. Opening the black box I don’t know about you, but I feel like I’ve been hearing about RSC for a long time now, and it’s really just felt like this fictional thing. It's as if nobody knows what it is or how it works. Its secrets are locked away inside these experimental builds that have been released by the React team. NextJS 13 Beta has finally started to give us a glimpse behind the curtain to see that it is a tangible thing, and what it looks like in practice. I’ll be honest, up to this point, I haven’t been interested enough to dig for answers to the half-baked questions and ideas about it swimming in my mind. I know that I’m not the only one that has had this feeling. If you’re keen on learning more about what an RSC implementation looks like, there’s a good Tweet thread from Dan Abramov that highlights a lot of the important pieces and links to the relevant source code files. Some other really curious people have also embarked on a journey to see if they could create an RSC implementation similar to App Router using Vite. The repo is a great reference for understanding what’s involved, and how things work. What’s left? Even if it does feel like a lot of things have been happening behind the scenes, to their credit, NextJS has provided a beta version of the new App Router that is still experimental, and very much a work in progress. We can try out RSC today to get a feel for what it’s like, and how they work. On top of that, the NextJS documentation includes a nice roadmap of the pieces that are completed, and things that are still in progress or not quite fleshed out. As of the time of this writing, some of the major items on the list that look like blockers to a stable release are related to data fetching like use(fetch() and cache(). The most important one that I’m excited to see a solution for is mutations. They currently have a “temporary workaround” for mutations that basically involves re-running all of the data-loading in the component tree where the mutation happens. I think the plan is to have some sort of RPC built into the React core to handle mutations. Final thoughts It’s been a long time coming, but I for one am excited to see the progress and evolution of RSC through the new NextJS App Router. Since it’s still an experimental and incomplete product, I will wait before I do any real application development with it. But I will probably spend some time trying it out and getting more familiar with it before that day comes....

 E2E Testing Basics with Playwright cover image

E2E Testing Basics with Playwright

End-to-end (E2E) testing is a crucial piece of the application testing puzzle. E2E testing generally refers to testing your application as an entire system as opposed to testing it in small isolated pieces like unit tests. This post introduces Playwright, a powerful E2E testing framework that offers APIs in several different programming languages. Before we dive in, let's take a high-level look at some of its most noteworthy features. - Component testing - This post is specifically about E2E tests but being able to test your components in isolation with the same framework is a really nice feature. - Incredible flexibility - Headless and headed test modes - Multiple browsers (Chromium, Firefox, WebKit), and mobile device testing environments - API is available in several different languages - Single-page and multi-page app testing - Project config supports running particular sets of tests against specific browsers and environments - Multiple browser contexts - Useful for testing multiple sessions or user accounts simultaneously - Parallel test execution - Runs tests in parallel by default - Test Generation - You can interact with your web app UI in the headed Playwright browser and have it generate selectors and test code for you. We won’t touch on it in this article, but you can learn more about it here - Debugging - Has built-in support for debugging Playwright in Practice In this post, we will reference a fictional web application with authentication that includes user login and profile setup flows to illustrate how you can use Playwright to test an application. Here is the directory structure for our tests: ` Playwright configuration playwright.config.ts is where you can specify various options and features for your testing setup. The projects option is where things get really interesting. You can use projects to configure different sets of tests to run on different browsers and devices. We can add tags to our test description to target particular tests for specific projects. For example, we can tag particular tests with @firefox and configure a project that only runs it against the Firefox browser. This might be useful for testing against regressions for a browser specific bug. We are also able to match against file names. In the project config below, we are ignoring tests with .mobile in the filename in all of our projects except the one that is mobile-specific. Here are some reference pages for some of the features, and config options covered here: - https://playwright.dev/docs/test-configuration - https://playwright.dev/docs/test-projects - https://playwright.dev/docs/running-tests ` The webServer option allows specifying a web server for server-rendered and API servers. You can provide a command to start the server, and Playwright will wait for it to be ready before running your tests. Artifacts and Fixtures In addition to the models and specs directories, we also have an artifacts directory and a fixtures directory. The artifacts directory is used to store any artifacts generated during tests, such as screenshots or videos. Playwright can automatically take screenshots or videos of test runs, and these will be saved in the artifacts directory. The fixtures directory, on the other hand, contains any static data that might be needed during tests, such as images or data files. For example, in our auth-flow tests, we use an avatar image stored in the fixtures directory to simulate a user uploading an avatar image during the profile setup process. Selectors and Basic Test Writing In Playwright, we use selectors to target and interact with specific elements on a page. Playwright supports a wide range of selector engines, including CSS, XPath, and text-based selectors. You can also create custom selectors to suit your specific testing needs. When writing tests, we typically use the page.locator() method to target a specific element using a selector. For instance, you can use CSS selectors to target elements by their class, ID, or attributes. Here's an example that demonstrates how to use selectors to interact with a simple login form: ` In this example, we used CSS selectors to target the email and password input fields and a text-based selector to locate the login button. We can call methods, such as fill() and click(), that simulate user interactions and verify that the application behaves as expected. If you want to learn more on this topic, check out the writing tests page of the documentation. Page Object Models One pattern that Playwright recommends in its documentation is called Page Object Models. A page object model is a design pattern for organizing tests in a way that makes them more maintainable and encapsulates reusable logic. The basic idea is to define a set of classes that represent the pages and components of your web application, and then use these classes in your tests to interact with the application. For testing our applications, auth flows we might add a auth-flow.ts file. We can define an AuthFlow class that represents the authentication flow of our web application. This class encapsulates all the logic for requesting magic links, creating user accounts, and clicking links in the email sent to the user. By defining this class, we can write more readable and maintainable tests that use the AuthFlow class to perform the necessary actions. We accept a page argument in our constructor. This is a special argument that is always available in the browser context of our tests. It allows us to interact with the page via selectors and other easy to use APIs. There is a dedicated page in the documentation for this special object. ` Specs Finally, let's take a look at the specs directory. This directory contains the actual test files that use the AuthFlow class to perform the authentication and profile setup flows. new-user.spec.ts For example, the new-user.spec.ts file contains a test that verifies that a new user can complete the authentication flow, and be successfully redirected. In this example, we use the test.describe.serial test annotation to run the tests one after the other, since the second (sign-out) test depends on the user being logged in. (By default, Playwright runs as many tests as it can in parallel). We use test.beforeAll to run setup code (creating a magic link and user account) and test.afterAll to run any cleanup at the end of the tests. One of the first things you’ll notice is the callback functions that we pass to the Playwright test methods like beforeAll get called with an object argument that includes things like browser and baseURL. The browser object provides an API to the actual browser that our tests are running in, and we can use it to create and open new pages like we do in the first couple of lines of the beforeAll below. ` profile-setup.spec.ts Next, we have a profile-setup.spec.ts file that contains a test that verifies that the profile setup form can be filled out and changes can be successfully saved. Tests similar to this will be pretty common in most web applications. Luckily Playwright’s API and selectors make it pretty easy. We are able to test form accessibility here by trying both clicking and tabbing to the next fields. ` sign-in.spec.ts And finally, we have a sign-in.spec.ts file that contains a test that verifies that the sign-in modal can be opened and a magic link can be sent. ` Once you get familiar with the API, and the tools that Playwright makes available to you, writing tests for your application becomes pretty easy… and dare I say… fun? Summary There is so much more that we can cover when it comes to Playwright because it’s such a fantastic and powerful tool. Hopefully, this served as a good introduction to help you get started writing some basic E2E tests for your application. We covered some good ground after the intro by looking at some of the configuration options Playwright provides, and then writing some example tests for a fictional authentication flow. Our page object model implementation provided a nice abstraction for working with our app’s authentication mechanisms. Please keep in mind that this is not a prescription for how you need to write or structure your tests. The specific setup in this post is more to serve as a guide and a way to introduce some of the features and ways to start writing some tests. The most important part is that you can meet your application testing goals, and enjoy your time building out your tests!...

Exploring tRPC with Server-first UI Frameworks cover image

Exploring tRPC with Server-first UI Frameworks

If you’re a front-end engineer, you’re likely to see RPC (Remote Procedure Call) and new UI "meta-frameworks" popping up more and more, if you haven’t already....

Prisma TypeScript ORM: An Introduction and Exploration cover image

Prisma TypeScript ORM: An Introduction and Exploration

Introduction Prisma has been one of the most popular ORM tools in the JavaScript/TypeScript ecosystem for quite some time now. This is for pretty good reasons. There’s a lot to like about Prisma, but just like everything else it comes with it’s own set of trade-offs. When developing software applications you always want to pick the right tool for the job, especially when it comes to your database technologies. This post aims to provide a broad introduction to Prisma. I’ll highlight some of the things that it does well and point out certain things that it might not. In the end, the decision on whether or not you should use it is up to you. This post is a great starting point in your due diligence journey. Prisma from 1000ft What is Prisma? Prisma is a modern ORM that supports multiple SQL databases, MongoDB, and CockroachDB (with the help of an external package). It offers a range of features that make working with databases easier and more productive, including a CLI tool, schemas, a type-safe query builder, migrations, and a GUI for inspecting your database and schema. With Prisma, you define your database schema using Prisma's schema definition language (SDL), and Prisma generates a type-safe query builder API based on that schema. This means that you can write database operations in a more type-safe and developer-friendly way. This includes autocompletion, syntax highlighting, and error checking. How does it work? Prisma abstracts away the underlying database operations and provides a unified and consistent API for working with different databases (typically SQL based). This API builds up your SQL/Mongo queries for you, so you don't have to write them manually. Along with filtering, paginating, and sorting your data, the API allows you to specify the fields you want to be returned as well as any related data you want to fetch (similar to a JOIN operation in SQL). If you’ve ever tried writing raw SQL before, or using a database driver directly, you understand just how amazing this is. This makes it easier to write complex database operations, and reduces the likelihood of errors. It also drastically reduces the amount of code you need to write to have data that is ready to provide to any clients of your server application. Prisma in practice The last section was a bit of a teaser. Let’s get an idea of what this looks like in practice using a basic blog application as the premise for our example code. Here's the Prisma schema: ` In this schema, we have a one-to-many relationship between User and Post. A user can have many posts, but a post can only have one author. Based on this schema, you can perform common database operations using Prisma's query builder. Example queries: ` This is a really nice and friendly API in my opinion. But sometimes you need an escape hatch to drill back down to raw query operations. Prisma has that covered as well: ` Where does it shine? Type-safe query builder API One of the biggest advantages of Prisma is its type-safety when you are working within a TypeScript application. The API that Prisma provides is already easy to use, but the type completion and suggestions really make it shine. Easy seeding Prisma is also great for writing powerful seed scripts. Prisma's CLI tool allows you to easily write scripts that populate your database with sample data. Migrations Prisma's migrations tooling is particularly powerful and easy to use, allowing developers to make changes to their schema and keep their database up to date with minimal effort. Potential gotchas and trade-offs While Prisma is a powerful and versatile ORM, it does have some limitations and trade-offs. For example, some features and APIs are only available for certain databases. The API docs are pretty proactive about telling you when a particular feature is only supported by certain databases though. Another potential issue with Prisma is its performance. Depending on the requirements for your application and the complexity of your schema, this could be something you need to consider. While Prisma does make it easy to fetch related data from other tables in your queries, it doesn’t use traditional JOIN operation’s to do this. It runs additional queries for each relation included in your query. You can configure logging for the Prisma client to inspect what queries it’s running under the hood if you want more details on this. Additional reading and resources If you're considering Prisma for your project, the Concepts page is a great resource that covers a lot of material from a higher-level systems design standpoint. You can also check out this blog post that compares Prisma to other ORMs and query builders. There are some good open-source application examples that use Prisma. Examples like these can help you understand how to use Prisma in practice and see how it can be integrated with other tools and frameworks. - https://github.com/kentcdodds/kentcdodds.com - https://github.com/poulainv/tottem - https://github.com/calcom/cal.com There are also some full-stack frameworks that come integrated with Prisma like RedwoodJS and Blitz.js. With these frameworks, you can quickly get up and running with Prisma, and benefit from its features and capabilities without having to worry about integrating Prisma into your application manually. This can save you time and effort, and allow you to focus on building your application's features and functionality. Conclusion Prisma is a powerful and versatile ORM that offers a range of features that make working with databases easier and more productive. Its type-safe API and schema definition language can help you write database operations in a more developer-friendly way, while its CLI tool and GUI make it easier to manage your database and schema. However, Prisma also has some limitations and trade-offs, such as potential performance issues and database-specific features. When choosing a database and ORM for your project, it's important to consider your requirements and use case specifically. Is Prisma right for you? Ultimately, the decision is yours. But if you're looking for a quality and reliable ORM for your JavaScript or TypeScript project, Prisma is definitely worth considering....

Ship Less JavaScript with GraphQL Resolvers cover image

Ship Less JavaScript with GraphQL Resolvers

In this article, I want to highlight some ways that we can use GraphQL and tools like Apollo Server to reduce the amount of JavaScript that gets shipped in our bundles....