From 06e695b2eb268186716f4ffb068d434b4b768232 Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Wed, 11 Jan 2023 21:37:12 +0100 Subject: [PATCH 1/5] Vue 3: Use createApp and update portal-vue --- changelog/unreleased/change-update-vue | 1 + packages/web-runtime/package.json | 2 +- packages/web-runtime/src/container/api.ts | 11 +++--- .../src/container/application/classic.ts | 6 +-- .../src/container/application/next.ts | 4 +- packages/web-runtime/src/defaults/vue.js | 2 - packages/web-runtime/src/index.ts | 29 ++++++++------ .../web-test-helpers/src/defaultPlugins.ts | 3 +- pnpm-lock.yaml | 39 +++++++++++++++---- 9 files changed, 61 insertions(+), 36 deletions(-) diff --git a/changelog/unreleased/change-update-vue b/changelog/unreleased/change-update-vue index 0afd2c59423..c9a224c26c9 100644 --- a/changelog/unreleased/change-update-vue +++ b/changelog/unreleased/change-update-vue @@ -13,3 +13,4 @@ https://github.com/owncloud/web/pull/8201 https://github.com/owncloud/web/pull/8202 https://github.com/owncloud/web/pull/8198 https://github.com/owncloud/web/pull/8213 +https://github.com/owncloud/web/pull/8214 diff --git a/packages/web-runtime/package.json b/packages/web-runtime/package.json index f6ef37afb95..95ed4d375d5 100644 --- a/packages/web-runtime/package.json +++ b/packages/web-runtime/package.json @@ -28,7 +28,7 @@ "owncloud-sdk": "~3.1.0-alpha.1", "p-queue": "^6.6.2", "popper-max-size-modifier": "^0.2.0", - "portal-vue": "^2.1.7", + "portal-vue": "3.0.0-beta.0", "postcss-import": "^12.0.1", "postcss-url": "^9.0.0", "promise": "^8.1.0", diff --git a/packages/web-runtime/src/container/api.ts b/packages/web-runtime/src/container/api.ts index 0dc1e4dffa9..b9e4ff2ddb0 100644 --- a/packages/web-runtime/src/container/api.ts +++ b/packages/web-runtime/src/container/api.ts @@ -9,8 +9,7 @@ import { import { ApiError } from './error' import { get, isEqual, isObject, isArray } from 'lodash-es' import { Store } from 'vuex' -import Vue, { Component } from 'vue' -import { Wormhole } from 'portal-vue' +import { App, Component, h } from 'vue' /** * inject application specific routes into runtime @@ -170,17 +169,17 @@ const announceStore = ( */ const openPortal = ( applicationId: string, - instance: typeof Vue.prototype, + instance: App, toApp: string, toPortal: string, order: number, components: Component[] ): void => { - Wormhole.open({ + instance.config.globalProperties.$wormhole.open({ to: ['app', toApp, toPortal].filter(Boolean).join('.'), from: ['app', applicationId, toPortal, order].filter(Boolean).join('.'), order: order, - passengers: components.map(instance.$createElement) + content: () => components.map(h) }) } @@ -265,7 +264,7 @@ export const buildRuntimeApi = ({ requestStore: (): Store => requestStore(store), requestRouter: (): VueRouter => requestRouter(router), openPortal: ( - instance: typeof Vue.prototype, + instance: App, toApp: string, toPortal: string, order: number, diff --git a/packages/web-runtime/src/container/application/classic.ts b/packages/web-runtime/src/container/application/classic.ts index 007b242c9dd..4f8e18da68c 100644 --- a/packages/web-runtime/src/container/application/classic.ts +++ b/packages/web-runtime/src/container/application/classic.ts @@ -1,6 +1,6 @@ import { ClassicApplicationScript, RuntimeApi } from '../types' import { buildRuntimeApi } from '../api' -import Vue from 'vue' +import Vue, { App } from 'vue' import { isFunction, isObject } from 'lodash-es' import { NextApplication } from './next' import { Store } from 'vuex' @@ -39,13 +39,13 @@ class ClassicApplication extends NextApplication { return Promise.resolve(undefined) } - mounted(instance: VueConstructor): Promise { + mounted(instance: App): Promise { const { mounted: mountedHook } = this.applicationScript this.attachPublicApi(mountedHook, instance) return Promise.resolve(undefined) } - private attachPublicApi(hook: unknown, instance?: VueConstructor) { + private attachPublicApi(hook: unknown, instance?: App) { isFunction(hook) && hook({ ...(instance && { diff --git a/packages/web-runtime/src/container/application/next.ts b/packages/web-runtime/src/container/application/next.ts index 2fd197f9cb9..89283f2850f 100644 --- a/packages/web-runtime/src/container/application/next.ts +++ b/packages/web-runtime/src/container/application/next.ts @@ -1,4 +1,4 @@ -import Vue from 'vue' +import Vue, { App } from 'vue' import { RuntimeApi } from '../types' type VueConstructor = typeof Vue @@ -13,5 +13,5 @@ export abstract class NextApplication { abstract ready(): Promise - abstract mounted(instance: VueConstructor): Promise + abstract mounted(instance: App): Promise } diff --git a/packages/web-runtime/src/defaults/vue.js b/packages/web-runtime/src/defaults/vue.js index 3d54be32d40..f3728b95861 100644 --- a/packages/web-runtime/src/defaults/vue.js +++ b/packages/web-runtime/src/defaults/vue.js @@ -4,7 +4,6 @@ import Avatar from '../components/Avatar.vue' import focusMixin from '../mixins/focusMixin' import lifecycleMixin from '../mixins/lifecycleMixin' import VueMeta from 'vue-meta' -import PortalVue from 'portal-vue' import VueRouter from 'vue-router' import Vuex from 'vuex' @@ -14,7 +13,6 @@ Vue.use(WebPlugin) Vue.use(VueMeta, { refreshOnceOnNavigation: true }) -Vue.use(PortalVue) Vue.component('AvatarImage', Avatar) diff --git a/packages/web-runtime/src/index.ts b/packages/web-runtime/src/index.ts index 7e48472f972..a3491f89516 100644 --- a/packages/web-runtime/src/index.ts +++ b/packages/web-runtime/src/index.ts @@ -36,8 +36,9 @@ import { } from 'web-client/src/helpers' import { WebDAV } from 'web-client/src/webdav' import { DavProperty } from 'web-client/src/webdav/constants' -import { configureCompat, h } from 'vue' +import { configureCompat, createApp, h } from 'vue' import { compatConfig } from './compatConfig' +import PortalVue, { createWormhole } from 'portal-vue' configureCompat(compatConfig) @@ -67,8 +68,7 @@ export const renderSuccess = (): void => { Vue.prototype.$store = store const applications = Array.from(applicationStore.values()) - const instance = new Vue({ - el: '#owncloud', + const instance = createApp({ store, router, render() { @@ -76,10 +76,16 @@ export const renderSuccess = (): void => { } }) - instance.$once('mounted', () => { - applications.forEach((application) => application.mounted(instance)) + // create wormhole + instance.config.globalProperties.$wormhole = createWormhole() + instance.use(PortalVue, { + wormhole: instance.config.globalProperties.$wormhole }) + // mount App + instance.mount('#owncloud') + applications.forEach((application) => application.mounted(instance)) + store.watch( (state, getters) => getters['runtime/auth/isUserContextReady'] || @@ -104,7 +110,7 @@ export const renderSuccess = (): void => { if (!userContextReady) { return } - const clientService = instance.$clientService + const clientService = instance.config.globalProperties.$clientService // Load spaces to make them available across the application if (store.getters.capabilities?.spaces?.enabled) { @@ -119,7 +125,7 @@ export const renderSuccess = (): void => { store.commit('runtime/spaces/UPDATE_SPACE_FIELD', { id: personalSpace.id, field: 'name', - value: instance.$gettext('Personal') + value: instance.config.globalProperties.$gettext('Personal') }) return } @@ -130,7 +136,7 @@ export const renderSuccess = (): void => { id: user.id, driveAlias: `personal/${user.id}`, driveType: 'personal', - name: instance.$gettext('All files'), + name: instance.config.globalProperties.$gettext('All files'), webDavPath: `/files/${user.id}`, webDavTrashPath: `/trash-bin/${user.id}`, serverUrl: configurationManager.serverUrl @@ -163,7 +169,7 @@ export const renderSuccess = (): void => { const publicLinkPassword = store.getters['runtime/auth/publicLinkPassword'] const space = buildPublicSpaceResource({ id: publicLinkToken, - name: instance.$gettext('Public files'), + name: instance.config.globalProperties.$gettext('Public files'), ...(publicLinkPassword && { publicLinkPassword }), serverUrl: configurationManager.serverUrl }) @@ -198,13 +204,12 @@ export const renderFailure = async (err: Error): Promise => { await announceTranslations({ vue: Vue, supportedLanguages, translations }) await announceTheme({ store, vue: Vue, designSystem }) console.error(err) - new Vue({ - el: '#owncloud', + createApp({ store, render() { return h(pages.failure) } - }) + }).mount('#owncloud') } ;(window as any).runtimeLoaded({ bootstrap, diff --git a/packages/web-test-helpers/src/defaultPlugins.ts b/packages/web-test-helpers/src/defaultPlugins.ts index 7b279331bf7..3be6522f24e 100644 --- a/packages/web-test-helpers/src/defaultPlugins.ts +++ b/packages/web-test-helpers/src/defaultPlugins.ts @@ -1,8 +1,7 @@ import DesignSystem from '@ownclouders/design-system' import GetTextPlugin from 'vue-gettext' import Vue from 'vue' - -window.Vue = Vue +;(window as any).Vue = Vue export interface DefaultPluginsOptions { designSystem?: boolean diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 638335e6bdd..e615b77668d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -506,7 +506,7 @@ importers: web-runtime: link:../web-runtime devDependencies: '@jest/globals': 29.3.1 - '@vueuse/core': 9.8.2_vue@3.2.45 + '@vueuse/core': 9.8.2 packages/web-app-pdf-viewer: specifiers: @@ -634,7 +634,7 @@ importers: owncloud-sdk: ~3.1.0-alpha.1 p-queue: ^6.6.2 popper-max-size-modifier: ^0.2.0 - portal-vue: ^2.1.7 + portal-vue: 3.0.0-beta.0 postcss-import: ^12.0.1 postcss-url: ^9.0.0 promise: ^8.1.0 @@ -683,7 +683,7 @@ importers: owncloud-sdk: 3.1.0-alpha.1_qgpf6seimtkgc6dfu7oqfstxh4 p-queue: 6.6.2 popper-max-size-modifier: 0.2.0_@popperjs+core@2.11.5 - portal-vue: 2.1.7_vue@3.2.45 + portal-vue: 3.0.0-beta.0_vue@3.2.45 postcss-import: 12.0.1 postcss-url: 9.0.0 promise: 8.1.0 @@ -6541,13 +6541,13 @@ packages: - supports-color dev: true - /@vueuse/core/9.8.2_vue@3.2.45: + /@vueuse/core/9.8.2: resolution: {integrity: sha512-aWiCmcYIpPt7xjuqYiceODEMHchDYthrJ4AqI+FXPZrR23PZOqdiktbUVyQl2kGlR3H4i9UJ/uimQrwhz9UouQ==} dependencies: '@types/web-bluetooth': 0.0.16 '@vueuse/metadata': 9.8.2 - '@vueuse/shared': 9.8.2_vue@3.2.45 - vue-demi: 0.13.11_vue@3.2.45 + '@vueuse/shared': 9.8.2 + vue-demi: 0.13.11 transitivePeerDependencies: - '@vue/composition-api' - vue @@ -6557,10 +6557,10 @@ packages: resolution: {integrity: sha512-N4E/BKS+9VsUeD4WLVRU1J2kCOLh+iikBcMtipFcTyL204132vDYHs27zLAVabJYGnhC0dIVGdhg9pbOZiY2TQ==} dev: true - /@vueuse/shared/9.8.2_vue@3.2.45: + /@vueuse/shared/9.8.2: resolution: {integrity: sha512-ACjrPQzowd5dnabNJt9EoGVobco9/ENiA5qP53vjiuxndlJYuc/UegwhXC7KdQbPX4F45a50+45K3g1wNqOzmA==} dependencies: - vue-demi: 0.13.11_vue@3.2.45 + vue-demi: 0.13.11 transitivePeerDependencies: - '@vue/composition-api' - vue @@ -17868,6 +17868,15 @@ packages: vue: 3.2.45 dev: false + /portal-vue/3.0.0-beta.0_vue@3.2.45: + resolution: {integrity: sha512-ktV+Q0fwlsjeF+2xGebMxrN6xH8yMdmbLzYbd2OfcgU4OmzSmkj6iP3kBQRGa+7A5WZlqCHWaFfecNs9Igsv9w==} + engines: {node: '>=14'} + peerDependencies: + vue: ^3.0.4 + dependencies: + vue: 3.2.45 + dev: false + /portfinder/1.0.32_supports-color@6.1.0: resolution: {integrity: sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==} engines: {node: '>= 0.12.0'} @@ -22050,6 +22059,19 @@ packages: vue: 3.2.45 dev: false + /vue-demi/0.13.11: + resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dev: true + /vue-demi/0.13.11_vue@3.2.45: resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==} engines: {node: '>=12'} @@ -22063,6 +22085,7 @@ packages: optional: true dependencies: vue: 3.2.45 + dev: false /vue-docgen-api/4.56.0_vue@3.2.45: resolution: {integrity: sha512-ab/Scb0DCjm4YVLf+AFa/R7XMFl8TVwUsvh26fFT5iaURih1m2hdd5Y8NveA7NQDcycpWavkFZj9eVbQdp2VGQ==} From 822a9eb8bded534522462e9945ea64a1048f8a0e Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Thu, 12 Jan 2023 00:56:27 +0100 Subject: [PATCH 2/5] Fix production builds --- packages/web-runtime/src/container/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-runtime/src/container/api.ts b/packages/web-runtime/src/container/api.ts index b9e4ff2ddb0..b12384d703d 100644 --- a/packages/web-runtime/src/container/api.ts +++ b/packages/web-runtime/src/container/api.ts @@ -179,7 +179,7 @@ const openPortal = ( to: ['app', toApp, toPortal].filter(Boolean).join('.'), from: ['app', applicationId, toPortal, order].filter(Boolean).join('.'), order: order, - content: () => components.map(h) + content: () => components.map((c) => h(c)) }) } From 8a85139b6251e734f4d87e844ddbc7ba0725539e Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Thu, 12 Jan 2023 01:24:36 +0100 Subject: [PATCH 3/5] Make global portal-vue components known to typescript --- packages/web-runtime/src/components/Topbar/TopBar.vue | 2 +- web.d.ts | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/web-runtime/src/components/Topbar/TopBar.vue b/packages/web-runtime/src/components/Topbar/TopBar.vue index 9f0f1cc8309..b7719762c2d 100644 --- a/packages/web-runtime/src/components/Topbar/TopBar.vue +++ b/packages/web-runtime/src/components/Topbar/TopBar.vue @@ -22,7 +22,7 @@ -