How to use absolute imports in react native with expo

This short post demonstrates how to use absolute imports of react components in a react native application created with expo.

Relative imports, as used by default, in react can become really confusing and produce a lot of additional overhead when you refactor, restructure or move components.

Relative Imports

/* .src/screens/Settings/MainSettings.js */
import AppButton from '../../components/AppButton'

If this screen component ever changes its location in the project, or we extract part of the component, we will also have to adapt the import. Additionally, with relative imports, we always have to mentally keep track of our exact position in the project structure. Two problems which we can easily avoid by using absolute imports.

Absolute Imports

Things are much easier for us with absolute imports. Let's have a look at the previous MainSettings component in this case.

/* .src/screens/Settings/MainSettings.js */
import AppButton from 'components/AppButton'

And if we move MainSettings, the import won't change!

/* .src/screens/MainSettings.js */
import AppButton from 'components/AppButton'

But how do we get there?

Setting Up Absolute Imports

The solution to our problem is actually quite simple. In the initial setup of the app, expo creates a babel.config.js file:

/* ./babel.config.js */
/* eslint-disable */
module.exports = function (api) {
  api.cache(true)
  return {
    presets: ['babel-preset-expo'],
  }
}

We can use this config file to create aliases for our modules:

/* ./babel.config.js */
/* eslint-disable */
module.exports = function (api) {
  api.cache(true)
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      [
        'module-resolver',
        {
          alias: {
            components: './src/components',
          },
        },
      ],
    ],
  }
}

The number of aliases and the naming is up to you. You can put in as many aliases as you want:

/* ./babel.config.js */
/* eslint-disable */
module.exports = function (api) {
  api.cache(true)
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      [
        'module-resolver',
        {
          alias: {
            components: './src/components',
            alsoComponents: './src/components',
            pictures: './src/assets/images',
          },
        },
      ],
    ],
  }
}