]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Speed up plugins loading
authorChocobozzz <me@florianbigard.com>
Fri, 4 Jun 2021 12:39:47 +0000 (14:39 +0200)
committerChocobozzz <me@florianbigard.com>
Fri, 4 Jun 2021 13:45:44 +0000 (15:45 +0200)
16 files changed:
client/src/app/+my-library/my-library.component.ts
client/src/app/+search/search-filters.component.ts
client/src/app/+search/search.component.ts
client/src/app/+videos/+video-edit/shared/video-edit.component.ts
client/src/app/+videos/+video-watch/video-watch.component.ts
client/src/app/app-routing.module.ts
client/src/app/app.component.ts
client/src/app/app.module.ts
client/src/app/core/core.module.ts
client/src/app/core/plugins/plugin.service.ts
client/src/app/core/routing/homepage-redirect.component.ts [new file with mode: 0644]
client/src/app/core/routing/index.ts
client/src/app/core/routing/redirect.service.ts
client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts
client/src/root-helpers/plugins.ts
client/src/root-helpers/utils.ts

index 939aa84c88962ee735ab354a0e54631934aa9bdc..2ee3559a78da116aa3c437df72e1d66fba4221ec 100644 (file)
@@ -11,7 +11,6 @@ export class MyLibraryComponent implements OnInit {
   menuEntries: TopMenuDropdownParam[] = []
   user: AuthUser
 
-
   private serverConfig: HTMLServerConfig
 
   constructor (
index f5f0c87ed36dbcb170486ea04c9c4b7e23f5a7b5..afa523b915ec30295c6081fcb5c7a15e67829d53 100644 (file)
@@ -99,7 +99,6 @@ export class SearchFiltersComponent implements OnInit {
   ngOnInit () {
     this.serverConfig = this.serverService.getHTMLConfig()
 
-
     this.serverService.getVideoCategories().subscribe(categories => this.videoCategories = categories)
     this.serverService.getVideoLicences().subscribe(licences => this.videoLicences = licences)
     this.serverService.getVideoLanguages().subscribe(languages => this.videoLanguages = languages)
index a31096bb2e6aad2830657346f9877d326b81ee62..a4ab7a5b133c91f4d11618a705f530a8d1a39a8c 100644 (file)
@@ -287,7 +287,7 @@ export class SearchComponent implements OnInit, OnDestroy {
     )
   }
 
-  private getDefaultSearchTarget(): SearchTargetType {
+  private getDefaultSearchTarget (): SearchTargetType {
     const searchIndexConfig = this.serverConfig.search.searchIndex
 
     if (searchIndexConfig.enabled && (searchIndexConfig.isDefaultSearch || searchIndexConfig.disableLocalSearch)) {
index 52801802bdd0f21d1e5730c0c3323249e024c5a9..c3299cade19c6ce6def39e8d39db933b12c9b9db 100644 (file)
@@ -194,7 +194,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
         }
       })
 
-
     this.serverConfig = this.serverService.getHTMLConfig()
 
     this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
index 51d486ea5d664f63b1ab6bb905b189d5913ef240..3fdbc018407bf729f85639f2d8fec1e9bdf455dc 100644 (file)
@@ -181,7 +181,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
       this.hasAlreadyAcceptedPrivacyConcern = true
     }
 
-
     this.paramsSub = this.route.params.subscribe(routeParams => {
       const videoId = routeParams[ 'videoId' ]
       if (videoId) this.loadVideo(videoId)
index b04e6a42baafd0202ea00220e7c5c51f757f3fb1..1f98e9d2e2966e679d21dda22d4ddd7a1df0cc9c 100644 (file)
@@ -3,7 +3,7 @@ import { RouteReuseStrategy, RouterModule, Routes, UrlMatchResult, UrlSegment }
 import { CustomReuseStrategy } from '@app/core/routing/custom-reuse-strategy'
 import { MenuGuards } from '@app/core/routing/menu-guard.service'
 import { POSSIBLE_LOCALES } from '@shared/core-utils/i18n'
-import { MetaGuard, PreloadSelectedModulesList } from './core'
+import { HomepageRedirectComponent, MetaGuard, PreloadSelectedModulesList } from './core'
 import { EmptyComponent } from './empty.component'
 import { USER_USERNAME_REGEX_CHARACTERS } from './shared/form-validators/user-validators'
 import { ActorRedirectGuard } from './shared/shared-main'
@@ -156,7 +156,7 @@ const routes: Routes = [
 
   {
     path: '',
-    component: EmptyComponent // Avoid 404, app component will redirect dynamically
+    component: HomepageRedirectComponent
   }
 ]
 
@@ -164,7 +164,7 @@ const routes: Routes = [
 for (const locale of POSSIBLE_LOCALES) {
   routes.push({
     path: locale,
-    component: EmptyComponent
+    component: HomepageRedirectComponent
   })
 }
 
index 6884068f6da8e3a1801ca7905bf44d07aac0373c..2056d6669b2d58391e4ce6d6ccad5bd46facd04a 100644 (file)
@@ -1,6 +1,5 @@
 import { Hotkey, HotkeysService } from 'angular2-hotkeys'
-import { concat } from 'rxjs'
-import { filter, first, map, pairwise, switchMap } from 'rxjs/operators'
+import { filter, map, pairwise, switchMap } from 'rxjs/operators'
 import { DOCUMENT, PlatformLocation, ViewportScroller } from '@angular/common'
 import { AfterViewInit, Component, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core'
 import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
@@ -14,7 +13,7 @@ import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
 import { NgbConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap'
 import { LoadingBarService } from '@ngx-loading-bar/core'
 import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
-import { getShortLocale, is18nPath } from '@shared/core-utils/i18n'
+import { getShortLocale } from '@shared/core-utils/i18n'
 import { BroadcastMessageLevel, HTMLServerConfig, ServerConfig, UserRole } from '@shared/models'
 import { MenuService } from './core/menu/menu.service'
 import { POP_STATE_MODAL_DISMISS } from './helpers'
@@ -75,7 +74,7 @@ export class AppComponent implements OnInit, AfterViewInit {
 
     this.serverConfig = this.serverService.getHTMLConfig()
 
-    this.loadPlugins()
+    this.hooks.runAction('action:application.init', 'common')
     this.themeService.initialize()
 
     this.authService.loadClientCredentials()
@@ -190,12 +189,6 @@ export class AppComponent implements OnInit, AfterViewInit {
                         }
                       })
 
-    // Homepage redirection
-    navigationEndEvent.pipe(
-      map(() => window.location.pathname),
-      filter(pathname => !pathname || pathname === '/' || is18nPath(pathname))
-    ).subscribe(() => this.redirectService.redirectToHomepage(true))
-
     // Plugin hooks
     navigationEndEvent.subscribe(e => {
       this.hooks.runAction('action:router.navigation-end', 'common', { path: e.url })
@@ -268,12 +261,6 @@ export class AppComponent implements OnInit, AfterViewInit {
     }
   }
 
-  private async loadPlugins () {
-    this.pluginService.initializePlugins()
-
-    this.hooks.runAction('action:application.init', 'common')
-  }
-
   private async openModalsIfNeeded () {
     this.authService.userInformationLoaded
         .pipe(
index ea53818e17e36813c266ebdd386a2cef1b178b29..dfdccbe69792a76efd59261111950e4ec6a85dba 100644 (file)
@@ -1,4 +1,5 @@
 import 'focus-visible'
+import { tap } from 'rxjs/operators'
 import { environment } from 'src/environments/environment'
 import { APP_BASE_HREF, registerLocaleData } from '@angular/common'
 import { APP_INITIALIZER, NgModule } from '@angular/core'
@@ -7,7 +8,7 @@ import { ServiceWorkerModule } from '@angular/service-worker'
 import localeOc from '@app/helpers/locales/oc'
 import { AppRoutingModule } from './app-routing.module'
 import { AppComponent } from './app.component'
-import { CoreModule, ServerService } from './core'
+import { CoreModule, PluginService, ServerService } from './core'
 import { EmptyComponent } from './empty.component'
 import { HeaderComponent, SearchTypeaheadComponent, SuggestionComponent } from './header'
 import { HighlightPipe } from './header/highlight.pipe'
@@ -26,8 +27,14 @@ import { SharedUserInterfaceSettingsModule } from './shared/shared-user-settings
 
 registerLocaleData(localeOc, 'oc')
 
-export function loadConfigFactory (server: ServerService) {
-  return () => server.loadHTMLConfig()
+export function loadConfigFactory (server: ServerService, pluginService: PluginService) {
+  return () => {
+    const result = server.loadHTMLConfig()
+
+    if (result) return result.pipe(tap(() => pluginService.initializePlugins()))
+
+    return pluginService.initializePlugins()
+  }
 }
 
 @NgModule({
@@ -75,9 +82,9 @@ export function loadConfigFactory (server: ServerService) {
     {
       provide: APP_INITIALIZER,
       useFactory: loadConfigFactory,
-      deps: [ ServerService ],
+      deps: [ ServerService, PluginService ],
       multi: true
-     }
+    }
   ]
 })
 export class AppModule {}
index de32745442fd7f9fd0e68040104905c410e27910..3e20564811648c5e79f51cfb8ae658baed7dc63c 100644 (file)
@@ -14,7 +14,7 @@ import { throwIfAlreadyLoaded } from './module-import-guard'
 import { Notifier } from './notification'
 import { HtmlRendererService, LinkifierService, MarkdownService } from './renderer'
 import { RestExtractor, RestService } from './rest'
-import { LoginGuard, MetaGuard, MetaService, RedirectService, UnloggedGuard, UserRightGuard } from './routing'
+import { HomepageRedirectComponent, LoginGuard, MetaGuard, MetaService, RedirectService, UnloggedGuard, UserRightGuard } from './routing'
 import { CanDeactivateGuard } from './routing/can-deactivate-guard.service'
 import { ServerConfigResolver } from './routing/server-config-resolver.service'
 import { ScopedTokensService } from './scoped-tokens'
@@ -36,13 +36,15 @@ import { LocalStorageService, ScreenService, SessionStorageService } from './wra
   ],
 
   declarations: [
-    CheatSheetComponent
+    CheatSheetComponent,
+    HomepageRedirectComponent
   ],
 
   exports: [
     ToastModule,
 
-    CheatSheetComponent
+    CheatSheetComponent,
+    HomepageRedirectComponent
   ],
 
   providers: [
index dff8ad864754469790b04c1f9a552cfda236de34..ccbfd3e4db5d903fa151d91629454b2ee6a16c65 100644 (file)
@@ -1,3 +1,4 @@
+import * as debug from 'debug'
 import { Observable, of, ReplaySubject } from 'rxjs'
 import { catchError, first, map, shareReplay } from 'rxjs/operators'
 import { HttpClient } from '@angular/common/http'
@@ -24,7 +25,6 @@ import {
 } from '@shared/models'
 import { environment } from '../../../environments/environment'
 import { RegisterClientHelpers } from '../../../types/register-client-option.model'
-import * as debug from 'debug'
 
 const logger = debug('peertube:plugins')
 
@@ -33,8 +33,6 @@ export class PluginService implements ClientHook {
   private static BASE_PLUGIN_API_URL = environment.apiUrl + '/api/v1/plugins'
   private static BASE_PLUGIN_URL = environment.apiUrl + '/plugins'
 
-  pluginsBuilt = new ReplaySubject<boolean>(1)
-
   pluginsLoaded: { [ scope in PluginClientScope ]: ReplaySubject<boolean> } = {
     common: new ReplaySubject<boolean>(1),
     'admin-plugin': new ReplaySubject<boolean>(1),
@@ -79,30 +77,18 @@ export class PluginService implements ClientHook {
   }
 
   initializePlugins () {
-    logger('Building plugin configuration')
+    const config = this.server.getHTMLConfig()
+    this.plugins = config.plugin.registered
 
-    this.server.getConfig()
-      .subscribe(config => {
-        this.plugins = config.plugin.registered
+    this.buildScopeStruct()
 
-        this.buildScopeStruct()
-
-        this.pluginsBuilt.next(true)
-
-        logger('Plugin configuration built')
-      })
+    this.ensurePluginsAreLoaded('common')
   }
 
   initializeCustomModal (customModal: CustomModalComponent) {
     this.customModal = customModal
   }
 
-  ensurePluginsAreBuilt () {
-    return this.pluginsBuilt.asObservable()
-               .pipe(first(), shareReplay())
-               .toPromise()
-  }
-
   ensurePluginsAreLoaded (scope: PluginClientScope) {
     this.loadPluginsByScope(scope)
 
@@ -156,8 +142,6 @@ export class PluginService implements ClientHook {
     logger('Loading scope %s', scope)
 
     try {
-      await this.ensurePluginsAreBuilt()
-
       if (!isReload) this.loadedScopes.push(scope)
 
       const toLoad = this.scopes[ scope ]
diff --git a/client/src/app/core/routing/homepage-redirect.component.ts b/client/src/app/core/routing/homepage-redirect.component.ts
new file mode 100644 (file)
index 0000000..9e38480
--- /dev/null
@@ -0,0 +1,30 @@
+import { Component, OnInit } from '@angular/core'
+import { ActivatedRoute } from '@angular/router'
+import { is18nPath } from '@shared/core-utils/i18n/i18n'
+import { RedirectService } from './redirect.service'
+
+/*
+ * We have to use a component instead of an homepage because of a weird issue when using router.navigate in guard
+ *
+ * Since we also want to use the `skipLocationChange` option, we cannot use a guard that returns a UrlTree
+ * See https://github.com/angular/angular/issues/27148
+*/
+
+@Component({
+  template: ''
+})
+export class HomepageRedirectComponent implements OnInit {
+
+  constructor (
+    private route: ActivatedRoute,
+    private redirectService: RedirectService
+  ) { }
+
+  ngOnInit () {
+    const url = this.route.snapshot.url
+
+    if (url.length === 0 || is18nPath('/' + url[0])) {
+      this.redirectService.redirectToHomepage(true)
+    }
+  }
+}
index 4314ea475ef78295a9b4be27c0b55d98ff9dae7d..d0c688a2f5f7882090eafeeb155948e84a0cc6e8 100644 (file)
@@ -1,6 +1,7 @@
 export * from './can-deactivate-guard.service'
 export * from './custom-reuse-strategy'
 export * from './disable-for-reuse-hook'
+export * from './homepage-redirect.component'
 export * from './login-guard.service'
 export * from './menu-guard.service'
 export * from './meta-guard.service'
index 198332b00bdd925363b576d541627549b9251e6a..17d9d1358b3a0db443a0f6b5a06eba3102cabfec 100644 (file)
@@ -42,7 +42,6 @@ export class RedirectService {
     return this.defaultRoute
   }
 
-
   getDefaultTrendingAlgorithm () {
     return this.defaultTrendingAlgorithm
   }
index eec325a611ba9b8884f2b794e374bd2129eabede..c3f10c055834dec2644fd2e8506f39dcd2467fb4 100644 (file)
@@ -44,7 +44,6 @@ export class ActorBannerEditComponent implements OnInit {
     this.bannerFormat = $localize`ratio 6/1, recommended size: 1920x317, max size: ${getBytes(this.maxBannerSize)}, extensions: ${this.bannerExtensions}`
   }
 
-
   onBannerChange (input: HTMLInputElement) {
     this.bannerfileInput = new ElementRef(input)
 
index 8c1c858b724c8d4d2b2f92fff02af75e76e067d7..10c111a8c4c593d12d6588bb66e4edce17fde923 100644 (file)
@@ -11,8 +11,8 @@ import {
   RegisterClientVideoFieldOptions,
   ServerConfigPlugin
 } from '../../../shared/models'
+import { environment } from '../environments/environment'
 import { ClientScript as ClientScriptModule } from '../types/client-script.model'
-import { importModule } from './utils'
 
 interface HookStructValue extends RegisterClientHookOptions {
   plugin: ServerConfigPlugin
@@ -101,7 +101,8 @@ function loadPlugin (options: {
 
   console.log('Loading script %s of plugin %s.', clientScript.script, plugin.name)
 
-  return importModule(clientScript.script)
+  const absURL = (environment.apiUrl || window.location.origin) + clientScript.script
+  return import(/* webpackIgnore: true */ absURL)
     .then((script: ClientScriptModule) => script.register({ registerHook, registerVideoField, registerSettingsScript, peertubeHelpers }))
     .then(() => sortHooksByPriority(hooks))
     .catch(err => console.error('Cannot import or register plugin %s.', pluginInfo.plugin.name, err))
index 06591b95e25414187cd72f76a4fead42d1bac223..00bd92411247aedfb890ea38fac7e3bd4acca28d 100644 (file)
@@ -1,5 +1,3 @@
-import { environment } from '../environments/environment'
-
 function objectToUrlEncoded (obj: any) {
   const str: string[] = []
   for (const key of Object.keys(obj)) {
@@ -21,41 +19,6 @@ function copyToClipboard (text: string) {
   document.body.removeChild(el)
 }
 
-// Thanks: https://github.com/uupaa/dynamic-import-polyfill
-function importModule (path: string) {
-  return new Promise((resolve, reject) => {
-    const vector = '$importModule$' + Math.random().toString(32).slice(2)
-    const script = document.createElement('script')
-
-    const destructor = () => {
-      delete window[ vector ]
-      script.onerror = null
-      script.onload = null
-      script.remove()
-      URL.revokeObjectURL(script.src)
-      script.src = ''
-    }
-
-    script.defer = true
-    script.type = 'module'
-
-    script.onerror = () => {
-      reject(new Error(`Failed to import: ${path}`))
-      destructor()
-    }
-    script.onload = () => {
-      resolve(window[ vector ])
-      destructor()
-    }
-    const absURL = (environment.apiUrl || window.location.origin) + path
-    const loader = `import * as m from "${absURL}"; window.${vector} = m;` // export Module
-    const blob = new Blob([ loader ], { type: 'text/javascript' })
-    script.src = URL.createObjectURL(blob)
-
-    document.head.appendChild(script)
-  })
-}
-
 function wait (ms: number) {
   return new Promise<void>(res => {
     setTimeout(() => res(), ms)
@@ -64,7 +27,6 @@ function wait (ms: number) {
 
 export {
   copyToClipboard,
-  importModule,
   objectToUrlEncoded,
   wait
 }