Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

ESLint "Unable to resolve path to module" in project with shared modules

I am getting ESLint errors when attempting to import modules from a shared project. The errors happen on every import from the shared/ project. The exact error is the common ESLint import error: Unable to resolve path to module 'shared/hooks/api'

When I disable ESLint, all my projects run and build fine. VSCode also can auto-complete the imports for me correctly, so I know at least it is partially setup correctly (I think). I can cmd+click on the imports and it navigates me to the correct shared/ project file. All of this makes me think that everything is "resolving" OK, just ESLint can’t figure it out.

An example:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

// mobile/screens/Home.tsx

// Error: Unable to resolve path to module 'shared/hooks/api'
import { someHook } from 'shared/hooks/api'

My project is setup like this:

frontend/
├─ mobile/
│  ├─ ...
│  ├─ screens/
│  │  ├─ Home.tsx
│  ├─ eslintrc.yml
│  ├─ tsconfig.json
├─ shared/
│  ├─ ...
│  ├─ hooks/
│  │  ├─ api.ts
│  ├─ eslintrc.yml
│  ├─ tsconfig.json
├─ web/
│  ├─ ...
│  ├─ eslintrc.yml
│  ├─ tsconfig.json

My tsconfig.json files look like:


// mobile/tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-native",
    "rootDirs": ["./src", "../shared/src/*"],
    "paths": {
      "shared/*": ["../shared/src/*"],
      "screens/*": ["./src/screens/*"]
    }
  },
  "extends": "expo/tsconfig.base",
  "baseUrl": "src",
  "include": [
    "src",
    "./babel.config.js",
    "**/*.tsx",
    "**/*.ts",
    "../shared/**/*.ts",
    "../shared/**/*.tsx"
  ]
}

// shared/tsconfig.json
{
  "compilerOptions": {
    ...,
    "baseUrl": "src",
    "paths": {
      "hooks/*": ["hooks/*"]
    }
  },
  "include": ["src"]
}

And relevant ESLint configurations:

# mobile/eslintrc.yml

env:
  browser: true
  es2021: true

parser: '@typescript-eslint/parser'

parserOptions:
  ecmaVersion: latest
  sourceType: module
  project: ['./tsconfig.json']

extends:
  - eslint:recommended
  - plugin:react/recommended
  - plugin:react/jsx-runtime
  - plugin:react-hooks/recommended
  - plugin:@typescript-eslint/recommended
  - plugin:@typescript-eslint/recommended-requiring-type-checking
  - plugin:import/recommended
  - plugin:jsdoc/recommended
  - prettier

plugins:
  - react
  - '@typescript-eslint'
  - 'no-relative-import-paths'
...

settings:
  react:
    version: detect
  import/resolver:
    node:
      paths: ['src', '../shared/src']
      extensions: ['.js', '.jsx', '.ts', '.tsx']
# shared/eslintrc.yml

env:
  browser: true
  es2021: true

parser: '@typescript-eslint/parser'

parserOptions:
  ecmaVersion: latest
  sourceType: module
  project: ['tsconfig.json']

extends:
  - eslint:recommended
  - plugin:react/recommended
  - plugin:react/jsx-runtime
  - plugin:react-hooks/recommended
  - plugin:@typescript-eslint/recommended
  - plugin:@typescript-eslint/recommended-requiring-type-checking
  - plugin:import/recommended
  - plugin:jsdoc/recommended
  - prettier

plugins:
  - react
  - '@typescript-eslint'
  - 'no-relative-import-paths'

... 

settings:
  react:
    version: detect
  import/resolver:
    node:
      paths: ['src']
      extensions: ['.js', '.jsx', '.ts', '.tsx']
// VSCode Workspace settings
{ 
  "eslint.workingDirectories": ["./shared", "./mobile", "./web"],
}

The configurations for the web/ project are pretty similar to the mobile/ project, except that the tooling is for a ReactJS project instead of react-native.

How can I setup the eslintrc.yml and tsconfig.json files to work correctly with this project structure?

>Solution :

You are using baseUrl in your tsconfig.json which lets you simplify your imports:

import  {someHook} from "shared/hooks/api";

This is a TypeScript feature! By default eslint (and most bundlers/runtimes) do not read your tsconfig.json, nor do they respect the baseUrl, paths or other settings that impact TypeScript’s module resolution. It’s quite a footgun.

You’ll need to install and configure the appropriate plugin to tell ESLint to respect your tsconfig: https://www.npmjs.com/package/eslint-import-resolver-typescript

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading