How to use Babel Module Resolver with react-native+expo on publication?

Viewed 12857

Here is my last version of my .babelrc file :

{
      "presets": ["babel-preset-expo"],
      "env": {
        "development": {
          "plugins": ["transform-react-jsx-source"]
        }
      },
      "plugins": [
        ["module-resolver", {
          "root": ["./src"],
          "alias": {
            "$components": "./src/components",
            "$screens": "./src/screens",
            "$stores": "./src/stores",
            "$utils": "./src/utils",
            "$services": "./src/services",
            "$assets": "./assets",
          }
        }]
      ]
    }

I tried to change many things but expo doesn't want to publish the app and display an error 500 during the publication when it meet the first import on the Main.js file :

import stores from 'stores';

And the error :

500 - "{\"originModulePath\":\"/Users/jhirsch/Code/kliner/app-client/src/Main.js\",\"targetModuleName\":\"stores\",\"message\":\"Unable to resolve module `stores` from `/Users/jhirsch/Code/kliner/app-client/src/Main.js`: Module `stores` does not exist in the Haste module map\\n\\nThis might be related to https://github.com/facebook/react-native/issues/4968\\nTo resolve try the following:\\n  1. Clear watchman watches: `watchman watch-del-all`.\\n  2. Delete the `node_modules` folder: `rm -rf node_modules && npm install`.\\n  3. Reset Metro Bundler cache: `rm -rf /tmp/metro-bundler-cache-*` or `npm start -- --reset-cache`.\\n  4. Remove haste cache: `rm -rf /tmp/haste-map-react-native-packager-*`.\",\"errors\":[{\"description\":\"Unable to resolve module `stores` from `/Users/jhirsch/Code/kliner/app-client/src/Main.js`: Module `stores` does not exist in the Haste module map\\n\\nThis might be related to https://github.com/facebook/react-native/issues/4968\\nTo resolve try the following:\\n  1. Clear watchman watches: `watchman watch-del-all`.\\n  2. Delete the `node_modules` folder: `rm -rf node_modules && npm install`.\\n  3. Reset Metro Bundler cache: `rm -rf /tmp/metro-bundler-cache-*` or `npm start -- --reset-cache`.\\n  4. Remove haste cache: `rm -rf /tmp/haste-map-react-native-packager-*`.\"}],\"name\":\"Error\",\"stack\":\"Error: Unable to resolve module `stores` from `/Users/jhirsch/Code/kliner/app-client/src/Main.js`: Module `stores` does not exist in the Haste module map\\n\\nThis might be related to https://github.com/facebook/react-native/issues/4968\\nTo resolve try the following:\\n  1. Clear watchman watches: `watchman watch-del-all`.\\n  2. Delete the `node_modules` folder: `rm -rf node_modules && npm install`.\\n  3. Reset Metro Bundler cache: `rm -rf /tmp/metro-bundler-cache-*` or `npm start -- --reset-cache`.\\n  4. Remove haste cache: `rm -rf /tmp/haste-map-react-native-packager-*`.\\n    at ModuleResolver.resolveDependency (/Users/jhirsch/Code/kliner/app-client/node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js:209:1301)\\n    at ResolutionRequest.resolveDependency (/Users/jhirsch/Code/kliner/app-client/node_modules/metro/src/node-haste/DependencyGraph/ResolutionRequest.js:83:16)\\n    at DependencyGraph.resolveDependency (/Users/jhirsch/Code/kliner/app-client/node_modules/metro/src/node-haste/DependencyGraph.js:238:485)\\n    at Object.resolve (/Users/jhirsch/Code/kliner/app-client/node_modules/metro/src/lib/transformHelpers.js:180:25)\\n    at dependencies.map.result (/Users/jhirsch/Code/kliner/app-client/node_modules/metro/src/DeltaBundler/traverseDependencies.js:311:29)\\n    at Array.map (<anonymous>)\\n    at resolveDependencies (/Users/jhirsch/Code/kliner/app-client/node_modules/metro/src/DeltaBundler/traverseDependencies.js:307:16)\\n    at /Users/jhirsch/Code/kliner/app-client/node_modules/metro/src/DeltaBundler/traverseDependencies.js:164:33\\n    at Generator.next (<anonymous>)\\n    at step (/Users/jhirsch/Code/kliner/app-client/node_modules/metro/src/DeltaBundler/traverseDependencies.js:266:307)\"}"
    ERROR
    15:45
    Unable to resolve "stores" from "src/Main.js"

Do you have an idea or an alternative to resolve the aliases with expo? It's strange because it's functionnal when i run the app on local simulator.

3 Answers

Finally .babelrc works in this format :

{
  "presets": ["babel-preset-expo"],
  "plugins": [
    [
      "module-resolver",
      {
        "root": ["./"],
        "alias": {
          "@components": "./src/components",
          "@screens": "./src/screens",
          "@stores": "./src/stores",
          "@utils": "./src/utils",
          "@services": "./src/services",
          "@assets": "./assets",
          "@constants": "./src/constants"
        }
      },
    ],
  ],
}

And add '@' when i import :

import stores from '@stores';

If you are like me, still experiencing problems even with @ character in front of your paths,

please, consider using babel-plugin-root-import - an alternative to babel-plugin-module-resolver,

which is not as feature-rich as babel-plugin-module-resolver,

but it is able to solve the essential problem - too many dots in paths like this one

import Button from '../../../../components/Button;

That was the main concern for me.

Here is my config (babel.config.js):

module.exports = function(api) {
  api.cache(true);

  const rootImportOpts = {
    paths: [
      {
        root: __dirname,
        rootPathPrefix: '~/',
        rootPathSuffix: 'src',
      },
      {
        root: __dirname,
        rootPathPrefix: '#/',
        rootPathSuffix: 'spec',
      }
    ]
  };

  return {
    presets: ['babel-preset-expo'],
    plugins: [['babel-plugin-root-import', rootImportOpts]]
  };
};

And the folder structure:

expo-app/
  ...
  spec/
  src/
    ...
    components/
    ...
  ...
  app.config.js
  babel.config.js

As a result, instead of this:

import Button from '../../../../components/Button;

I use that:

import Button from '~/components/Button;

Also, it works as expected on publication.

(typescript project)

For those who are stuck try adding a list for the file extensions.

Before:

  const plugins = [
    ['module-resolver', {
      root: ['src'],
    }]
  ];

After:

  const plugins = [
    ['module-resolver', {
      root: ['src'],
      extensions: ['.tsx', 'json'], // and more
    }]
  ];

Before I added extensions, only aliases would work, but not the root: ['src'].

Related