Skip to main content
Path Mapping allows you to import modules using absolute paths instead of relative paths. This improves code readability and eliminates the need to update import paths when files are moved.

Path Mapping in Web (React)

Sonamu Web projects provide @/* path mapping by default.

tsconfig.json Configuration

web/tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Vite Configuration

TypeScript configuration alone is not enough; you also need to set up the same alias in Vite.
web/vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});
You must configure both TypeScript and Vite. If only one is configured, type checking or builds will fail.

Usage Examples

src/pages/users/UserDetail.tsx
// ❌ Complex and hard to maintain
import { Button } from "../../components/Button";
import { Input } from "../../components/Input";
import { formatDate } from "../../utils/format";
import { useAuth } from "../../hooks/useAuth";
Problems:
  • Need to update all imports when file location changes
  • Complex paths like ../../../
  • Poor readability

Directory-specific Mapping

You can map more paths.
web/tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"],
      "@pages/*": ["./src/pages/*"],
      "@utils/*": ["./src/utils/*"],
      "@hooks/*": ["./src/hooks/*"],
      "@types/*": ["./src/types/*"]
    }
  }
}
web/vite.config.ts
export default defineConfig({
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
      "@components": path.resolve(__dirname, "./src/components"),
      "@pages": path.resolve(__dirname, "./src/pages"),
      "@utils": path.resolve(__dirname, "./src/utils"),
      "@hooks": path.resolve(__dirname, "./src/hooks"),
      "@types": path.resolve(__dirname, "./src/types"),
    },
  },
});
Usage examples:
// Default method
import { Button } from "@/components/Button";

// Specific mappings
import { Button } from "@components/Button";
import { UserPage } from "@pages/UserPage";
import { formatDate } from "@utils/format";
import { useAuth } from "@hooks/useAuth";
import type { User } from "@types/user";
We recommend using only @/*. Too many mappings can cause confusion.

Module Resolution in API Server

The API server typically does not use path mapping.

Reason

api/tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "bundler",  // Vite resolves modules
    "target": "esnext",
    "module": "esnext"
  }
}
Vite resolves all modules
  • API is built with Vite, so separate path mapping is unnecessary
  • Packages like sonamu are automatically resolved by Vite
  • Relative paths are clearer and simpler

API Structure

API has a relatively simple structure.
api/src/application/controllers/UserController.ts
// Relative paths are sufficiently clear
import { UserService } from "../services/UserService";
import { User } from "../../domain/entities/User";
You can add path mapping to API if needed, but it’s generally unnecessary.

Importing Sonamu Packages

Sonamu itself can be imported without path mapping.
// βœ… Direct import
import { BaseModelClass, api, transactional } from "sonamu";
import { DB } from "sonamu";
import { drivers } from "sonamu/storage";
import { store } from "sonamu/cache";

// βœ… Type import
import type { Context, SonamuConfig } from "sonamu";
Sonamu package structure:
  • sonamu - Main package
  • sonamu/storage - Storage drivers
  • sonamu/cache - Cache drivers
Sonamu provides subpackages through the exports field in package.json.

Type Imports

Use the type keyword when importing only types.
// βœ… Import types only
import type { User } from "@/types/user";
import type { Context } from "sonamu";

// βœ… Mixed values and types
import { DB, type Context } from "sonamu";

// ❌ Unnecessary import at runtime
import { User } from "@/types/user";
type imports are removed after compilation, reducing bundle size.

IDE Auto-completion

When path mapping is configured, IDEs automatically recognize it.

VS Code

.vscode/settings.json
{
  "typescript.preferences.importModuleSpecifier": "non-relative"
}
This setting uses absolute paths for auto imports.

IntelliJ / WebStorm

Automatically reads tsconfig.json and recognizes path mapping.
Symptoms:
  • @/... paths show red underline
  • Auto-completion doesn’t work
Solutions:
  1. Restart TypeScript server
    VS Code: Cmd/Ctrl + Shift + P β†’ "TypeScript: Restart TS Server"
    
  2. Check tsconfig.json
    {
      "compilerOptions": {
        "baseUrl": ".",  // Required!
        "paths": {
          "@/*": ["./src/*"]
        }
      }
    }
    
  3. Restart Vite dev server
    # Restart Vite
    pnpm dev
    
  4. Reinstall node_modules
    rm -rf node_modules
    pnpm install
    

Jest Test Configuration

Jest configuration is needed to use path mapping in tests.
web/jest.config.ts
export default {
  moduleNameMapper: {
    "^@/(.*)$": "<rootDir>/src/$1",
    "^@components/(.*)$": "<rootDir>/src/components/$1",
  },
};
Usage in test files:
src/components/Button.test.tsx
import { render } from "@testing-library/react";
import { Button } from "@/components/Button";
import { formatDate } from "@/utils/format";

describe("Button", () => {
  it("renders correctly", () => {
    const { getByText } = render(<Button>Click me</Button>);
    expect(getByText("Click me")).toBeInTheDocument();
  });
});

Common Troubleshooting

Symptom:
Cannot find module '@/components/Button' or its corresponding type declarations.
Causes:
  1. baseUrl is not set
  2. Vite alias is not configured
  3. Path typo
Solutions:1. Check tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",  // Required!
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
2. Check vite.config.ts
import path from "path";

export default defineConfig({
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});
3. Verify file exists
ls -la src/components/Button.tsx
Symptom:
pnpm build  # βœ… Success
pnpm tsc    # ❌ Type error
Cause:
  • Vite recognizes the alias but TypeScript doesn’t
Solution:Add baseUrl and paths to tsconfig.json:
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
Symptom:
pnpm tsc    # βœ… Success
pnpm build  # ❌ Build error
Cause:
  • TypeScript recognizes the alias but Vite doesn’t
Solution:Add alias to vite.config.ts:
import path from "path";

export default defineConfig({
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

Recommendations

Recommended settings:
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
Usage:
  • @/components/* - Components
  • @/pages/* - Pages
  • @/utils/* - Utilities
  • @/hooks/* - Custom hooks
  • @/types/* - Type definitions
Avoid:
  • Too many aliases (adds confusion)
  • Alias for every subdirectory (unnecessary)

Next Steps