The Top 6 JavaScript Libraries to Avoid for Better DX in 2023

The Top 6 JavaScript Libraries to Avoid for Better DX in 2023
Photo by Leiada Krozjhen on Unsplash

Building websites and web applications is a complex endeavor. In 2023, using a library is pretty standard, those tools make developers life easier and work faster.

Some people might argue that everything could be simpler, that using a meta framework, code splitting and global edge network is overkill and things went south when JavaScript frameworks emerged.

There is some truth in the argument. However, the industry reality is that building a competent website is hard. It’s easier to find a job as a developer for companies that uses a framework than for one that have their own stuff.

This is why choosing the appropriate library for the job is critical. I already discussed this in a previous article that you can find here:

8 Amazing NextJS Libraries That Make Coding Easier
8 amazing NextJS libraries (with 4 bonus) that will make your life easier and your web application better!

Why Use a Library

Before diving into the list, let’s go through some reasons that make libraries useful. It won’t be long, since this is not the focus of this article.

  • First and most important, libraries offer a range of features that takes time and effort to build and maintain. Imagine building a website without the ease of components composition that React offers.
  • On a similar note, specialized libraries helps developers focus on the features that are part of the application and not features that are a consequence of the application. There is no need to build a complex date manipulation utility for an e-commerce website.
  • Third-party libraries are built by, well … third parties. This means that the efforts needed to maintain the code is offloaded to someone else. Developers won’t have to keep the old code up to date and will keep enhancing the application.
  • Finally, code needs to be tested. More written code means more tests to write. Popular libraries are tested and are working fine most of the time. Developers now have more time to test their code.

What Problem Libraries Bring

Of course, using libraries comes with some caveats. There are many cases where using a library is not possible or not recommended.

Security Issues

I have friends that work in the banking industry, and just having the thought of running npm install date-fnstrigger alerts. Using the code someone else wrote means exposing yourself to security vulnerabilities.

Developers will write bugs and potential security breaches. This is true for in-house code and code coming from a third party. However, companies have more control over the code that is written by their employees (hopefully).

Processes such as code reviews, code analysis, … are all there to make sure that the code reaching production is safe. Besides that, staged deployments are a way to expose as few customers as possible to a potential bug that hit prod.

Using a library has a huge impact on this whole security chain, and some teams or companies are not able to take the risk. This is the main reason libraries are not always the right answer.

Third Party Dependency

Having a third party added to the stakeholders of a project always comes at a cost. Security is a big one, but there is another one that is just as bad.

A third party could be compromised.

Downloading code from someone else from the internet contains many weak spots.

First, the developers could be corrupted (or coerced) to add some backdoors or some bugs. This can result in the whole application being vulnerable. If the library is popular enough, those changes should be cached by the community and rejected. Trust in the library would be however lost, and a fork might be created.

Second, the hosting platform could be forced to host malicious files without the developer’s notice. It could be possible that downloading a popular category from NPM results in a corrupted library that contains bad code. This kind of attack could be done only for a small number of users or even a few IP making the attack harder to detect.

Lastly, a sophisticated attack could make everybody thinks that the code downloaded is the one expected, when in reality they were changed with someone else during transport.

Some of those scenarios could look like a sci-fi movie, but it’s important to keep in mind that some people are building financial applications, code that runs on nuclear facilities or manage the whole HR department of Fortune 500 companies. Those high-value targets are at risk and face those kinds of attacks.

Limitations

Although real, I guess that most of you reading this article isn’t concerned by government espionage. You might face security and limitation risks.

This last point is a pain and is very hard to anticipate. Every project grows in complexity as it grows. This increase in complexity also means an increase in the features required from a library.

It’s all fun and games until the library cannot suit your needs.

Hitting those limitations can have a devastating impact on your application. In some cases, it’s possible to use a workaround or create a wrapper around the library to extend it. Although not perfect, this can work in some cases.

In other cases, reconsidering the library as a whole could be needed. I remember having issues with complex queries with the Firebase React library. This resulted in the whole company switching, for new projects, from No-SQL solution to SQL solutions such as Supabase.

Which library you should stop using

Now that we know when to use a library and what kind of trade off they bring, it’s time to discuss the libraries I no longer recommend using in 2023.

This list is highly suggestive and will change depending on whom you ask. However, some of the choices listed below are coming either from the developers themselves or from the community around the library.

React

Let’s make things clear, I’m not suggesting stopping learning React. React is the most popular JavaScript framework and is widely adopted by the industry.

However, I think that using React without a meta framework or with create-react-appis outdated and should be avoided for new projects. The new React documentation don’t even mention create-react-app in their quick start guide.

Start a New React Project – React
The library for web and native user interfaces

Meta frameworks such as Next.js or Remix (for example) offer everything React offers while adding some interesting features on top of them. Next.js allow developers to build a full-stack application that can scale and contain all the code in one project.

Using creact-react-app is getting less recommended for new projects, since alternatives such as Vite are more performant out of the box. create-react-appuses Webpack as bundler which was fine sometimes ago but is getting a bit outdated and could be replaced by Rollup or Parcel which are more modern and more performant.

This doesn’t mean that Webpack is bad, it’s still broadly used and enjoy the largest collection of extensions and documentation. Besides that, changing a bundler is a huge endeavor and could require a lot of work. Using the industry standard solution can be good while not being the most fun choice.

For a small side project, I would recommend either Next.js or Vite instead ofcreate-react-app. Those two options are also great if you’re stating a huge company project. Please do a POC before diving into either one of those solutions, since moving out of them could be an issue.

Moment

Moment JS was great. It was the best library to manage dates and offered a broad range of features.

However, the library is no longer recommended by the developers. There won’t be new development and the application is not optimized.

The developers give more reason why alternative should be used for new projects.

Moment.js | Docs

It’s crazy to think that despite the fact that the library is not recommended anymore, there are still more than 20 million weekly downloads.

Alternatives such as dayjs are drop-in replacement but are still struggling to surpass Moment. Other libraries that are much more powerful and pleasing to use such as date-fns aren’t reaching download levels of Moment.

If you’re still using Moment on your project, it’s time to move to something else. I would personally recommend dayjs that works quite nicely until you work with time zones (there are extensions, but it gets a bit harder to use). You can adopt it incrementally until you have completely removed Moment from your application.

However, if you’re starting from zero, please consider using the default JavaScript date. The API evolved quite a lot and can be sufficient for quite a lot of use cases.

If you need a date library, I would recommend date-fns. The methods are moderns and powerful. The library has a minimal impact on the bundle size and use default JavaScript dates.

dayjs

Let’s be clear, dayjs is a better choice than Moment. However, the API is similar to Moment. This means that things aren’t as pleasing to use as they could be.

The library is intended to be a replacement of Moment. This means that if you don’t need to use Moment you don’t need to use dayjs and use a more modern library is more suited for your needs.

As discussed before, I would avoid using a date library for a bit and try to use the built-in API. They evolved and are nicer to work with than it was in the past. The MDN documentation is excellent.

Date - JavaScript | MDN
JavaScript Date objects represent a single moment in time in a platform-independent format. Date objects encapsulate an integral number that represents milliseconds since the midnight at the beginning of January 1, 1970, UTC (the epoch).

If you don’t want to build helpers or have more advanced use cases, I would recommend date-fns which is amazing to work with. The team built many methods for a lot of use cases.

The following code snippet shows some of the methods that are available with date-fns. It’s quite concise and powerful!

// If today, the hour is rounded to the nearest half hour
const minTime = isToday(date) ? roundToNearestMinutes(currentDate, { nearestTo: 30 }) : startOfToday();

// Difference between the end of the hour of a date and the start of the current date
const hoursDiff = differenceInHours(endOfHour(expirationDate), startOfHour(new Date()));

Subscribe to the newsletter to get new articles right in your inbox!

Subscribe to the newsletter

Redux

State management is a vast topic and many solutions exist. There are some that are inspired by Flux (like Redux), others that are atomic (like Zustand or Jotai) or state machines (like XState).

Redux is (or was) one of the most popular state management libraries in the past. It was also one of the first ones to release in 2015.

The quality of the Redux Library and the quick start guide is excellent. The library is quite competent and can handle the server side and client side state. Besides that, the RTQ query helps manage cache and make optimist UI changes.

Redux is excellent, but why don’t I recommend it for most developers? It’s simple, Redux is verbose and overkill for most of the projects.

There are a lot of tutorials online (less in the last few years) that recommended Redux as a default state management library, and that’s a bad suggestion.

Redux is great when building a large application where multiple team are working together. Each team is responsible for its part of the state (its slice) but still can use other team state.

However, when building a small project, Redux is way overkill and will slow you down. Dan Abramov, one of Redux creator, even wrote an article that discourages using Redux in projects.

You Might Not Need Redux
People often choose Redux before they need it. “What if our app doesn’t scale without it?” Later, developers frown at the indirection Redux…

There are many alternatives that are faster and easier to implement and maintain. If working with remote cache (such as most web applications), libraries like React Query are quite great.

If the application gets bigger, Zustand is also a great choice. But there might be some features that are harder to implement or require some hacking.

The graph above highlight how Redux is still dominating the state management libraries. Downloads are not perfect metric, but is can still indicate if a library is popular or not.

Alternative to Redux such as Zustand, React Query are getting more traction where newcomer such as Jotai struggle to get wider adoption.

Zustand

I know I just recommended Zustand, and it’s on my list of non-recommended libraries. This is because, in many cases, a state management library is not always required.

Let’s imagine an application that lets you organize your next holidays. You can then share this plan with friends, so they can have a look at the planned activities.

In its essence, the application is a form. You log in and you can then edit the activities. You perform simple CRUD operation that requires authentication.

This kind of use case is quite common when working with web applications. I don’t think that a Zustand or any other atomic state management library is required.

Instead, I would recommend using a combination of React context (to manage authentication) and a remote cache library such as React Query.

Using an atomic state means fetching the data, storing it temporarily in a local state and send it back once edited. The local state step is not required and could be removed by using a remote cache solution.

Remote cache is a term I came up with when referring to libraries that help manage CRUD operation on remote data. Those libraries (such as React Query) fetches, caches, mutate and invalidate the data while making the data available on your whole application.

That’s where React Query shines. It stores in a key-value pair shared store the fetched values. You can then edit the value and update values on the server.

Besides that, it helps build optimistic UIs where the application interface is updated before the server did the change. We simply assume that the fetch request will resolve and revert to an older state if that’s not the case.

Those mechanism helps build snappier applications that feel like all the data is stored locally when everything is in fact remote. The following diagram shows how optimistic UI updates work when the request resolve and when it fails.

On the left, an update that resolve and on the right one with an error that falls back to the initial state after the failure

Two libraries are the main players in this area. React Query created by Tanner Linsley and SWR developed by Vercel. Out of the two, React Query is most powerful and popular.

json-object-mapper

This one is a strange one and most of the people won’t know about it. json-object-mapper will serialize and deserialize a JSON blob to a TypeScript object.

It’s only downloaded 2000 times a week, do not make a very used library. So why bother presenting it? Well, there might be other libraries I’m not aware of that solve the same issue that is parsing JSON to a valid and save TypeScript object.

Developers can create their own class and make constructors that will validate the data coming from a server. This is fine and still better than json-object-mapper that reduce performances and is limited when it comes to more complex data such as nested objects or dates.

Creating classes and constructors works fine for sometimes, but can still be tedious and requires quite a lot of code, depending on the complexity of your models.

Instead, you should use Zod which is a tiny and amazing library that makes data parsing a breeze. In its essence, Zod is a schema validation library that will make sure that the provided data is how it should be.

You can see in the following example how schema are defined and how data can be parsed after a request. You are sure, after that, that the data you work with is exactly how it should be.

export const userParse = z.object({
  id: z.string(),
  firstName: z.string().nullable(), // means string | null
  lastName: z.string().nullable(), // means string | null
  age: z.string().optional(), // means string | undefined
  email: z.string().email(), // makes sure this is an email
  role: z.enum(["user", "admin"]),
  favorites: z.string().array(),
});

//Can be used throughout the app as type
export type User = z.infer<typeof userParse>;

const getAllUsers = async (): Promise<User[] | null> => {
  try {
    const data = await usersCollection.get();
    return data.docs.map((doc) => FAQZod.parse({ ...doc.data(), id: doc.id }));
  } catch (e) {
    // handle errors
  }
  return null;
};

Using Zod seems mandatory, it’s faster and easier to maintain than classes, and you don’t rely on less optimal solutions to parse your data.

Wrap up

In this article, I presented 6 libraries I wouldn’t recommend for new projects in 2023. Those recommendations are highly personal and are to be considered with a pinch of salt.

Some recommendations are made because of security concern or lack of support. That’s the case for Moment that could be replaced by date-fns or dayjs (if you want to migrate out of Moment) for example.

Other libraries don’t fall under my set of rules that I follow when deciding to choose a new library. json-object-mapper is an example and shouldn’t be used at all, zod is better. You can find the set of rules in this article:

How to Choose the Best JavaScript Library for Your React and Next Project?
Choosing a bad library can create huge issues in the future. Here are 6 steps that will help you choose the most appropriate library.

Other libraries are fine, but could be replaced by something more adapted or more performant. Again, date-fns could replace either moment or dayjs. Zustand is a better (and lighter) alternative to Redux. However, state management libraries could be replaced altogether with a library that better manage remote cache such as React Query and the React Context (for authentication for example).

That’s all the recommendations I had! I hope that you found them useful and that you discovered new tools to make your code better!