Path Mapping์ ์ฌ์ฉํ๋ฉด ์๋ ๊ฒฝ๋ก ๋์ ์ ๋ ๊ฒฝ๋ก๋ก ๋ชจ๋์ importํ ์ ์์ต๋๋ค. ์ฝ๋ ๊ฐ๋
์ฑ์ด ํฅ์๋๊ณ ํ์ผ ์ด๋ ์ import ๊ฒฝ๋ก๋ฅผ ์์ ํ ํ์๊ฐ ์์ต๋๋ค.
Web (React)์ Path Mapping
Sonamu Web ํ๋ก์ ํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก @/* ๊ฒฝ๋ก ๋งคํ์ ์ ๊ณตํฉ๋๋ค.
tsconfig.json ์ค์
{
"compilerOptions" : {
"baseUrl" : "." ,
"paths" : {
"@/*" : [ "./src/*" ]
}
}
}
Vite ์ค์
TypeScript ์ค์ ๋ง์ผ๋ก๋ ๋ถ์กฑํ๊ณ , Vite์๋ ๋์ผํ alias๋ฅผ ์ค์ ํด์ผ ํฉ๋๋ค.
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" ),
},
} ,
}) ;
TypeScript์ Vite ๋ชจ๋์ ์ค์ ํด์ผ ํฉ๋๋ค. ํ๋๋ง ์ค์ ํ๋ฉด ํ์
์ฒดํฌ๋ ๋น๋๊ฐ ์คํจํฉ๋๋ค.
์ฌ์ฉ ์์
Before (์๋ ๊ฒฝ๋ก)
After (์ ๋ ๊ฒฝ๋ก)
src/pages/users/UserDetail.tsx
// โ ๋ณต์กํ๊ณ ์ ์ง๋ณด์ ์ด๋ ค์
import { Button } from "../../components/Button" ;
import { Input } from "../../components/Input" ;
import { formatDate } from "../../utils/format" ;
import { useAuth } from "../../hooks/useAuth" ;
๋ฌธ์ ์ :
ํ์ผ ์์น๊ฐ ๋ฐ๋๋ฉด ๋ชจ๋ import ์์ ํ์
../../../ ๊ฐ์ ๋ณต์กํ ๊ฒฝ๋ก
๊ฐ๋
์ฑ์ด ๋จ์ด์ง
src/pages/users/UserDetail.tsx
// โ
๊น๋ํ๊ณ ๋ช
ํํจ
import { Button } from "@/components/Button" ;
import { Input } from "@/components/Input" ;
import { formatDate } from "@/utils/format" ;
import { useAuth } from "@/hooks/useAuth" ;
์ฅ์ :
ํ์ผ ์์น๊ฐ ๋ฐ๋์ด๋ import ๊ฒฝ๋ก ์ ์ง
์ด๋์๋ ๋์ผํ ๋ฐฉ์์ผ๋ก import
๊ฐ๋
์ฑ ํฅ์
๋๋ ํ ๋ฆฌ๋ณ ๋งคํ
๋ ๋ง์ ๊ฒฝ๋ก๋ฅผ ๋งคํํ ์ ์์ต๋๋ค.
{
"compilerOptions" : {
"baseUrl" : "." ,
"paths" : {
"@/*" : [ "./src/*" ],
"@components/*" : [ "./src/components/*" ],
"@pages/*" : [ "./src/pages/*" ],
"@utils/*" : [ "./src/utils/*" ],
"@hooks/*" : [ "./src/hooks/*" ],
"@types/*" : [ "./src/types/*" ]
}
}
}
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" ),
},
} ,
}) ;
์ฌ์ฉ ์์:
// ๊ธฐ๋ณธ ๋ฐฉ์
import { Button } from "@/components/Button" ;
// ์ธ๋ถ ๋งคํ
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" ;
@/* ํ๋๋ง ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ๋๋ฌด ๋ง์ ๋งคํ์ ์คํ๋ ค ํผ๋์ ์ค ์ ์์ต๋๋ค.
API ์๋ฒ์ ๋ชจ๋ ํด์
API ์๋ฒ๋ ์ผ๋ฐ์ ์ผ๋ก path mapping์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
{
"compilerOptions" : {
"moduleResolution" : "bundler" , // Vite๊ฐ ๋ชจ๋ ํด์
"target" : "esnext" ,
"module" : "esnext"
}
}
Vite๊ฐ ๋ชจ๋ ๋ชจ๋์ ํด์
API๋ Vite๋ก ๋น๋๋๋ฏ๋ก ๋ณ๋์ path mapping ๋ถํ์
sonamu ๊ฐ์ ํจํค์ง๋ Vite๊ฐ ์๋์ผ๋ก ํด์
์๋ ๊ฒฝ๋ก๊ฐ ๋ ๋ช
ํํ๊ณ ๋จ์ํจ
API ๊ตฌ์กฐ
API๋ ์๋์ ์ผ๋ก ๊ฐ๋จํ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋๋ค.
api/src/application/controllers/UserController.ts
// ์๋ ๊ฒฝ๋ก๋ก ์ถฉ๋ถํ ๋ช
ํํจ
import { UserService } from "../services/UserService" ;
import { User } from "../../domain/entities/User" ;
API์์ path mapping์ด ํ์ํ๋ค๋ฉด ์ถ๊ฐํ ์ ์์ง๋ง, ์ผ๋ฐ์ ์ผ๋ก ๋ถํ์ํฉ๋๋ค.
Sonamu ํจํค์ง Import
Sonamu ์์ฒด๋ path mapping ์์ด importํ ์ ์์ต๋๋ค.
// โ
์ง์ import
import { BaseModelClass , api , transactional } from "sonamu" ;
import { DB } from "sonamu" ;
import { drivers } from "sonamu/storage" ;
import { store } from "sonamu/cache" ;
// โ
ํ์
import
import type { Context , SonamuConfig } from "sonamu" ;
Sonamu ํจํค์ง ๊ตฌ์กฐ:
sonamu - ๋ฉ์ธ ํจํค์ง
sonamu/storage - ์คํ ๋ฆฌ์ง ๋๋ผ์ด๋ฒ
sonamu/cache - ์บ์ ๋๋ผ์ด๋ฒ
Sonamu๋ package.json์ exports ํ๋๋ก ์๋ธํจํค์ง๋ฅผ ์ ๊ณตํฉ๋๋ค.
ํ์
Import
ํ์
๋ง importํ ๋๋ type ํค์๋๋ฅผ ์ฌ์ฉํ์ธ์.
// โ
ํ์
๋ง import
import type { User } from "@/types/user" ;
import type { Context } from "sonamu" ;
// โ
๊ฐ๊ณผ ํ์
ํผํฉ
import { DB , type Context } from "sonamu" ;
// โ ๋ฐํ์์ ๋ถํ์ํ import
import { User } from "@/types/user" ;
type import๋ ์ปดํ์ผ ํ ์ ๊ฑฐ๋์ด ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์
๋๋ค.
IDE ์๋ ์์ฑ
Path mapping์ ์ค์ ํ๋ฉด IDE๊ฐ ์๋์ผ๋ก ์ธ์ํฉ๋๋ค.
VS Code
{
"typescript.preferences.importModuleSpecifier" : "non-relative"
}
์ด ์ค์ ์ผ๋ก ์๋ import ์ ์ ๋ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํฉ๋๋ค.
IntelliJ / WebStorm
์๋์ผ๋ก tsconfig.json์ ์ฝ์ด path mapping์ ์ธ์ํฉ๋๋ค.
์๋ ์์ฑ์ด ์๋ํ์ง ์์ ๋
์ฆ์:
@/... ๊ฒฝ๋ก๊ฐ ๋นจ๊ฐ ๋ฐ์ค
์๋ ์์ฑ์ด ์๋ํ์ง ์์
ํด๊ฒฐ:
TypeScript ์๋ฒ ์ฌ์์
VS Code: Cmd/Ctrl + Shift + P โ "TypeScript: Restart TS Server"
tsconfig.json ํ์ธ
{
"compilerOptions" : {
"baseUrl" : "." , // ํ์!
"paths" : {
"@/*" : [ "./src/*" ]
}
}
}
Vite ๊ฐ๋ฐ ์๋ฒ ์ฌ์์
# Vite ์ฌ์์
pnpm dev
node_modules ์ฌ์ค์น
rm -rf node_modules
pnpm install
Jest ํ
์คํธ ์ค์
ํ
์คํธ์์๋ path mapping์ ์ฌ์ฉํ๋ ค๋ฉด Jest ์ค์ ์ด ํ์ํฉ๋๋ค.
export default {
moduleNameMapper: {
"^@/(.*)$" : "<rootDir>/src/$1" ,
"^@components/(.*)$" : "<rootDir>/src/components/$1" ,
} ,
} ;
ํ
์คํธ ํ์ผ์์ ์ฌ์ฉ:
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 ();
});
});
์ผ๋ฐ์ ์ธ ๋ฌธ์ ํด๊ฒฐ
Cannot find module '@/...' ์๋ฌ
์ฆ์: Cannot find module '@/components/Button' or its corresponding type declarations.
์์ธ:
baseUrl์ด ์ค์ ๋์ง ์์
Vite alias๊ฐ ์ค์ ๋์ง ์์
๊ฒฝ๋ก ์คํ
ํด๊ฒฐ: 1. tsconfig.json ํ์ธ {
"compilerOptions" : {
"baseUrl" : "." , // ๋ฐ๋์ ํ์!
"paths" : {
"@/*" : [ "./src/*" ]
}
}
}
2. vite.config.ts ํ์ธ import path from "path" ;
export default defineConfig ({
resolve: {
alias: {
"@" : path . resolve ( __dirname , "./src" ),
},
} ,
}) ;
3. ํ์ผ ์กด์ฌ ํ์ธ ls -la src/components/Button.tsx
๋น๋๋ ๋์ง๋ง ํ์
์ฒดํฌ ์คํจ
์ฆ์: pnpm build # โ
์ฑ๊ณต
pnpm tsc # โ ํ์
์๋ฌ
์์ธ:
Vite๋ alias๋ฅผ ์ธ์ํ์ง๋ง TypeScript๋ ์ธ์ํ์ง ๋ชปํจ
ํด๊ฒฐ: tsconfig.json์ baseUrl๊ณผ paths ์ถ๊ฐ:{
"compilerOptions" : {
"baseUrl" : "." ,
"paths" : {
"@/*" : [ "./src/*" ]
}
}
}
ํ์
์ฒดํฌ๋ ๋์ง๋ง ๋น๋ ์คํจ
์ฆ์: pnpm tsc # โ
์ฑ๊ณต
pnpm build # โ ๋น๋ ์๋ฌ
์์ธ:
TypeScript๋ alias๋ฅผ ์ธ์ํ์ง๋ง Vite๋ ์ธ์ํ์ง ๋ชปํจ
ํด๊ฒฐ: vite.config.ts์ alias ์ถ๊ฐ:import path from "path" ;
export default defineConfig ({
resolve: {
alias: {
"@" : path . resolve ( __dirname , "./src" ),
},
} ,
}) ;
๊ถ์ฅ ์ฌํญ
๊ถ์ฅ ์ค์ : {
"compilerOptions" : {
"baseUrl" : "." ,
"paths" : {
"@/*" : [ "./src/*" ]
}
}
}
์ฌ์ฉ ๋ฐฉ๋ฒ:
@/components/* - ์ปดํฌ๋ํธ
@/pages/* - ํ์ด์ง
@/utils/* - ์ ํธ๋ฆฌํฐ
@/hooks/* - ์ปค์คํ
ํ
@/types/* - ํ์
์ ์
ํผํด์ผ ํ ๊ฒ:
๋๋ฌด ๋ง์ alias (ํผ๋ ๊ฐ์ค)
ํ์ ๋๋ ํ ๋ฆฌ๋ง๋ค alias (๋ถํ์)
๊ถ์ฅ:
Path mapping ์ฌ์ฉํ์ง ์์
์๋ ๊ฒฝ๋ก๋ก ์ถฉ๋ถํ ๋ช
ํํจ
๋ง์ฝ ํ์ํ๋ค๋ฉด: {
"compilerOptions" : {
"baseUrl" : "." ,
"paths" : {
"@/*" : [ "./src/*" ]
}
}
}
๋จ, Vite ์ค์ ์ ํ์ ์์ (moduleResolution: bundler) ํ ์ ์ฒด ์ผ๊ด์ฑ ์ ์ง: // โ
๋ชจ๋ ํ๋ก์ ํธ์์ ๋์ผ
{
"paths" : {
"@/*" : [ "./src/*" ]
}
}
// โ
ํ์ ๋ชจ๋๊ฐ ๋์ผํ ๋ฐฉ์ ์ฌ์ฉ
import { Button } from "@/components/Button" ;
ํผํด์ผ ํ ๊ฒ: // โ ํ๋ก์ ํธ๋ง๋ค ๋ค๋ฅธ prefix
import { Button } from "~/components/Button" ; // ํ๋ก์ ํธ A
import { Button } from "@/components/Button" ; // ํ๋ก์ ํธ B
import { Button } from "#/components/Button" ; // ํ๋ก์ ํธ C
๋ค์ ๋จ๊ณ