Speed up plugins loading
This commit is contained in:
parent
2989628b79
commit
fc21ef5c62
|
@ -11,7 +11,6 @@ export class MyLibraryComponent implements OnInit {
|
||||||
menuEntries: TopMenuDropdownParam[] = []
|
menuEntries: TopMenuDropdownParam[] = []
|
||||||
user: AuthUser
|
user: AuthUser
|
||||||
|
|
||||||
|
|
||||||
private serverConfig: HTMLServerConfig
|
private serverConfig: HTMLServerConfig
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
|
|
@ -99,7 +99,6 @@ export class SearchFiltersComponent implements OnInit {
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.serverConfig = this.serverService.getHTMLConfig()
|
this.serverConfig = this.serverService.getHTMLConfig()
|
||||||
|
|
||||||
|
|
||||||
this.serverService.getVideoCategories().subscribe(categories => this.videoCategories = categories)
|
this.serverService.getVideoCategories().subscribe(categories => this.videoCategories = categories)
|
||||||
this.serverService.getVideoLicences().subscribe(licences => this.videoLicences = licences)
|
this.serverService.getVideoLicences().subscribe(licences => this.videoLicences = licences)
|
||||||
this.serverService.getVideoLanguages().subscribe(languages => this.videoLanguages = languages)
|
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
|
const searchIndexConfig = this.serverConfig.search.searchIndex
|
||||||
|
|
||||||
if (searchIndexConfig.enabled && (searchIndexConfig.isDefaultSearch || searchIndexConfig.disableLocalSearch)) {
|
if (searchIndexConfig.enabled && (searchIndexConfig.isDefaultSearch || searchIndexConfig.disableLocalSearch)) {
|
||||||
|
|
|
@ -194,7 +194,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
this.serverConfig = this.serverService.getHTMLConfig()
|
this.serverConfig = this.serverService.getHTMLConfig()
|
||||||
|
|
||||||
this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
|
this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
|
||||||
|
|
|
@ -181,7 +181,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
this.hasAlreadyAcceptedPrivacyConcern = true
|
this.hasAlreadyAcceptedPrivacyConcern = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.paramsSub = this.route.params.subscribe(routeParams => {
|
this.paramsSub = this.route.params.subscribe(routeParams => {
|
||||||
const videoId = routeParams[ 'videoId' ]
|
const videoId = routeParams[ 'videoId' ]
|
||||||
if (videoId) this.loadVideo(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 { CustomReuseStrategy } from '@app/core/routing/custom-reuse-strategy'
|
||||||
import { MenuGuards } from '@app/core/routing/menu-guard.service'
|
import { MenuGuards } from '@app/core/routing/menu-guard.service'
|
||||||
import { POSSIBLE_LOCALES } from '@shared/core-utils/i18n'
|
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 { EmptyComponent } from './empty.component'
|
||||||
import { USER_USERNAME_REGEX_CHARACTERS } from './shared/form-validators/user-validators'
|
import { USER_USERNAME_REGEX_CHARACTERS } from './shared/form-validators/user-validators'
|
||||||
import { ActorRedirectGuard } from './shared/shared-main'
|
import { ActorRedirectGuard } from './shared/shared-main'
|
||||||
|
@ -156,7 +156,7 @@ const routes: Routes = [
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '',
|
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) {
|
for (const locale of POSSIBLE_LOCALES) {
|
||||||
routes.push({
|
routes.push({
|
||||||
path: locale,
|
path: locale,
|
||||||
component: EmptyComponent
|
component: HomepageRedirectComponent
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||||
import { concat } from 'rxjs'
|
import { filter, map, pairwise, switchMap } from 'rxjs/operators'
|
||||||
import { filter, first, map, pairwise, switchMap } from 'rxjs/operators'
|
|
||||||
import { DOCUMENT, PlatformLocation, ViewportScroller } from '@angular/common'
|
import { DOCUMENT, PlatformLocation, ViewportScroller } from '@angular/common'
|
||||||
import { AfterViewInit, Component, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core'
|
import { AfterViewInit, Component, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core'
|
||||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
|
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 { NgbConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { LoadingBarService } from '@ngx-loading-bar/core'
|
import { LoadingBarService } from '@ngx-loading-bar/core'
|
||||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
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 { BroadcastMessageLevel, HTMLServerConfig, ServerConfig, UserRole } from '@shared/models'
|
||||||
import { MenuService } from './core/menu/menu.service'
|
import { MenuService } from './core/menu/menu.service'
|
||||||
import { POP_STATE_MODAL_DISMISS } from './helpers'
|
import { POP_STATE_MODAL_DISMISS } from './helpers'
|
||||||
|
@ -75,7 +74,7 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
this.serverConfig = this.serverService.getHTMLConfig()
|
this.serverConfig = this.serverService.getHTMLConfig()
|
||||||
|
|
||||||
this.loadPlugins()
|
this.hooks.runAction('action:application.init', 'common')
|
||||||
this.themeService.initialize()
|
this.themeService.initialize()
|
||||||
|
|
||||||
this.authService.loadClientCredentials()
|
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
|
// Plugin hooks
|
||||||
navigationEndEvent.subscribe(e => {
|
navigationEndEvent.subscribe(e => {
|
||||||
this.hooks.runAction('action:router.navigation-end', 'common', { path: e.url })
|
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 () {
|
private async openModalsIfNeeded () {
|
||||||
this.authService.userInformationLoaded
|
this.authService.userInformationLoaded
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'focus-visible'
|
import 'focus-visible'
|
||||||
|
import { tap } from 'rxjs/operators'
|
||||||
import { environment } from 'src/environments/environment'
|
import { environment } from 'src/environments/environment'
|
||||||
import { APP_BASE_HREF, registerLocaleData } from '@angular/common'
|
import { APP_BASE_HREF, registerLocaleData } from '@angular/common'
|
||||||
import { APP_INITIALIZER, NgModule } from '@angular/core'
|
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 localeOc from '@app/helpers/locales/oc'
|
||||||
import { AppRoutingModule } from './app-routing.module'
|
import { AppRoutingModule } from './app-routing.module'
|
||||||
import { AppComponent } from './app.component'
|
import { AppComponent } from './app.component'
|
||||||
import { CoreModule, ServerService } from './core'
|
import { CoreModule, PluginService, ServerService } from './core'
|
||||||
import { EmptyComponent } from './empty.component'
|
import { EmptyComponent } from './empty.component'
|
||||||
import { HeaderComponent, SearchTypeaheadComponent, SuggestionComponent } from './header'
|
import { HeaderComponent, SearchTypeaheadComponent, SuggestionComponent } from './header'
|
||||||
import { HighlightPipe } from './header/highlight.pipe'
|
import { HighlightPipe } from './header/highlight.pipe'
|
||||||
|
@ -26,8 +27,14 @@ import { SharedUserInterfaceSettingsModule } from './shared/shared-user-settings
|
||||||
|
|
||||||
registerLocaleData(localeOc, 'oc')
|
registerLocaleData(localeOc, 'oc')
|
||||||
|
|
||||||
export function loadConfigFactory (server: ServerService) {
|
export function loadConfigFactory (server: ServerService, pluginService: PluginService) {
|
||||||
return () => server.loadHTMLConfig()
|
return () => {
|
||||||
|
const result = server.loadHTMLConfig()
|
||||||
|
|
||||||
|
if (result) return result.pipe(tap(() => pluginService.initializePlugins()))
|
||||||
|
|
||||||
|
return pluginService.initializePlugins()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -75,9 +82,9 @@ export function loadConfigFactory (server: ServerService) {
|
||||||
{
|
{
|
||||||
provide: APP_INITIALIZER,
|
provide: APP_INITIALIZER,
|
||||||
useFactory: loadConfigFactory,
|
useFactory: loadConfigFactory,
|
||||||
deps: [ ServerService ],
|
deps: [ ServerService, PluginService ],
|
||||||
multi: true
|
multi: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { throwIfAlreadyLoaded } from './module-import-guard'
|
||||||
import { Notifier } from './notification'
|
import { Notifier } from './notification'
|
||||||
import { HtmlRendererService, LinkifierService, MarkdownService } from './renderer'
|
import { HtmlRendererService, LinkifierService, MarkdownService } from './renderer'
|
||||||
import { RestExtractor, RestService } from './rest'
|
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 { CanDeactivateGuard } from './routing/can-deactivate-guard.service'
|
||||||
import { ServerConfigResolver } from './routing/server-config-resolver.service'
|
import { ServerConfigResolver } from './routing/server-config-resolver.service'
|
||||||
import { ScopedTokensService } from './scoped-tokens'
|
import { ScopedTokensService } from './scoped-tokens'
|
||||||
|
@ -36,13 +36,15 @@ import { LocalStorageService, ScreenService, SessionStorageService } from './wra
|
||||||
],
|
],
|
||||||
|
|
||||||
declarations: [
|
declarations: [
|
||||||
CheatSheetComponent
|
CheatSheetComponent,
|
||||||
|
HomepageRedirectComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
exports: [
|
exports: [
|
||||||
ToastModule,
|
ToastModule,
|
||||||
|
|
||||||
CheatSheetComponent
|
CheatSheetComponent,
|
||||||
|
HomepageRedirectComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import * as debug from 'debug'
|
||||||
import { Observable, of, ReplaySubject } from 'rxjs'
|
import { Observable, of, ReplaySubject } from 'rxjs'
|
||||||
import { catchError, first, map, shareReplay } from 'rxjs/operators'
|
import { catchError, first, map, shareReplay } from 'rxjs/operators'
|
||||||
import { HttpClient } from '@angular/common/http'
|
import { HttpClient } from '@angular/common/http'
|
||||||
|
@ -24,7 +25,6 @@ import {
|
||||||
} from '@shared/models'
|
} from '@shared/models'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
import { RegisterClientHelpers } from '../../../types/register-client-option.model'
|
import { RegisterClientHelpers } from '../../../types/register-client-option.model'
|
||||||
import * as debug from 'debug'
|
|
||||||
|
|
||||||
const logger = debug('peertube:plugins')
|
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_API_URL = environment.apiUrl + '/api/v1/plugins'
|
||||||
private static BASE_PLUGIN_URL = environment.apiUrl + '/plugins'
|
private static BASE_PLUGIN_URL = environment.apiUrl + '/plugins'
|
||||||
|
|
||||||
pluginsBuilt = new ReplaySubject<boolean>(1)
|
|
||||||
|
|
||||||
pluginsLoaded: { [ scope in PluginClientScope ]: ReplaySubject<boolean> } = {
|
pluginsLoaded: { [ scope in PluginClientScope ]: ReplaySubject<boolean> } = {
|
||||||
common: new ReplaySubject<boolean>(1),
|
common: new ReplaySubject<boolean>(1),
|
||||||
'admin-plugin': new ReplaySubject<boolean>(1),
|
'admin-plugin': new ReplaySubject<boolean>(1),
|
||||||
|
@ -79,30 +77,18 @@ export class PluginService implements ClientHook {
|
||||||
}
|
}
|
||||||
|
|
||||||
initializePlugins () {
|
initializePlugins () {
|
||||||
logger('Building plugin configuration')
|
const config = this.server.getHTMLConfig()
|
||||||
|
this.plugins = config.plugin.registered
|
||||||
|
|
||||||
this.server.getConfig()
|
this.buildScopeStruct()
|
||||||
.subscribe(config => {
|
|
||||||
this.plugins = config.plugin.registered
|
|
||||||
|
|
||||||
this.buildScopeStruct()
|
this.ensurePluginsAreLoaded('common')
|
||||||
|
|
||||||
this.pluginsBuilt.next(true)
|
|
||||||
|
|
||||||
logger('Plugin configuration built')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeCustomModal (customModal: CustomModalComponent) {
|
initializeCustomModal (customModal: CustomModalComponent) {
|
||||||
this.customModal = customModal
|
this.customModal = customModal
|
||||||
}
|
}
|
||||||
|
|
||||||
ensurePluginsAreBuilt () {
|
|
||||||
return this.pluginsBuilt.asObservable()
|
|
||||||
.pipe(first(), shareReplay())
|
|
||||||
.toPromise()
|
|
||||||
}
|
|
||||||
|
|
||||||
ensurePluginsAreLoaded (scope: PluginClientScope) {
|
ensurePluginsAreLoaded (scope: PluginClientScope) {
|
||||||
this.loadPluginsByScope(scope)
|
this.loadPluginsByScope(scope)
|
||||||
|
|
||||||
|
@ -156,8 +142,6 @@ export class PluginService implements ClientHook {
|
||||||
logger('Loading scope %s', scope)
|
logger('Loading scope %s', scope)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.ensurePluginsAreBuilt()
|
|
||||||
|
|
||||||
if (!isReload) this.loadedScopes.push(scope)
|
if (!isReload) this.loadedScopes.push(scope)
|
||||||
|
|
||||||
const toLoad = this.scopes[ 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 './can-deactivate-guard.service'
|
||||||
export * from './custom-reuse-strategy'
|
export * from './custom-reuse-strategy'
|
||||||
export * from './disable-for-reuse-hook'
|
export * from './disable-for-reuse-hook'
|
||||||
|
export * from './homepage-redirect.component'
|
||||||
export * from './login-guard.service'
|
export * from './login-guard.service'
|
||||||
export * from './menu-guard.service'
|
export * from './menu-guard.service'
|
||||||
export * from './meta-guard.service'
|
export * from './meta-guard.service'
|
||||||
|
|
|
@ -42,7 +42,6 @@ export class RedirectService {
|
||||||
return this.defaultRoute
|
return this.defaultRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getDefaultTrendingAlgorithm () {
|
getDefaultTrendingAlgorithm () {
|
||||||
return this.defaultTrendingAlgorithm
|
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}`
|
this.bannerFormat = $localize`ratio 6/1, recommended size: 1920x317, max size: ${getBytes(this.maxBannerSize)}, extensions: ${this.bannerExtensions}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onBannerChange (input: HTMLInputElement) {
|
onBannerChange (input: HTMLInputElement) {
|
||||||
this.bannerfileInput = new ElementRef(input)
|
this.bannerfileInput = new ElementRef(input)
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ import {
|
||||||
RegisterClientVideoFieldOptions,
|
RegisterClientVideoFieldOptions,
|
||||||
ServerConfigPlugin
|
ServerConfigPlugin
|
||||||
} from '../../../shared/models'
|
} from '../../../shared/models'
|
||||||
|
import { environment } from '../environments/environment'
|
||||||
import { ClientScript as ClientScriptModule } from '../types/client-script.model'
|
import { ClientScript as ClientScriptModule } from '../types/client-script.model'
|
||||||
import { importModule } from './utils'
|
|
||||||
|
|
||||||
interface HookStructValue extends RegisterClientHookOptions {
|
interface HookStructValue extends RegisterClientHookOptions {
|
||||||
plugin: ServerConfigPlugin
|
plugin: ServerConfigPlugin
|
||||||
|
@ -101,7 +101,8 @@ function loadPlugin (options: {
|
||||||
|
|
||||||
console.log('Loading script %s of plugin %s.', clientScript.script, plugin.name)
|
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((script: ClientScriptModule) => script.register({ registerHook, registerVideoField, registerSettingsScript, peertubeHelpers }))
|
||||||
.then(() => sortHooksByPriority(hooks))
|
.then(() => sortHooksByPriority(hooks))
|
||||||
.catch(err => console.error('Cannot import or register plugin %s.', pluginInfo.plugin.name, err))
|
.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) {
|
function objectToUrlEncoded (obj: any) {
|
||||||
const str: string[] = []
|
const str: string[] = []
|
||||||
for (const key of Object.keys(obj)) {
|
for (const key of Object.keys(obj)) {
|
||||||
|
@ -21,41 +19,6 @@ function copyToClipboard (text: string) {
|
||||||
document.body.removeChild(el)
|
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) {
|
function wait (ms: number) {
|
||||||
return new Promise<void>(res => {
|
return new Promise<void>(res => {
|
||||||
setTimeout(() => res(), ms)
|
setTimeout(() => res(), ms)
|
||||||
|
@ -64,7 +27,6 @@ function wait (ms: number) {
|
||||||
|
|
||||||
export {
|
export {
|
||||||
copyToClipboard,
|
copyToClipboard,
|
||||||
importModule,
|
|
||||||
objectToUrlEncoded,
|
objectToUrlEncoded,
|
||||||
wait
|
wait
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue