From 6b693b3237c2228a3febcd8381a223dc15231a0d Mon Sep 17 00:00:00 2001 From: 4gray Date: Wed, 15 Oct 2025 23:12:19 +0200 Subject: [PATCH] refactor: convert to standalone api --- apps/web/src/app/app.component.ts | 4 +- apps/web/src/app/app.config.ts | 88 ++++++++++++++++++ apps/web/src/app/app.module.ts | 89 ------------------- .../{app-routing.module.ts => app.routes.ts} | 22 ++--- apps/web/src/main.ts | 17 ++-- 5 files changed, 101 insertions(+), 119 deletions(-) create mode 100644 apps/web/src/app/app.config.ts delete mode 100644 apps/web/src/app/app.module.ts rename apps/web/src/app/{app-routing.module.ts => app.routes.ts} (79%) diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts index 0587a1c01..0fb45dadd 100644 --- a/apps/web/src/app/app.component.ts +++ b/apps/web/src/app/app.component.ts @@ -1,7 +1,7 @@ import { Component, inject, OnDestroy, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { Router } from '@angular/router'; +import { Router, RouterOutlet } from '@angular/router'; import { Store } from '@ngrx/store'; import { TranslateService } from '@ngx-translate/core'; /* import * as semver from 'semver'; */ @@ -26,7 +26,7 @@ import { SearchResultsComponent } from './xtream-tauri/search-results/search-res @Component({ selector: 'app-root', templateUrl: './app.component.html', - standalone: false, + imports: [RouterOutlet], }) export class AppComponent implements OnInit, OnDestroy { private dataService = inject(DataService); diff --git a/apps/web/src/app/app.config.ts b/apps/web/src/app/app.config.ts new file mode 100644 index 000000000..68d293811 --- /dev/null +++ b/apps/web/src/app/app.config.ts @@ -0,0 +1,88 @@ +import { + HttpClient, + provideHttpClient, + withInterceptorsFromDi, +} from '@angular/common/http'; +import { + ApplicationConfig, + importProvidersFrom, + provideZoneChangeDetection, +} from '@angular/core'; +import { provideAnimations } from '@angular/platform-browser/animations'; +import { provideRouter } from '@angular/router'; +import { provideServiceWorker } from '@angular/service-worker'; +import { provideEffects } from '@ngrx/effects'; +import { provideRouterStore, routerReducer } from '@ngrx/router-store'; +import { provideStore } from '@ngrx/store'; +import { provideStoreDevtools } from '@ngrx/store-devtools'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { TranslateHttpLoader } from '@ngx-translate/http-loader'; +import { PlaylistEffects, playlistReducer } from 'm3u-state'; +import { NgxIndexedDBModule, NgxIndexedDBService } from 'ngx-indexed-db'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { DataService } from 'services'; +import { dbConfig } from 'shared-interfaces'; +import { AppConfig } from '../environments/environment'; +import { routes } from './app.routes'; +import { PwaService } from './services/pwa.service'; +import { TauriService } from './services/tauri.service'; + +// AoT requires an exported function for factories +export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { + return new TranslateHttpLoader(http, './assets/i18n/', '.json'); +} + +/** + * Conditionally provides the necessary service based on the current environment + */ +export function DataFactory() { + if (window.electron) { + return new TauriService(); + } + return new PwaService(); +} + +export const appConfig: ApplicationConfig = { + providers: [ + provideZoneChangeDetection({ eventCoalescing: true }), + provideRouter(routes), + provideAnimations(), + provideHttpClient(withInterceptorsFromDi()), + provideStore({ + router: routerReducer, + playlistState: playlistReducer, + }), + provideEffects([PlaylistEffects]), + provideRouterStore(), + provideStoreDevtools({ + maxAge: 25, + logOnly: AppConfig.production, + }), + provideServiceWorker('ngsw-worker.js', { + enabled: AppConfig.production && !!window.electron, + registrationStrategy: 'registerWhenStable:30000', + }), + importProvidersFrom( + AppConfig.environment === 'WEB' + ? NgxIndexedDBModule.forRoot(dbConfig) + : [], + NgxIndexedDBModule.forRoot(dbConfig), + NgxSkeletonLoaderModule.forRoot({ + animation: 'pulse', + loadingText: 'This item is actually loading...', + }), + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient], + }, + }) + ), + { + provide: DataService, + useFactory: DataFactory, + deps: [NgxIndexedDBService, HttpClient], + }, + ], +}; diff --git a/apps/web/src/app/app.module.ts b/apps/web/src/app/app.module.ts deleted file mode 100644 index f9553b496..000000000 --- a/apps/web/src/app/app.module.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { - HttpClient, - provideHttpClient, - withInterceptorsFromDi, -} from '@angular/common/http'; -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { ServiceWorkerModule } from '@angular/service-worker'; -import { EffectsModule } from '@ngrx/effects'; -import { StoreRouterConnectingModule, routerReducer } from '@ngrx/router-store'; -import { StoreModule } from '@ngrx/store'; -import { StoreDevtoolsModule } from '@ngrx/store-devtools'; -import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; -import { TranslateHttpLoader } from '@ngx-translate/http-loader'; -import { PlaylistEffects, playlistReducer } from 'm3u-state'; -import { NgxIndexedDBModule, NgxIndexedDBService } from 'ngx-indexed-db'; -import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { DataService } from 'services'; -import { dbConfig } from 'shared-interfaces'; -import { AppConfig } from '../environments/environment'; -import '../polyfills'; -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { PwaService } from './services/pwa.service'; -import { TauriService } from './services/tauri.service'; - -// AoT requires an exported function for factories -export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { - return new TranslateHttpLoader(http, './assets/i18n/', '.json'); -} - -/** - * Conditionally imports the necessary service based on the current environment - */ -export function DataFactory() { - if (window.electron) { - return new TauriService(); - } - return new PwaService(); -} - -@NgModule({ - declarations: [AppComponent], - bootstrap: [AppComponent], - imports: [ - AppRoutingModule, - BrowserAnimationsModule, - BrowserModule, - AppConfig.environment === 'WEB' - ? NgxIndexedDBModule.forRoot(dbConfig) - : [], - NgxIndexedDBModule.forRoot(dbConfig), - NgxSkeletonLoaderModule.forRoot({ - animation: 'pulse', - loadingText: 'This item is actually loading...', - }), - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useFactory: HttpLoaderFactory, - deps: [HttpClient], - }, - }), - ServiceWorkerModule.register('ngsw-worker.js', { - enabled: AppConfig.production && !!window.electron, - registrationStrategy: 'registerWhenStable:30000', - }), - StoreModule.forRoot({ - router: routerReducer, - }), - StoreRouterConnectingModule.forRoot(), - StoreModule.forFeature('playlistState', playlistReducer), - EffectsModule.forRoot([PlaylistEffects]), - StoreDevtoolsModule.instrument({ - maxAge: 25, - logOnly: AppConfig.production, - }), - ], - providers: [ - { - provide: DataService, - useFactory: DataFactory, - deps: [NgxIndexedDBService, HttpClient], - }, - provideHttpClient(withInterceptorsFromDi()), - ], -}) -export class AppModule {} diff --git a/apps/web/src/app/app-routing.module.ts b/apps/web/src/app/app.routes.ts similarity index 79% rename from apps/web/src/app/app-routing.module.ts rename to apps/web/src/app/app.routes.ts index 1c3a859d7..0203fcae7 100644 --- a/apps/web/src/app/app-routing.module.ts +++ b/apps/web/src/app/app.routes.ts @@ -1,8 +1,8 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; +import { Routes } from '@angular/router'; import { stalkerRoutes } from './stalker/stalker.routes'; +import { xtreamRoutes } from './xtream-tauri/xtream.routes'; -const routes: Routes = [ +export const routes: Routes = [ { path: '', loadComponent: () => @@ -36,7 +36,7 @@ const routes: Routes = [ (c) => c.SettingsComponent ), }, - /* ...(!!window.electron + ...(window.electron ? xtreamRoutes : [ { @@ -46,7 +46,7 @@ const routes: Routes = [ (c) => c.XtreamMainContainerComponent ), }, - ]), */ + ]), { path: 'portals/:id', loadComponent: () => @@ -60,15 +60,3 @@ const routes: Routes = [ redirectTo: '', }, ]; - -@NgModule({ - imports: [ - RouterModule.forRoot( - routes /* { - enableTracing: !AppConfig.production, - } */ - ), - ], - exports: [RouterModule], -}) -export class AppRoutingModule {} diff --git a/apps/web/src/main.ts b/apps/web/src/main.ts index e3a3b3ac9..c2fda5c01 100644 --- a/apps/web/src/main.ts +++ b/apps/web/src/main.ts @@ -1,12 +1,7 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowser } from '@angular/platform-browser'; -import { AppModule } from './app/app.module'; -import { AppConfig } from './environments/environment'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; -if (AppConfig.production) { - enableProdMode(); -} - -platformBrowser() - .bootstrapModule(AppModule) - .catch((err) => console.error(err)); +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err) +);