Search code examples
typescriptvisual-studio-codealias

How can I prevent TS errors in vs code due to custom vite alias plugin


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" }]
}

Solution

  • 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" }]
    }