From ca4013bbfa0027261c4fbc83463f88a9b4cf7c73 Mon Sep 17 00:00:00 2001 From: Razvan Stoenescu Date: Wed, 24 Jan 2024 16:28:33 +0200 Subject: [PATCH 1/6] chore: Bump Vue to 3.4 on all packages devDeps --- app-vite/package.json | 2 +- ui/package.json | 2 +- utils/render-ssr-error/package.json | 2 +- yarn.lock | 113 +++++++++++++++++++++++++++- 4 files changed, 114 insertions(+), 5 deletions(-) diff --git a/app-vite/package.json b/app-vite/package.json index a1dbff79bc2..493ee410c4d 100644 --- a/app-vite/package.json +++ b/app-vite/package.json @@ -98,7 +98,7 @@ "quasar": "^2.14.0", "ts-essentials": "^9.1.2", "typescript": "^5.2.2", - "vue": "^3.3.4", + "vue": "^3.4.15", "vue-router": "^4.2.1", "vuex": "^4.0.0", "workbox-build": "^7.0.0" diff --git a/ui/package.json b/ui/package.json index 1b0f359212b..21413d478f7 100644 --- a/ui/package.json +++ b/ui/package.json @@ -105,7 +105,7 @@ "table": "^6.8.1", "typescript": "^4.9.5", "uglify-es": "^3.3.9", - "vue": "^3.3.4", + "vue": "^3.4.15", "vue-router": "^4.2.1", "yargs": "^17.7.2" }, diff --git a/utils/render-ssr-error/package.json b/utils/render-ssr-error/package.json index 9759add409b..e517b5889f2 100644 --- a/utils/render-ssr-error/package.json +++ b/utils/render-ssr-error/package.json @@ -51,7 +51,7 @@ "postcss": "^8.4.31", "prismjs": "^1.29.0", "quasar": "^2.6.0", - "vue": "^3.0.0", + "vue": "^3.4.15", "vue-router": "^4.2.4" } } diff --git a/yarn.lock b/yarn.lock index 7cba5f2dbaa..4992cbbefd3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -292,6 +292,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.5.tgz#37dee97c4752af148e1d38c34b856b2507660563" integrity sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ== +"@babel/parser@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" + integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.23.3": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz#5cd1c87ba9380d0afb78469292c954fee5d2411a" @@ -2054,6 +2059,17 @@ estree-walker "^2.0.2" source-map-js "^1.0.2" +"@vue/compiler-core@3.4.15": + version "3.4.15" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.15.tgz#be20d1bbe19626052500b48969302cb6f396d36e" + integrity sha512-XcJQVOaxTKCnth1vCxEChteGuwG6wqnUHxAm1DO3gCz0+uXKaJNx8/digSz4dLALCy8n2lKq24jSUs8segoqIw== + dependencies: + "@babel/parser" "^7.23.6" + "@vue/shared" "3.4.15" + entities "^4.5.0" + estree-walker "^2.0.2" + source-map-js "^1.0.2" + "@vue/compiler-dom@3.3.11": version "3.3.11" resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.3.11.tgz#36a76ea3a296d41bad133a6912cb0a847d969e4f" @@ -2062,6 +2078,14 @@ "@vue/compiler-core" "3.3.11" "@vue/shared" "3.3.11" +"@vue/compiler-dom@3.4.15": + version "3.4.15" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.15.tgz#753f5ed55f78d33dff04701fad4d76ff0cf81ee5" + integrity sha512-wox0aasVV74zoXyblarOM3AZQz/Z+OunYcIHe1OsGclCHt8RsRm04DObjefaI82u6XDzv+qGWZ24tIsRAIi5MQ== + dependencies: + "@vue/compiler-core" "3.4.15" + "@vue/shared" "3.4.15" + "@vue/compiler-sfc@3.3.11": version "3.3.11" resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.3.11.tgz#acfae240c875d067e0e2c9a4e2d910074408c73b" @@ -2078,6 +2102,21 @@ postcss "^8.4.32" source-map-js "^1.0.2" +"@vue/compiler-sfc@3.4.15": + version "3.4.15" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.15.tgz#4e5811e681955fcec886cebbec483f6ae463a64b" + integrity sha512-LCn5M6QpkpFsh3GQvs2mJUOAlBQcCco8D60Bcqmf3O3w5a+KWS5GvYbrrJBkgvL1BDnTp+e8q0lXCLgHhKguBA== + dependencies: + "@babel/parser" "^7.23.6" + "@vue/compiler-core" "3.4.15" + "@vue/compiler-dom" "3.4.15" + "@vue/compiler-ssr" "3.4.15" + "@vue/shared" "3.4.15" + estree-walker "^2.0.2" + magic-string "^0.30.5" + postcss "^8.4.33" + source-map-js "^1.0.2" + "@vue/compiler-ssr@3.3.11": version "3.3.11" resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.3.11.tgz#598942a73b64f2bd3f95908b104a7fbb55fc41a2" @@ -2086,6 +2125,14 @@ "@vue/compiler-dom" "3.3.11" "@vue/shared" "3.3.11" +"@vue/compiler-ssr@3.4.15": + version "3.4.15" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.15.tgz#a910a5b89ba4f0a776e40b63d69bdae2f50616cf" + integrity sha512-1jdeQyiGznr8gjFDadVmOJqZiLNSsMa5ZgqavkPZ8O2wjHv0tVuAEsw5hTdUoUW4232vpBbL/wJhzVW/JwY1Uw== + dependencies: + "@vue/compiler-dom" "3.4.15" + "@vue/shared" "3.4.15" + "@vue/devtools-api@^6.0.0-beta.11", "@vue/devtools-api@^6.5.0": version "6.5.1" resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.5.1.tgz#7f71f31e40973eeee65b9a64382b13593fdbd697" @@ -2109,6 +2156,13 @@ dependencies: "@vue/shared" "3.3.11" +"@vue/reactivity@3.4.15": + version "3.4.15" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.4.15.tgz#ad9d9b83f5398d2e8660ad5cfc0f171e7679a9a1" + integrity sha512-55yJh2bsff20K5O84MxSvXKPHHt17I2EomHznvFiJCAZpJTNW8IuLj1xZWMLELRhBK3kkFV/1ErZGHJfah7i7w== + dependencies: + "@vue/shared" "3.4.15" + "@vue/runtime-core@3.3.11": version "3.3.11" resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.3.11.tgz#63defba57bc54c1dac68a95b56c2633b1419193d" @@ -2117,6 +2171,14 @@ "@vue/reactivity" "3.3.11" "@vue/shared" "3.3.11" +"@vue/runtime-core@3.4.15": + version "3.4.15" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.15.tgz#f81e2fd2108ea41a6d5c61c2462b11dfb754fdf0" + integrity sha512-6E3by5m6v1AkW0McCeAyhHTw+3y17YCOKG0U0HDKDscV4Hs0kgNT5G+GCHak16jKgcCDHpI9xe5NKb8sdLCLdw== + dependencies: + "@vue/reactivity" "3.4.15" + "@vue/shared" "3.4.15" + "@vue/runtime-dom@3.3.11": version "3.3.11" resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.3.11.tgz#1146d8d280b0fec4d2e18c4a4c8f8121d0cecc09" @@ -2126,6 +2188,15 @@ "@vue/shared" "3.3.11" csstype "^3.1.2" +"@vue/runtime-dom@3.4.15": + version "3.4.15" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.15.tgz#108ef86aa7334ead5d6b9c56a7d93679e1e45406" + integrity sha512-EVW8D6vfFVq3V/yDKNPBFkZKGMFSvZrUQmx196o/v2tHKdwWdiZjYUBS+0Ez3+ohRyF8Njwy/6FH5gYJ75liUw== + dependencies: + "@vue/runtime-core" "3.4.15" + "@vue/shared" "3.4.15" + csstype "^3.1.3" + "@vue/server-renderer@3.3.11": version "3.3.11" resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.3.11.tgz#409aed8031a125791e2143552975ecd1958ad601" @@ -2134,11 +2205,24 @@ "@vue/compiler-ssr" "3.3.11" "@vue/shared" "3.3.11" +"@vue/server-renderer@3.4.15": + version "3.4.15" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.15.tgz#34438f998e6f6370fac78883a75efe136631957f" + integrity sha512-3HYzaidu9cHjrT+qGUuDhFYvF/j643bHC6uUN9BgM11DVy+pM6ATsG6uPBLnkwOgs7BpJABReLmpL3ZPAsUaqw== + dependencies: + "@vue/compiler-ssr" "3.4.15" + "@vue/shared" "3.4.15" + "@vue/shared@3.3.11": version "3.3.11" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.11.tgz#f6a038e15237edefcc90dbfe7edb806dd355c7bd" integrity sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw== +"@vue/shared@3.4.15": + version "3.4.15" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.15.tgz#e7d2ea050c667480cb5e1a6df2ac13bcd03a8f30" + integrity sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g== + "@xmldom/xmldom@^0.8.8": version "0.8.10" resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99" @@ -3772,7 +3856,7 @@ csso@^4.2.0: dependencies: css-tree "^1.1.2" -csstype@^3.1.2: +csstype@^3.1.2, csstype@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== @@ -4276,6 +4360,11 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== +entities@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + entities@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" @@ -7475,6 +7564,15 @@ postcss@^8.4.21, postcss@^8.4.27, postcss@^8.4.31, postcss@^8.4.32: picocolors "^1.0.0" source-map-js "^1.0.2" +postcss@^8.4.33: + version "8.4.33" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742" + integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.0.2" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -9292,7 +9390,7 @@ vue-router@^4.2.1, vue-router@^4.2.4: dependencies: "@vue/devtools-api" "^6.5.0" -vue@^3.0.0, vue@^3.2.45, vue@^3.3.4: +vue@^3.2.45, vue@^3.3.4: version "3.3.11" resolved "https://registry.yarnpkg.com/vue/-/vue-3.3.11.tgz#898d97025f73cdb5fc4e3ae3fd07a54615232140" integrity sha512-d4oBctG92CRO1cQfVBZp6WJAs0n8AK4Xf5fNjQCBeKCvMI1efGQ5E3Alt1slFJS9fZuPcFoiAiqFvQlv1X7t/w== @@ -9303,6 +9401,17 @@ vue@^3.0.0, vue@^3.2.45, vue@^3.3.4: "@vue/server-renderer" "3.3.11" "@vue/shared" "3.3.11" +vue@^3.4.15: + version "3.4.15" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.15.tgz#91f979844ffca9239dff622ba4c79c5d5524b88c" + integrity sha512-jC0GH4KkWLWJOEQjOpkqU1bQsBwf4R1rsFtw5GQJbjHVKWDzO6P0nWWBTmjp1xSemAioDFj1jdaK1qa3DnMQoQ== + dependencies: + "@vue/compiler-dom" "3.4.15" + "@vue/compiler-sfc" "3.4.15" + "@vue/runtime-dom" "3.4.15" + "@vue/server-renderer" "3.4.15" + "@vue/shared" "3.4.15" + vuex@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/vuex/-/vuex-4.1.0.tgz#aa1b3ea5c7385812b074c86faeeec2217872e36c" From 872760ac8a82de0e674a637ead4daaa170e1cb00 Mon Sep 17 00:00:00 2001 From: Razvan Stoenescu Date: Wed, 24 Jan 2024 16:30:07 +0200 Subject: [PATCH 2/6] fix(ui): Hydration issues with Vue 3.4 (QField/QInput/..., QBtnDropdown, QExpansionItem, QFab) #16792 --- .../components/btn-dropdown/QBtnDropdown.js | 8 ++--- .../expansion-item/QExpansionItem.js | 7 ++-- ui/src/components/fab/QFab.js | 8 ++--- ui/src/composables/private/use-field.js | 35 ++++++------------- ui/src/composables/private/use-id.js | 34 ++++++++++++++++++ 5 files changed, 56 insertions(+), 36 deletions(-) create mode 100644 ui/src/composables/private/use-id.js diff --git a/ui/src/components/btn-dropdown/QBtnDropdown.js b/ui/src/components/btn-dropdown/QBtnDropdown.js index b8ea5eac01f..2b20e2b7335 100644 --- a/ui/src/components/btn-dropdown/QBtnDropdown.js +++ b/ui/src/components/btn-dropdown/QBtnDropdown.js @@ -6,11 +6,11 @@ import QBtnGroup from '../btn-group/QBtnGroup.js' import QMenu from '../menu/QMenu.js' import { getBtnDesignAttr, useBtnProps } from '../btn/use-btn.js' +import useId from '../../composables/private/use-id.js' import { useTransitionProps } from '../../composables/private/use-transition.js' import { createComponent } from '../../utils/private/create.js' import { stop } from '../../utils/event.js' -import uid from '../../utils/uid.js' import { hSlot } from '../../utils/private/render.js' const btnPropsList = Object.keys(useBtnProps) @@ -70,13 +70,13 @@ export default createComponent({ const showing = ref(props.modelValue) const menuRef = ref(null) - const targetUid = uid() + const targetUid = useId() const ariaAttrs = computed(() => { const acc = { 'aria-expanded': showing.value === true ? 'true' : 'false', 'aria-haspopup': 'true', - 'aria-controls': targetUid, + 'aria-controls': targetUid.value, 'aria-label': props.toggleAriaLabel || proxy.$q.lang.label[ showing.value === true ? 'collapse' : 'expand' ](props.label) } @@ -170,7 +170,7 @@ export default createComponent({ props.disableDropdown !== true && Arrow.push( h(QMenu, { ref: menuRef, - id: targetUid, + id: targetUid.value, class: props.contentClass, style: props.contentStyle, cover: props.cover, diff --git a/ui/src/components/expansion-item/QExpansionItem.js b/ui/src/components/expansion-item/QExpansionItem.js index d715224d70b..537d7fcca0c 100644 --- a/ui/src/components/expansion-item/QExpansionItem.js +++ b/ui/src/components/expansion-item/QExpansionItem.js @@ -8,6 +8,7 @@ import QSlideTransition from '../slide-transition/QSlideTransition.js' import QSeparator from '../separator/QSeparator.js' import useDark, { useDarkProps } from '../../composables/private/use-dark.js' +import useId from '../../composables/private/use-id.js' import { useRouterLinkProps } from '../../composables/private/use-router-link.js' import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../composables/private/use-model-toggle.js' @@ -75,7 +76,7 @@ export default createComponent({ ) const blurTargetRef = ref(null) - const targetUid = uid() + const targetUid = useId() const { show, hide, toggle } = useModelToggle({ showing }) @@ -143,7 +144,7 @@ export default createComponent({ return { role: 'button', 'aria-expanded': showing.value === true ? 'true' : 'false', - 'aria-controls': targetUid, + 'aria-controls': targetUid.value, 'aria-label': toggleAriaLabel } }) @@ -320,7 +321,7 @@ export default createComponent({ key: 'e-content', class: 'q-expansion-item__content relative-position', style: contentStyle.value, - id: targetUid + id: targetUid.value }, hSlot(slots.default)), [ [ vShow, diff --git a/ui/src/components/fab/QFab.js b/ui/src/components/fab/QFab.js index 2bfdd1a71ac..9fb80cacb7a 100644 --- a/ui/src/components/fab/QFab.js +++ b/ui/src/components/fab/QFab.js @@ -4,12 +4,12 @@ import QBtn from '../btn/QBtn.js' import QIcon from '../icon/QIcon.js' import useFab, { useFabProps } from './use-fab.js' +import useId from '../../composables/private/use-id.js' import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../composables/private/use-model-toggle.js' import { createComponent } from '../../utils/private/create.js' import { hSlot, hMergeSlot } from '../../utils/private/render.js' import { fabKey } from '../../utils/private/symbols.js' -import uid from '../../utils/uid.js' const directions = [ 'up', 'right', 'down', 'left' ] const alignValues = [ 'left', 'center', 'right' ] @@ -49,7 +49,7 @@ export default createComponent({ setup (props, { slots }) { const triggerRef = ref(null) const showing = ref(props.modelValue === true) - const targetUid = uid() + const targetUid = useId() const { proxy: { $q } } = getCurrentInstance() const { formClass, labelProps } = useFab(props, showing) @@ -77,7 +77,7 @@ export default createComponent({ const actionAttrs = computed(() => { const attrs = { - id: targetUid, + id: targetUid.value, role: 'menu' } @@ -149,7 +149,7 @@ export default createComponent({ fab: true, 'aria-expanded': showing.value === true ? 'true' : 'false', 'aria-haspopup': 'true', - 'aria-controls': targetUid, + 'aria-controls': targetUid.value, onClick: toggle }, getTriggerContent), diff --git a/ui/src/composables/private/use-field.js b/ui/src/composables/private/use-field.js index ecd95a5ee90..c4dec8bba4a 100644 --- a/ui/src/composables/private/use-field.js +++ b/ui/src/composables/private/use-field.js @@ -1,25 +1,17 @@ import { h, ref, computed, watch, Transition, nextTick, onActivated, onDeactivated, onBeforeUnmount, onMounted, getCurrentInstance } from 'vue' -import { isRuntimeSsrPreHydration } from '../../plugins/Platform.js' - import QIcon from '../../components/icon/QIcon.js' import QSpinner from '../../components/spinner/QSpinner.js' import useDark, { useDarkProps } from '../../composables/private/use-dark.js' +import useId, { getId } from './use-id.js' import useValidate, { useValidateProps } from './use-validate.js' import useSplitAttrs from './use-split-attrs.js' import { hSlot } from '../../utils/private/render.js' -import uid from '../../utils/uid.js' import { prevent, stopAndPrevent } from '../../utils/event.js' import { addFocusFn, removeFocusFn } from '../../utils/private/focus-manager.js' -function getTargetUid (val, requiredForAttr) { - return val === void 0 - ? (requiredForAttr === true ? `f_${ uid() }` : void 0) - : val -} - export function fieldValueIsFilled (val) { return val !== void 0 && val !== null @@ -80,6 +72,7 @@ export function useFieldState ({ requiredForAttr = true, tagProp } = {}) { const { props, attrs, proxy, vnode } = getCurrentInstance() const isDark = useDark(props, proxy.$q) + const targetUid = useId(props.for, requiredForAttr) return { requiredForAttr, @@ -98,9 +91,7 @@ export function useFieldState ({ requiredForAttr = true, tagProp } = {}) { hasPopupOpen: false, splitAttrs: useSplitAttrs(attrs, vnode), - targetUid: ref( - getTargetUid(props.for, requiredForAttr) - ), + targetUid, rootRef: ref(null), targetRef: ref(null), @@ -252,8 +243,10 @@ export default function (state) { })) const attributes = computed(() => { - const acc = { - for: state.targetUid.value + const acc = {} + + if (state.targetUid.value) { + acc.for = state.targetUid.value } if (props.disable === true) { @@ -266,7 +259,7 @@ export default function (state) { watch(() => props.for, val => { // don't transform targetUid into a computed // prop as it will break SSR - state.targetUid.value = getTargetUid(val, state.requiredForAttr) + state.targetUid.value = getId(val, state.requiredForAttr) }) function focusHandler () { @@ -548,16 +541,8 @@ export default function (state) { shouldActivate === true && props.autofocus === true && proxy.focus() }) - onMounted(() => { - if ( - isRuntimeSsrPreHydration.value === true - && state.requiredForAttr === true - && props.for === void 0 - ) { - state.targetUid.value = `f_${ uid() }` // getTargetUid(void 0, true) - } - - props.autofocus === true && proxy.focus() + props.autofocus === true && onMounted(() => { + proxy.focus() }) onBeforeUnmount(() => { diff --git a/ui/src/composables/private/use-id.js b/ui/src/composables/private/use-id.js new file mode 100644 index 00000000000..f2b0fb3e1b7 --- /dev/null +++ b/ui/src/composables/private/use-id.js @@ -0,0 +1,34 @@ +import { ref, onMounted } from 'vue' + +import uid from '../../utils/uid.js' + +import { isRuntimeSsrPreHydration } from '../../plugins/Platform.js' + +export function getId (val, requiredId) { + return val === void 0 + ? (requiredId === true ? `f_${ uid() }` : void 0) + : val +} + +/** + * Returns an "id" which is a ref() that can be used as a unique identifier. + * On SSR, it takes care of generating the id on the client side (only) to + * avoid hydration errors. + */ +export default function (initialId, requiredId = true) { + if (isRuntimeSsrPreHydration.value === true) { + const id = ref(initialId) + + if (requiredId === true && initialId === void 0) { + onMounted(() => { + id.value = `f_${ uid() }` // getId(void 0, true) + }) + } + + return id + } + + return ref( + getId(initialId, requiredId) + ) +} From e93ebdac16c6e25cfbbbc744389feb5c43019bd9 Mon Sep 17 00:00:00 2001 From: Razvan Stoenescu Date: Thu, 25 Jan 2024 13:42:49 +0200 Subject: [PATCH 3/6] fix(docs): platform detection page -> token gets transformed by quasar/vite-plugin --- docs/src/pages/options/platform-detection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/pages/options/platform-detection.md b/docs/src/pages/options/platform-detection.md index 6f5023f7ca7..3efd86c0790 100644 --- a/docs/src/pages/options/platform-detection.md +++ b/docs/src/pages/options/platform-detection.md @@ -111,7 +111,7 @@ Running on mobile means you can have this code running on a mobile device (phone ::: ## Note about SSR -When building for SSR, use only the `$q.platform` form. If you need to use the `import { Platform } from 'quasar'` (when on server-side), then you'll need to do it like this: +When building for SSR, use only the `$q.platform` form. Alternatively, when on server-side, this is an example of how you can use it: ```js import { Platform } from 'quasar' From 4ed72b82cf2662f736a614d50510e4195f70ab59 Mon Sep 17 00:00:00 2001 From: Razvan Stoenescu Date: Thu, 25 Jan 2024 13:50:13 +0200 Subject: [PATCH 4/6] fix(docs): multiple pages -> token gets transformed by quasar/vite-plugin --- docs/src/pages/options/platform-detection.md | 2 +- .../developing-ssr/ssr-frequently-asked-questions.md | 2 +- .../developing-ssr/ssr-frequently-asked-questions.md | 2 +- docs/src/pages/quasar-plugins/cookies.md | 2 +- docs/src/pages/quasar-plugins/dark.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/pages/options/platform-detection.md b/docs/src/pages/options/platform-detection.md index 3efd86c0790..db4a5c4b3ab 100644 --- a/docs/src/pages/options/platform-detection.md +++ b/docs/src/pages/options/platform-detection.md @@ -111,7 +111,7 @@ Running on mobile means you can have this code running on a mobile device (phone ::: ## Note about SSR -When building for SSR, use only the `$q.platform` form. Alternatively, when on server-side, this is an example of how you can use it: +When building for SSR, use only the `$q.platform` form. Alternatively, when on server-side, this is one more example of how you can use it: ```js import { Platform } from 'quasar' diff --git a/docs/src/pages/quasar-cli-vite/developing-ssr/ssr-frequently-asked-questions.md b/docs/src/pages/quasar-cli-vite/developing-ssr/ssr-frequently-asked-questions.md index 0673415efd3..a3781c4ff43 100644 --- a/docs/src/pages/quasar-cli-vite/developing-ssr/ssr-frequently-asked-questions.md +++ b/docs/src/pages/quasar-cli-vite/developing-ssr/ssr-frequently-asked-questions.md @@ -7,7 +7,7 @@ desc: (@quasar/app-vite) Tips and tricks for a Quasar server-side rendered app. Take a look at our [Client Side Hydration](/quasar-cli-vite/developing-ssr/client-side-hydration) page. When you get hydration errors, it means the HTML rendered on the server does not match the equivalent HTML rendered on client-side. This error will appear only when developing (and NOT on production) and it definitely needs to be addressed, before you release your website. Is there some content that you can only generate on client-side? Then use [QNoSsr](/vue-components/no-ssr). ## Why doesn't importing Platform and Cookies work? -When building for SSR, use only the `$q.platform` / `$q.cookies` form. If you need to use the `import { Platform, Cookies } from 'quasar'` (when on server-side), then you’ll need to do it like this: +When building for SSR, use only the `$q.platform` / `$q.cookies` form. Alternatively, when on server-side, this is one more example of how you can use it: ```js // example with Platform; same thing for Cookies diff --git a/docs/src/pages/quasar-cli-webpack/developing-ssr/ssr-frequently-asked-questions.md b/docs/src/pages/quasar-cli-webpack/developing-ssr/ssr-frequently-asked-questions.md index 3fdaf875fb6..641170d7f53 100644 --- a/docs/src/pages/quasar-cli-webpack/developing-ssr/ssr-frequently-asked-questions.md +++ b/docs/src/pages/quasar-cli-webpack/developing-ssr/ssr-frequently-asked-questions.md @@ -7,7 +7,7 @@ desc: (@quasar/app-webpack) Tips and tricks for a Quasar server-side rendered ap Take a look at our [Client Side Hydration](/quasar-cli-webpack/developing-ssr/client-side-hydration) page. When you get hydration errors, it means the HTML rendered on the server does not match the equivalent HTML rendered on client-side. This error will appear only when developing (and NOT on production) and it definitely needs to be addressed, before you release your website. Is there some content that you can only generate on client-side? Then use [QNoSsr](/vue-components/no-ssr). ## Why doesn't importing Platform and Cookies work? -When building for SSR, use only the `$q.platform` / `$q.cookies` form. If you need to use the `import { Platform, Cookies } from 'quasar'` (when on server-side), then you’ll need to do it like this: +When building for SSR, use only the `$q.platform` / `$q.cookies` form. Alternatively, when on server-side, this is one more example of how you can use it: ```js // example with Platform; same thing for Cookies diff --git a/docs/src/pages/quasar-plugins/cookies.md b/docs/src/pages/quasar-plugins/cookies.md index b7ba15ce7d4..a9cf6a35974 100644 --- a/docs/src/pages/quasar-plugins/cookies.md +++ b/docs/src/pages/quasar-plugins/cookies.md @@ -18,7 +18,7 @@ With Electron version >= v1.12.2 the Cookie Plugin isn't functional in the Elect ## Notes on SSR -When building for SSR, use only the `$q.cookies` form. If you need to use the `import { Cookies } from 'quasar'`, then you'll need to do it like this: +When building for SSR, use only the `$q.cookies` form. Alternatively, when on server-side, this is one more example of how you can use it: ```js import { Cookies } from 'quasar' diff --git a/docs/src/pages/quasar-plugins/dark.md b/docs/src/pages/quasar-plugins/dark.md index a03d976012d..a31c00c2f60 100644 --- a/docs/src/pages/quasar-plugins/dark.md +++ b/docs/src/pages/quasar-plugins/dark.md @@ -82,7 +82,7 @@ Dark.toggle() When on a SSR build: -* `import { Dark } from 'quasar'` method of using Dark mode will not error out but it will not work (won't do anything). But, you can use the [Inside of a Vue file](/quasar-plugins/dark#inside-of-a-vue-file) approach or the [Configuration](/quasar-plugins/dark#configuration) (recommended) approach. +* Import `Dark` from 'quasar' method of using Dark mode will not error out but it will not work (won't do anything). But, you can use the [Inside of a Vue file](/quasar-plugins/dark#inside-of-a-vue-file) approach or the [Configuration](/quasar-plugins/dark#configuration) (recommended) approach. * It's preferred to avoid setting Dark mode to 'auto' for SSR builds. It's because the client dark mode preference cannot be inferred, so SSR will always render in light mode then when the client takes over, it will switch to Dark (if it will be the case). As a result, a quick flicker of the screen will occur. ## Watching for status change From c6368ba73b84d35641e8c761cd45112bd2f3165f Mon Sep 17 00:00:00 2001 From: Razvan Stoenescu Date: Thu, 25 Jan 2024 14:07:52 +0200 Subject: [PATCH 5/6] fix(Dark): [Vue 3.4] Hydration issue with Dark Quasar plugin on SSR #16818 --- ui/src/plugins/Dark.js | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/ui/src/plugins/Dark.js b/ui/src/plugins/Dark.js index 80f4da7888f..29429c15e51 100644 --- a/ui/src/plugins/Dark.js +++ b/ui/src/plugins/Dark.js @@ -1,5 +1,4 @@ import defineReactivePlugin from '../utils/private/define-reactive-plugin.js' -import { isRuntimeSsrPreHydration } from './Platform.js' const Plugin = defineReactivePlugin({ isActive: false, @@ -38,7 +37,7 @@ const Plugin = defineReactivePlugin({ } }, - install ({ $q, onSSRHydrated, ssrContext }) { + install ({ $q, ssrContext }) { const { dark } = $q.config if (__QUASAR_SSR_SERVER__) { @@ -66,31 +65,8 @@ const Plugin = defineReactivePlugin({ $q.dark = this - if (this.__installed === true && dark === void 0) { - return - } - - this.isActive = dark === true - - const initialVal = dark !== void 0 ? dark : false - - if (isRuntimeSsrPreHydration.value === true) { - const ssrSet = val => { - this.__fromSSR = val - } - - const originalSet = this.set - - this.set = ssrSet - ssrSet(initialVal) - - onSSRHydrated.push(() => { - this.set = originalSet - this.set(this.__fromSSR) - }) - } - else { - this.set(initialVal) + if (this.__installed !== true) { + this.set(dark !== void 0 ? dark : false) } } }) From bb91d264f2907bf54d77c21934a33510162d8a69 Mon Sep 17 00:00:00 2001 From: Razvan Stoenescu Date: Thu, 25 Jan 2024 14:20:08 +0200 Subject: [PATCH 6/6] chore(ui): Bump version --- ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/package.json b/ui/package.json index 21413d478f7..2648a3d4050 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "quasar", - "version": "2.14.2", + "version": "2.14.3", "description": "Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time", "main": "dist/quasar.cjs.prod.js", "module": "dist/quasar.esm.prod.js",