Written by jltechadminin Development

Solving Module Duplication Issues in Next.js with a React Submodule

A Surprisingly Simple Solution to a Complex Problem

In today's fast-paced tech industry, developers often find themselves using modern frameworks like Next.js in conjunction with other packages or submodules to enhance productivity and deliver powerful applications. However, despite the convenience, working with multiple libraries can sometimes present unique challenges. One such issue that developers frequently encounter is module duplication.

In a recent scenario, I was working on a Next.js project that incorporated a React submodule I was developing. I was hit with the hard reality of duplicate React module issues. This article aims to demystify how I resolved the module duplication problem using a few clever lines of code within the Webpack configuration.

Understanding the Problem: Duplicate React Modules

Unhandled Runtime Error
TypeError: Cannot read properties of null (reading 'useState')

Before we dive into the solution, let's quickly understand the problem. When incorporating a React submodule into a Next.js project, you might encounter an issue with two instances of React loading simultaneously. This happens because both the main project and the submodule have their own instances of React installed in their respective 'node_modules' directories. The problem arises when the code from your submodule tries to use its instance of React, while the rest of your Next.js project uses a different instance.

This situation leads to an infamous error: "Invalid hook call. Hooks can only be called inside of the body of a function component." This happens because React hooks expect to be working with a single instance of React. If there are two or more instances, hooks can't function correctly, causing our application to crash.

The Solution: Modifying the Webpack Configuration

Fortunately, Next.js allows us to customize the Webpack configuration and solve our problem. Here's the life-saving code snippet by updating next.config.js:


webpack: (config, options) => {
    if (options.isServer) {
      config.externals = ['react', ...config.externals];
    }

    config.resolve.alias['react'] = path.resolve(__dirname, '.', 'node_modules', 'react');

    return config;
},

So, what does this code do?

  1. The if (options.isServer) condition ensures that the following changes are only applied to the server-side build. The line config.externals = ['react', ...config.externals]; adds 'react' to the list of external dependencies for server-side builds. The term "externals" in Webpack terminology refers to modules that should not be bundled into the final bundle. By marking 'react' as an external, we're telling Webpack not to include React in the server-side bundle, hence preventing it from creating a separate instance.

  2. The next line, config.resolve.alias['react'] = path.resolve(__dirname, '.', 'node_modules', 'react');, provides an alias to the 'react' module. Here, we're essentially instructing Webpack to resolve all imports of 'react' to the specific version of React in our root 'node_modules' directory. This means whenever 'react' is imported anywhere in our application, it always refers to the same React instance, eliminating any duplication.

Conclusion

In a world where using various libraries, packages, and modules is the norm, encountering complexities like module duplication is not unusual. However, with a deep understanding of your tools and their configurations, you can devise clever solutions. Remember, the key lies in understanding the problem thoroughly before diving into the resolution. Happy coding!

Article Comments

Let’s Chat.

Are you ready to start your project? Maybe you have some questions? We’re here, let’s chat.