skip to Main Content

I’m using a npm workspaces mono repo with two workspaces _common and le. My project is React + Vite + TS + Tailwind. I’m using a custom aliasing plugin with vite…

import path from 'path';
import fs from 'fs';
import { Plugin } from 'vite';

const multiAlias = (src: string): Plugin => ({
  name: 'multi-alias',
  async resolveId(source: string) {
    if (source.startsWith('@/')) {

      const possiblePaths = [
        path.resolve(src, './' + source.replace('@/', '')),
        path.resolve(src, '../_common/' + source.replace('@/', '')),
      ];

      for (const p of possiblePaths) {
        if (fs.existsSync(p)) {
          return p;
        }
      }
    }
    return null;
  }
});

export default multiAlias;

This plugin allows me to import common components import Carousel from '@/src/Carousel.tsx' and then surgically overwriting any child component down the dependency tree just by including the same path in my workspace.

This works great when I build my files, however, when I’m developing in VS Code I’m getting the Cannot find module '@/src/Carousel.tsx' or its corresponding type declarations.ts(2307) in my le workspace. The same file in my _common workspace shows no such errors. I’m pretty sure it’s because the tsconfig.json isn’t setup correctly.

Error example

Here is my tsconfig which is used in both workspaces via "extends": "../_common/tsconfig.json", in the le workspace.

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "baseUrl": "./",
    "paths": {
      "@/*": ["./*", "../_common/*"],
    },

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "allowUnreachableCode": true,
  },
  "include": ["*.tsx", "src/*.ts", "tokens/*", "../_common/*.tsx", "../_common/src/*.ts", "../_common/tokens/*"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

2

Answers


  1. Chosen as BEST ANSWER

    So while debugging a bit further I found that I needed to move my basepath up a directory "baseUrl": "../", and then name each directory that would be possible for the alias to resolve for the "paths" object. This is what I ended up with

    {
      "compilerOptions": {
        "target": "ES2020",
        "useDefineForClassFields": true,
        "lib": ["ES2020", "DOM", "DOM.Iterable"],
        "module": "ESNext",
        "skipLibCheck": true,
        "baseUrl": "../",
        "paths": {
          "@/*": ["./_common/*", "./le/*"],
        },
    
        /* Bundler mode */
        "moduleResolution": "bundler",
        "allowImportingTsExtensions": true,
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
    
        /* Linting */
        "strict": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noFallthroughCasesInSwitch": true,
      },
      "include": ["*.tsx", "src/*.ts", "tokens/*"],
      "references": [{ "path": "./tsconfig.node.json" }]
    }
    

  2. Although, you already answered your own question… There’s a bounty so I’ll answer it for fun and to provide any additional context. But the issue you’re facing with module resolution in your VS Code environment is likely due to the way TypeScript handles your path aliases in tsconfig.json… While your Vite plugin manages alias resolution during the build, TypeScript and VS Code need to be properly configured to recognize these paths during development; so, tsconfig.json needs to be consistently configured in both the le and _common workspaces:

    _common/tsconfig.json

    {
      "compilerOptions": {
        "target": "ES2020",
        "useDefineForClassFields": true,
        "lib": ["ES2020", "DOM", "DOM.Iterable"],
        "module": "ESNext",
        "skipLibCheck": true,
        "baseUrl": "./",
        "paths": {
          "@/*": ["src/*"]
        },
        "moduleResolution": "node",
        "allowImportingTsExtensions": true,
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
        "strict": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noFallthroughCasesInSwitch": true,
        "allowUnreachableCode": true
      },
      "include": ["src/**/*", "tokens/**/*"]
    }
    

    le/tsconfig.json

    {
      "extends": "../_common/tsconfig.json",
      "compilerOptions": {
        "baseUrl": "./",
        "paths": {
          "@/*": ["src/*", "../_common/src/*"]
        }
      },
      "include": ["src/**/*", "tokens/**/*", "../_common/src/**/*"]
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search