Skip to content

Commit

Permalink
perf: reduce network load on token renewal
Browse files Browse the repository at this point in the history
Reduces the network load on token renewal by not bootstrapping the whole application. Parts that are skipped loading during token renewal are:

* loading applications
* loading the inter font
* loading translations
* loading the theme
  • Loading branch information
JammingBen committed Jun 20, 2024
1 parent 26235d6 commit 566f5fb
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Reduce network load on token renewal

We've reduced the network load on token renewal, resulting in better overall performance of the Web client.

https://github.com/owncloud/web/pull/11077
https://github.com/owncloud/web/issues/11069
5 changes: 3 additions & 2 deletions packages/design-system/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getSizeClass } from './utils/sizeClasses'
import './utils/webFontLoader'
import { App } from 'vue'

import * as components from './components'
Expand All @@ -19,7 +18,9 @@ export const applyCustomProp = (key: string, value: string | undefined) => {
}

export default {
install(app: App, options: any = {}) {
async install(app: App, options: any = {}) {
await import('./utils/webFontLoader')

const themeOptions = options.tokens
initializeCustomProps(themeOptions?.breakpoints, 'breakpoint-')
initializeCustomProps(themeOptions?.colorPalette, 'color-')
Expand Down
36 changes: 34 additions & 2 deletions packages/web-runtime/src/container/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { registerClient } from '../services/clientRegistration'
import { buildApplication, NextApplication } from './application'
import { RouteLocationRaw, Router, RouteRecordNormalized } from 'vue-router'
import { App, watch } from 'vue'
import { App, computed, watch } from 'vue'
import { loadTheme } from '../helpers/theme'
import { createGettext, GetTextOptions, Language, Translations } from 'vue3-gettext'
import { getBackendVersion, getWebVersion } from './versions'
Expand All @@ -28,7 +28,8 @@ import {
ResourcesStore,
SpacesStore,
MessageStore,
SharesStore
SharesStore,
ArchiverService
} from '@ownclouders/web-pkg'
import { authService } from '../services/auth'
import {
Expand Down Expand Up @@ -410,6 +411,37 @@ export const announceClientService = ({
app.provide('$clientService', clientService)
}

export const announceArchiverService = ({
app,
configStore,
userStore,
capabilityStore
}: {
app: App
configStore: ConfigStore
userStore: UserStore
capabilityStore: CapabilityStore
}): void => {
app.config.globalProperties.$archiverService = new ArchiverService(
app.config.globalProperties.$clientService,
userStore,
configStore.serverUrl,
computed(
() =>
capabilityStore.filesArchivers || [
{
enabled: true,
version: '1.0.0',
formats: ['tar', 'zip'],
archiver_url: `${configStore.serverUrl}index.php/apps/files/ajax/download.php`
}
]
)
)

app.provide('$archiverService', app.config.globalProperties.$archiverService)
}

/**
* @param vue
*/
Expand Down
18 changes: 13 additions & 5 deletions packages/web-runtime/src/defaults/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import merge from 'lodash-es/merge'
import App from '../App.vue'
import TokenRenewal from '../pages/tokenRenewal.vue'
import missingOrInvalidConfigPage from '../pages/missingOrInvalidConfig.vue'

// fontawesome-free attributions console message
import '@fortawesome/fontawesome-free/attribution'

export { default as DesignSystem } from 'design-system'
export * from './languages'

export const pages = { success: App, failure: missingOrInvalidConfigPage }
export const pages = {
success: App,
failure: missingOrInvalidConfigPage,
tokenRenewal: TokenRenewal
}

export const loadTranslations = async () => {
const { coreTranslations, clientTranslations, pkgTranslations, odsTranslations } = await import(
Expand All @@ -17,3 +18,10 @@ export const loadTranslations = async () => {

return merge({}, coreTranslations, clientTranslations, pkgTranslations, odsTranslations)
}

export const loadDesignSystem = async () => {
// fontawesome-free attributions console message
import('@fortawesome/fontawesome-free/attribution')

return (await import('design-system')).default
}
1 change: 1 addition & 0 deletions packages/web-runtime/src/helpers/silentRedirect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const isSilentRedirectRoute = () => window.location.pathname === '/web-oidc-silent-redirect'
122 changes: 56 additions & 66 deletions packages/web-runtime/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
DesignSystem as designSystem,
pages,
loadTranslations,
supportedLanguages
} from './defaults'
import { loadDesignSystem, pages, loadTranslations, supportedLanguages } from './defaults'
import { router } from './router'
import { PortalTarget } from '@ownclouders/web-pkg'
import { createHead } from '@vueuse/head'
Expand Down Expand Up @@ -31,7 +26,8 @@ import {
announcePasswordPolicyService,
registerSSEEventListeners,
setViewOptions,
announceGettext
announceGettext,
announceArchiverService
} from './container/bootstrap'
import { applicationStore } from './container/store'
import {
Expand All @@ -41,18 +37,20 @@ import {
PublicSpaceResource
} from '@ownclouders/web-client'
import { loadCustomTranslations } from 'web-runtime/src/helpers/customTranslations'
import { computed, createApp, watch } from 'vue'
import { createApp, watch } from 'vue'
import PortalVue, { createWormhole } from 'portal-vue'
import { createPinia } from 'pinia'
import Avatar from './components/Avatar.vue'
import focusMixin from './mixins/focusMixin'
import { ArchiverService } from '@ownclouders/web-pkg'
import { UnifiedRoleDefinition } from '@ownclouders/web-client/graph/generated'
import { extensionPoints } from './extensionPoints'
import { isSilentRedirectRoute } from './helpers/silentRedirect'

export const bootstrapApp = async (configurationPath: string, appsReadyCallback: () => void) => {
const isSilentRedirect = isSilentRedirectRoute()

const pinia = createPinia()
const app = createApp(pages.success)
const app = createApp(isSilentRedirect ? pages.tokenRenewal : pages.success)
app.use(pinia)

const {
Expand All @@ -74,65 +72,12 @@ export const bootstrapApp = async (configurationPath: string, appsReadyCallback:
app.provide('$router', router)

await announceConfiguration({ path: configurationPath, configStore })
startSentry(configStore, app)

app.use(abilitiesPlugin, createMongoAbility([]), { useGlobalProperties: true })

const gettext = announceGettext({ app, availableLanguages: supportedLanguages })

announceUppyService({ app })
announceClientService({ app, configStore, authStore })

// TODO: move to announceArchiverService function
app.config.globalProperties.$archiverService = new ArchiverService(
app.config.globalProperties.$clientService,
userStore,
configStore.serverUrl,
computed(
() =>
capabilityStore.filesArchivers || [
{
enabled: true,
version: '1.0.0',
formats: ['tar', 'zip'],
archiver_url: `${configStore.serverUrl}index.php/apps/files/ajax/download.php`
}
]
)
)
app.provide('$archiverService', app.config.globalProperties.$archiverService)
announceLoadingService({ app })
announcePreviewService({
app,
configStore,
userStore,
authStore,
capabilityStore
})
announcePasswordPolicyService({ app })
await announceClient(configStore)

app.config.globalProperties.$wormhole = createWormhole()
app.use(PortalVue, {
wormhole: app.config.globalProperties.$wormhole,
// do not register portal-target component so we can register our own wrapper
portalTargetName: false
})
app.component('PortalTarget', PortalTarget)

const applicationsPromise = initializeApplications({ app, configStore, router })
const translationsPromise = loadTranslations()
const customTranslationsPromise = loadCustomTranslations({ configStore })
const themePromise = announceTheme({ app, designSystem, configStore })
const [coreTranslations, customTranslations] = await Promise.all([
translationsPromise,
customTranslationsPromise,
applicationsPromise,
themePromise
])

announceTranslations({ appsStore, gettext, coreTranslations, customTranslations })

announceAuthService({
app,
configStore,
Expand All @@ -142,9 +87,49 @@ export const bootstrapApp = async (configurationPath: string, appsReadyCallback:
capabilityStore,
webWorkersStore
})
announceCustomStyles({ configStore })
announceCustomScripts({ configStore })
announceDefaults({ appsStore, router, extensionRegistry, configStore })

if (!isSilentRedirect) {
const designSystem = await loadDesignSystem()

announceUppyService({ app })
startSentry(configStore, app)
announceArchiverService({ app, configStore, userStore, capabilityStore })
announceLoadingService({ app })
announcePreviewService({
app,
configStore,
userStore,
authStore,
capabilityStore
})
announcePasswordPolicyService({ app })
await announceClient(configStore)

app.config.globalProperties.$wormhole = createWormhole()
app.use(PortalVue, {
wormhole: app.config.globalProperties.$wormhole,
// do not register portal-target component so we can register our own wrapper
portalTargetName: false
})
app.component('PortalTarget', PortalTarget)

const applicationsPromise = initializeApplications({ app, configStore, router })
const translationsPromise = loadTranslations()
const customTranslationsPromise = loadCustomTranslations({ configStore })
const themePromise = announceTheme({ app, designSystem, configStore })
const [coreTranslations, customTranslations] = await Promise.all([
translationsPromise,
customTranslationsPromise,
applicationsPromise,
themePromise
])

announceTranslations({ appsStore, gettext, coreTranslations, customTranslations })

announceCustomStyles({ configStore })
announceCustomScripts({ configStore })
announceDefaults({ appsStore, router, extensionRegistry, configStore })
}

app.use(router)
app.use(createHead())
Expand All @@ -154,6 +139,10 @@ export const bootstrapApp = async (configurationPath: string, appsReadyCallback:

app.mount('#owncloud')

if (isSilentRedirect) {
return
}

setViewOptions({ resourcesStore })

const applications = Array.from(applicationStore.values())
Expand Down Expand Up @@ -273,6 +262,7 @@ export const bootstrapErrorApp = async (err: Error): Promise<void> => {
const { capabilityStore, configStore } = announcePiniaStores()
announceVersions({ capabilityStore })
const app = createApp(pages.failure)
const designSystem = await loadDesignSystem()
await announceTheme({ app, designSystem, configStore })
console.error(err)
const translations = await loadTranslations()
Expand Down
4 changes: 2 additions & 2 deletions packages/web-runtime/src/pages/oidcCallback.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export default defineComponent({
const error = ref(false)
const footerSlogan = computed(() => currentTheme.value.common.slogan)
const logoImg = computed(() => currentTheme.value.logo.login)
const footerSlogan = computed(() => unref(currentTheme)?.common.slogan)
const logoImg = computed(() => unref(currentTheme)?.logo.login)
const route = useRoute()
Expand Down
13 changes: 13 additions & 0 deletions packages/web-runtime/src/pages/tokenRenewal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<template>
<router-view />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
/**
* This page gets rendered in the iFrame for the silent token renewal to take place.
*/
export default defineComponent({
name: 'TokenRenewal'
})
</script>
5 changes: 4 additions & 1 deletion packages/web-runtime/src/services/auth/authService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Ability } from '@ownclouders/web-client'
import { Language } from 'vue3-gettext'
import { PublicLinkType } from '@ownclouders/web-client'
import { WebWorkersStore } from '@ownclouders/web-pkg'
import { isSilentRedirectRoute } from '../../helpers/silentRedirect'

export class AuthService implements AuthServiceInterface {
private clientService: ClientService
Expand Down Expand Up @@ -109,7 +110,9 @@ export class AuthService implements AuthServiceInterface {
accessTokenExpiryThreshold: this.accessTokenExpiryThreshold
})

if (!this.tokenTimerWorker) {
// don't load worker in the silent redirect iframe
const isSilentRedirect = isSilentRedirectRoute()
if (!this.tokenTimerWorker && !isSilentRedirect) {
const { options } = this.configStore

if (!options.embed?.enabled || !options.embed?.delegateAuthentication) {
Expand Down

0 comments on commit 566f5fb

Please sign in to comment.