Fixing import path hell (React Native, ESLint, VS Code)

Jun 11, 2019

I see several advantages to getting rid of the import path hell:

  • Easier to move files around (inner file imports relative to project root)
  • Easier to refactor import paths (think “Find & Replace”)
  • Easier to locate a file (mental model)

That said, it should not come at the cost of a lesser Developer experience. If aliasing a folder breaks an ESLint rule and/or prevents code navigation (“Go to definition”), it’s a no go.

Let’s see how to setup a complete folder aliasing solution.

Metro bundler

The React Native metro bundler comes with a nice little feature that allows you to alias sub-folders.

Given this app file structure:

tree -d ./src/

./src/
├── config
├── services
├── views
│   └── atoms

Adding a simple package.json inside the src folder:

// ./src/package.json

{
    "name": "app"
}

Will allow you to import files relative to the chosen “app” alias:

import Config from 'app/config';

import Api from 'app/services/api';

import Button from 'app/views/atoms/button';

Source: https://www.belighted.com/blog/react-and-react-native-directories-management

VS Code

Now we need to tell VS Code (IntelliSense) how to resolve those aliased paths.

// ./jsconfig.json

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "app/*": ["./src/*"]
        }
    }
}

ESLint

One of the most useful & helpful ESLint plugin that I came across is eslint-plugin-import.

eslint-import-resolver-node

In my example, I decided to alias the src folder “app”. If I had decided to go for the simpler case and alias my src folder “src”, I could have used the standard eslint-import-resolver-node resolver.

And I would simply have to tell this resolver where to load the “Node modules” from, adding the app root folder as another moduleDirectory:

# ./.eslintrc.yaml

settings:
    import/resolver:
        node:
            extensions: [".js", ".android.js", ".ios.js", ".web.js"]
            moduleDirectory:
                - node_modules
                - . # <-- app root

But since I believe “app” makes for a better alias than “src” (too generic), I had to battle a little more in order to get things working.

eslint-import-resolver-alias

# ./.eslintrc.yaml

settings:
    import/resolver:
        alias:
            extensions: [".js", ".android.js", ".ios.js", ".web.js"]
            map:
                - ["app", "./src"]

Here we go. We’re all setup.

If you enjoyed this article, give it a clap on Medium.