DEV Community

Ramesh Vishnoi
Ramesh Vishnoi

Posted on

Mastering Project Maintainability with Module Resolver

Why you need Module Resolver?

Imagine working on a large-scale project containing numerous files such as components, screens, utils, etc.

Over time, the complexity of the project increases with multiple levels of imports. This eventually leads to a drop in developer productivity, making it difficult to onboard new developers. The impact is more pronounced on junior developers, who often get lost in the myriad of files.

Snapshot of project folder structure containing multiple folders, inner folders and files

With this project structure, importing components would look like this:

import Button from "../../components";
import Delete from "../../actions";
import utils from "../../utils";
Enter fullscreen mode Exit fullscreen mode

To tackle all of the above issues, we can use the Module Resolver Babel plugin. This plugin helps simplify and manage your import paths, making your project more organized and maintainable.

What is Module Resolver?

Module Resolver is tool or mechanisms to covert relative paths to aliases for your entire Javascript/Typescript project.

How to setup project to use Module Resolver?

If you are using JavaScript, then make the following changes in the jsconfig.json file or create a new jsconfig.json file. If you are using TypeScript, either modify the existing tsconfig.json file or create a new tsconfig.json file with the following code:

{
    "compilerOptions": {
      "jsx": "react",
      "baseUrl": "./",
      "paths": {
        "@myapp/components": ["./src/components"],
        "@myapp/actions": ["./src/actions"],
        "@myapp/screens": ["./src/screens"],
        "@constants": ["./src/constants"],
        "@utils": ["./src/utils"]
      }
    },
    "exclude": ["node_modules"]
} 
Enter fullscreen mode Exit fullscreen mode

After making this change, restart your IDE for it to take effect. You can also replace @myapp with your project name to personalize your project setup.

Here’s how you can do it:

*Metro Bundler (React/React Native)

If your project is using Metro Bundler, which is the default bundler for React and React Native setups, modify the metro.config.js file with the following code:

const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

/**
 * Metro configuration
 * https://reactnative.dev/docs/metro
 *
 * @type {import('metro-config').MetroConfig}
 */

const config = {
    resolver: {
        extraNodeModules: {
            "@myapp/components": `${__dirname}/src/components`,
            "@myapp/actions": `${__dirname}/src/actions`,
            "@myapp/screens": `${__dirname}/src/screens`,
            "@constants": `${__dirname}/src/constants`,
            "@utils": `${__dirname}/src/utils`
        }
    }
};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);
Enter fullscreen mode Exit fullscreen mode

*Babel

If your project is using Babel, you can use the babel-plugin-module-resolver to manage your module paths. First, install the plugin:

npm install --save-dev babel-plugin-module-resolver
Enter fullscreen mode Exit fullscreen mode

Then, update your babel.config.js file with the following code:

module.exports = {
  plugins: [
    [
      "module-resolver",
      {
        "root": ["./src"],
        "alias": {
          "@myapp/components": "./components",
          "@myapp/actions": "./actions",
          "@myapp/screens": "./screens",
          "@constants": "./constants",
          "@utils": "./utils"
        },
        "extensions": [".js", ".ios.js", ".android.js", ".json"]
      }
    ]
  ]
};

Enter fullscreen mode Exit fullscreen mode

* Webpack

If your project is using Webpack, you can configure it to resolve custom module paths by modifying the webpack.config.js file as follows:

module.exports = {
  resolve: {
    alias: {
      "@myapp/components": path.resolve(__dirname,"src/components"),
      "@myapp/actions": path.resolve(__dirname,"src/actions"),
      "@myapp/screens": path.resolve(__dirname,"src/screens"),
      "@constants": path.resolve(__dirname,"src/constants"),
      "@utils": path.resolve(__dirname,"src/utils")
    },
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
  },
};
Enter fullscreen mode Exit fullscreen mode

After module resolver changes, you can import like this:

import Button from "@myapp/components";
import Delete from "@myapp/actions";
import utils from "@constants";
Enter fullscreen mode Exit fullscreen mode

Feel free to tweak it according to your personal style or any additional points you might want to add!

Happy Coding!
Feel free to reach out to me on linkedin - https://www.linkedin.com/in/rameshvishnoi/

Top comments (0)