Skip to content

Commit 780575c

Browse files
committed
fix: lazy load files sidebar tab
The global sidebar tab entrypoint was eagerly importing the Files tab component, which pulled LibreSign router code into unrelated apps and rewrote app navigation paths such as Deck. Fixes #7321 Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent 43ea40a commit 780575c

1 file changed

Lines changed: 33 additions & 22 deletions

File tree

src/tab.ts

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@
44
*/
55

66
import { createPinia } from 'pinia'
7-
import { createApp } from 'vue'
7+
import { createApp, type App as VueApp } from 'vue'
88

99
import { loadState } from '@nextcloud/initial-state'
1010
import { t, n } from '@nextcloud/l10n'
1111
import { FileType, registerSidebarTab } from '@nextcloud/files'
1212

1313
import LibreSignLogoDarkSvg from '../img/app-dark.svg?raw'
1414

15-
import AppFilesTab from './components/RightSidebar/AppFilesTab.vue'
16-
1715
import './style/icons.scss'
1816

1917
if (!window.OCA.Libresign) {
@@ -79,11 +77,13 @@ function mapNodeToFileInfo(node: SidebarNode = {}): FileInfo {
7977
interface LibreSignSidebarTabElement extends HTMLElement {
8078
_node?: SidebarNode
8179
_active?: boolean
80+
_vueApp?: VueApp<Element> | null
8281
_vueInstance?: TabComponentInstance | null
82+
_mountPromise?: Promise<void> | null
8383
node?: SidebarNode
8484
update(fileInfo: FileInfo): void
8585
setActive(active: boolean): Promise<void>
86-
mountVue(): void
86+
mountVue(): Promise<void>
8787
destroyVue(): void
8888
updateFromNode(): void
8989
}
@@ -98,11 +98,12 @@ function setupCustomElement() {
9898
class LibreSignSidebarTab extends HTMLElement implements LibreSignSidebarTabElement {
9999
_node?: SidebarNode
100100
_active?: boolean
101+
_vueApp?: VueApp<Element> | null
101102
_vueInstance?: TabComponentInstance | null
103+
_mountPromise?: Promise<void> | null
102104

103105
connectedCallback() {
104-
this.mountVue()
105-
this.updateFromNode()
106+
void this.mountVue()
106107
}
107108

108109
disconnectedCallback() {
@@ -132,35 +133,45 @@ function setupCustomElement() {
132133
}
133134
}
134135

135-
mountVue() {
136-
if (this._vueInstance) {
137-
return
136+
async mountVue() {
137+
if (this._vueInstance || this._mountPromise) {
138+
return this._mountPromise ?? Promise.resolve()
138139
}
139140

140-
const app = createApp(AppFilesTab)
141-
app.config.globalProperties.t = t
142-
app.config.globalProperties.n = n
143-
app.use(pinia)
141+
this._mountPromise = (async () => {
142+
const { default: AppFilesTab } = await import('./components/RightSidebar/AppFilesTab.vue')
143+
if (!this.isConnected || this._vueInstance) {
144+
return
145+
}
146+
147+
const app = createApp(AppFilesTab)
148+
app.config.globalProperties.t = t
149+
app.config.globalProperties.n = n
150+
app.use(pinia)
151+
152+
const element = document.createElement('div')
153+
this._vueApp = app
154+
this._vueInstance = app.mount(element)
155+
this.appendChild(element)
156+
this.updateFromNode()
157+
})().finally(() => {
158+
this._mountPromise = null
159+
})
144160

145-
const element = document.createElement('div')
146-
this._vueInstance = app.mount(element)
147-
this.appendChild(element)
161+
return this._mountPromise
148162
}
149163

150164
destroyVue() {
151-
if (this._vueInstance && this._vueInstance.$el) {
152-
// For Vue 3, we need to unmount the app
153-
// The best way would be to track the app instance
154-
this._vueInstance = null
155-
}
165+
this._vueApp?.unmount()
166+
this._vueApp = null
167+
this._vueInstance = null
156168
}
157169

158170
updateFromNode() {
159171
if (!this._vueInstance || !this._node) {
160172
return
161173
}
162174
const fileInfo = mapNodeToFileInfo(this._node)
163-
// Call update on the mounted component if it exists
164175
if (typeof this._vueInstance.update === 'function') {
165176
this._vueInstance.update(fileInfo)
166177
}

0 commit comments

Comments
 (0)