A practical example implementing Clean Architecture principles in a Vue.js frontend application
Read the detailed guide »
View Demo
·
Report Bug
·
Request Feature
This project demonstrates a practical implementation of Clean Architecture principles in a Vue.js frontend application. It showcases how to structure a frontend application with clear separation of concerns across different layers, making the codebase more maintainable, testable, and scalable.
The application uses the Pokémon TCG API to showcase these architectural concepts in a real-world scenario.
Important
Before starting, make sure you have the following installed to run the project in development mode.
Install Node.js on macOS 🍏
# Install nvm (Node Version Manager)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
# Download and install Node.js (you may need to restart the terminal)
nvm install 22.14.0
# Verify Node.js installation
node -v # should print `v22.14.0`
# Verify npm installation
npm -v
Install Node.js on Windows 🪟
# Install fnm (Fast Node Manager)
winget install Schniz.fnm
# Configure fnm environment
fnm env --use-on-cd | Out-String | Invoke-Expression
# Download and install Node.js
fnm use --install-if-missing 22.14.0
# Verify Node.js installation
node -v # should print `v22.14.0`
Install Bun Package Manager
# For macOS, Linux, and WSL
curl -fsSL https://bun.sh/install | bash
# For Windows (via PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"
# Verify Bun installation
bun -v
Follow these steps to set up and run the project locally.
- Create a
.env.local
file in the root directory based on the provided.env.example
:
# .env.local
,-. _,---._ __ / \
/ ) .-' `./ / \ ~~~ Env Init ~~~
( ( ,' `/ /|
\ `-" \'\ / |
`. , \ \ / |
/`* ,'-`----Y |
( ; .envs | '
| ,-. ,-' | /
| | ( | | /
) | \ `.___________|/
`--' `--'
VITE_POKEMONTCG_API_KEY=your_api_key_here
- Generate an API key from PokemonTCG Developer Portal and add it to your
.env.local
file.
Install dependencies using Bun:
bun i
The project includes several useful scripts:
# Start development server
bun run dev
# Build for production
bun run build
# Preview production build
bun run preview
# Run end-to-end tests
bun run test:e2e
# Type checking
bun run type-check
# Linting
bun run lint # Run all linters
bun run lint:oxlint # Run oxlint only
bun run lint:eslint # Run eslint only
# Code formatting
bun run format
After running bun run dev
, the application will be available at:
http://localhost:5173/
This project follows Clean Architecture principles, organized into the following layers:
graph TB
User((User))
subgraph "Frontend Application"
VueApp["Vue Application<br>(Vue.js)"]
subgraph "Frontend Components"
Router["Router<br>(Vue Router)"]
StateManager["State Management<br>(Pinia)"]
CardStore["Card Store<br>(Pinia Store)"]
end
end
subgraph "Domain Layer (Business Logic Layer)"
CardDomain["Card Domain<br>(TypeScript)"]
subgraph "Card Domain Components"
CardEntity["Card Entity<br>(TypeScript)"]
CardRepository["Card Repository Interface<br>(TypeScript)"]
end
end
subgraph "Application Layer"
subgraph "Card Application Components"
CardServiceHandler["Card Service Handler<br>(TypeScript)"]
PersistentCardsMapper["Persistent Cards Mapper<br>(TypeScript)"]
StorageCardDTO["Storage Card DTO<br>(TypeScript)"]
end
end
subgraph "Infrastructure Layer"
subgraph "Network Infrastructure"
HttpService["HTTP Service<br>(Http Client)"]
NetworkErrorHandler["Network Error Handler<br>(TypeScript)"]
end
subgraph "Persistence Infrastructure"
LocalStorage["Local Storage Manager<br>(Browser Storage)"]
SessionStorage["Session Storage Manager<br>(Browser Storage)"]
end
subgraph "Card Infrastructure"
CardServiceRepo["Card Service Repository<br>(TypeScript)"]
CardStorageRepo["Card Storage Repository<br>(TypeScript)"]
end
end
%% Relationships
User -->|"Interacts with"| VueApp
VueApp -->|"Uses"| Router
VueApp -->|"Uses"| StateManager
StateManager -->|"Manages"| CardStore
CardStore -->|"Uses"| CardServiceRepo
CardDomain -->|"Defines"| CardEntity
CardDomain -->|"Defines"| CardRepository
CardServiceRepo -->|"Implements"| CardRepository
CardStorageRepo -->|"Implements"| CardRepository
CardServiceRepo -->|"Uses"| HttpService
CardStorageRepo -->|"Uses"| LocalStorage
CardStorageRepo -->|"Uses"| SessionStorage
HttpService -->|"Handles Errors via"| NetworkErrorHandler
CardStorageRepo -->|"Uses"| PersistentCardsMapper
PersistentCardsMapper -->|"Maps to/from"| StorageCardDTO
PersistentCardsMapper -->|"Uses"| CardEntity
VueApp -->|"Use"| PersistentCardsMapper
CardStore -->|"Implement"| CardEntity
%% Style
classDef container fill:#e9e9e9,stroke:#666,stroke-width:2px
classDef component fill:#fff,stroke:#999,stroke-width:1px
class VueApp,HttpService,LocalStorage,SessionStorage container
class Router,StateManager,CardStore,CardEntity,CardRepository,CardServiceHandler,PersistentCardsMapper,StorageCardDTO,NetworkErrorHandler,CardServiceRepo,CardStorageRepo component
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
This project is licensed under the MIT License.
Oscar Raygoza - oscar.eduardo.raygoza@gmail.com