Speed up plugins loading
This commit is contained in:
parent
2989628b79
commit
fc21ef5c62
|
@ -11,7 +11,6 @@ export class MyLibraryComponent implements OnInit {
|
|||
menuEntries: TopMenuDropdownParam[] = []
|
||||
user: AuthUser
|
||||
|
||||
|
||||
private serverConfig: HTMLServerConfig
|
||||
|
||||
constructor (
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -194,7 +194,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
this.serverConfig = this.serverService.getHTMLConfig()
|
||||
|
||||
this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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: [
|
||||
|
|
|
@ -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 ]
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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'
|
||||
|
|
|
@ -42,7 +42,6 @@ export class RedirectService {
|
|||
return this.defaultRoute
|
||||
}
|
||||
|
||||
|
||||
getDefaultTrendingAlgorithm () {
|
||||
return this.defaultTrendingAlgorithm
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue