# Angular vs Vue 3 - Side by Side Comparison ## Your Question: "Is there a better way?" **YES! You were right to question it.** Here's why the Vue rewrite solves your problems: ## The Problems You Had ### ❌ Angular Issues 1. **"Disappearing interfaces"** - Components randomly vanishing on route changes 2. **"Routing problems"** - Navigation breaking, routes not loading 3. **"Untable and hard to work with"** - Complex module system, slow builds 4. **"Seems a bit shit"** - Your words, but accurate! 😅 ### ✅ Vue Solutions 1. **Stable routing** - Vue Router is simpler and more predictable 2. **Components don't vanish** - Reactive system is more reliable 3. **Fast & easy** - Vite HMR is instant, code is cleaner 4. **Actually enjoyable** - Modern DX that doesn't fight you ## Technical Comparison ### Routing **Angular (Complex & Brittle):** ```typescript // app-routing.module.ts const routes: Routes = [ { path: '', redirectTo: '/login', pathMatch: 'full' }, { path: 'login', loadChildren: () => import('./pages/login/login.module').then(m => m.LoginPageModule) }, // Module imports, lazy loading, guards in separate files... ] // app.component.ts - Complex splash logic causing routing issues this.router.events .pipe(filter(e => e instanceof NavigationEnd)) .subscribe((e: any) => { // Lots of state management that can break routes }) ``` **Vue (Clean & Simple):** ```typescript // router/index.ts const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', redirect: '/login' }, { path: '/login', component: () => import('../views/Login.vue') }, // Done. No modules, no complexity. ] }) // Auth guard router.beforeEach((to, from, next) => { const isPublic = to.meta.public if (!isPublic && !store.isAuthenticated) { next('/login') } else { next() } }) ``` ### State Management **Angular (RxJS Spaghetti):** ```typescript // Observables everywhere this.authService.isVerified$ .pipe( filter(verified => verified), take(1), ) .subscribe(() => { this.subscriptions.add((this.patchData as any).subscribe?.() ?? new Subscription()) this.subscriptions.add((this.patchMonitor as any).subscribe?.() ?? new Subscription()) // Easy to miss unsubscribe, causes memory leaks }) ``` **Vue (Simple & Reactive):** ```typescript // Pinia store const isAuthenticated = ref(false) const serverInfo = computed(() => data.value?.['server-info']) // No subscriptions to manage! async function login(password: string) { await rpcClient.login(password) isAuthenticated.value = true await connectWebSocket() } ``` ### Components **Angular (Verbose):** ```typescript import { Component, inject, OnDestroy } from '@angular/core' import { ActivatedRoute, NavigationEnd, Router } from '@angular/router' import { filter, take } from 'rxjs/operators' import { combineLatest, map, startWith, Subscription } from 'rxjs' @Component({ selector: 'app-root', templateUrl: 'app.component.html', styleUrls: ['app.component.scss'], }) export class AppComponent implements OnDestroy { private readonly subscriptions = new Subscription() constructor( private readonly titleService: Title, private readonly patchData: PatchDataService, // ... 10 more injected services ) {} ngOnDestroy() { this.subscriptions.unsubscribe() } } ``` **Vue (Concise):** ```vue ``` ### Styling (Glass Cards) **Angular (Fighting Ionic):** ```scss // Have to override Ionic parts ion-menu.left-menu::part(container) { background: rgba(0, 0, 0, 0.35) !important; backdrop-filter: blur(18px); } :host ::ng-deep ion-item.service-card { --background: rgba(0, 0, 0, 0.35) !important; // Fighting specificity wars } ``` **Vue (Tailwind Utility Classes):** ```vue