From bcf469ef91f2d496ae01934b797b022cc179a9ad Mon Sep 17 00:00:00 2001 From: "Michael H." Date: Sat, 29 Aug 2026 12:26:46 +0200 Subject: [PATCH] fix: generatedstate memory leak & bump ts query --- apps/app-frontend/package.json | 2 +- apps/frontend/package.json | 2 +- apps/frontend/src/composables/generated.ts | 15 +++++++- packages/ui/package.json | 2 +- pnpm-lock.yaml | 40 +++++++++++----------- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/apps/app-frontend/package.json b/apps/app-frontend/package.json index 7eea9d5397..643a41d661 100644 --- a/apps/app-frontend/package.json +++ b/apps/app-frontend/package.json @@ -21,7 +21,7 @@ "@modrinth/utils": "workspace:*", "@sentry/vue": "^8.27.0", "@sfirew/minecraft-motd-parser": "^1.1.6", - "@tanstack/vue-query": "5.90.7", + "@tanstack/vue-query": "5.101.4", "@tauri-apps/api": "^2.5.0", "@tauri-apps/plugin-dialog": "^2.2.1", "@tauri-apps/plugin-fs": "^2.4.5", diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 034d70fa26..3cc19894b1 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -48,7 +48,7 @@ "@modrinth/ui": "workspace:*", "@modrinth/utils": "workspace:*", "@sentry/nuxt": "^10.33.0", - "@tanstack/vue-query": "5.90.7", + "@tanstack/vue-query": "5.101.4", "@types/three": "^0.172.0", "@vitejs/plugin-vue": "^6.0.3", "@vue-email/components": "^0.0.21", diff --git a/apps/frontend/src/composables/generated.ts b/apps/frontend/src/composables/generated.ts index 8a7b895e0f..d10f355877 100644 --- a/apps/frontend/src/composables/generated.ts +++ b/apps/frontend/src/composables/generated.ts @@ -1,5 +1,6 @@ import type { ISO3166, Labrinth } from '@modrinth/api-client' import type { DisplayProjectType } from '@modrinth/utils' +import type { ShallowRef } from 'vue' import { apiUrl, @@ -155,11 +156,23 @@ const generatedState = shallowRef( }) as GeneratedState, ) +/** + * Non-reactive server-side view of the state above. + * + * `generatedState` lives for the lifetime of the isolate, so every per-request `computed()` that + * reads it registers a subscriber link on its dep. SSR never unmounts, so those links are never + * released, and each one pins the whole request graph that created it. The data is frozen and + * `setGameVersions` is client-only, so the server has nothing to react to. + */ +const serverGeneratedState = { + value: generatedState.value, +} as unknown as ShallowRef + /** * Composable for accessing the globally used generated state. * This includes both fetched data and runtime-defined constants. */ -export const useGeneratedState = () => generatedState +export const useGeneratedState = () => (import.meta.server ? serverGeneratedState : generatedState) /** * Replaces the build-time game versions with a freshly fetched list. Client-only: mutating this diff --git a/packages/ui/package.json b/packages/ui/package.json index 2ab8cc1f71..b1d53bcb8d 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -60,7 +60,7 @@ "@modrinth/assets": "workspace:*", "@modrinth/blog": "workspace:*", "@modrinth/utils": "workspace:*", - "@tanstack/vue-query": "5.90.7", + "@tanstack/vue-query": "5.101.4", "@tresjs/cientos": "^4.3.0", "@tresjs/core": "^4.3.4", "@tresjs/post-processing": "^2.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c58967540c..1ccac3174b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,8 +102,8 @@ importers: specifier: ^1.1.6 version: 1.1.6 '@tanstack/vue-query': - specifier: 5.90.7 - version: 5.90.7(vue@3.5.27(typescript@5.9.3)) + specifier: 5.101.4 + version: 5.101.4(vue@3.5.27(typescript@5.9.3)) '@tauri-apps/api': specifier: ^2.5.0 version: 2.10.1 @@ -300,8 +300,8 @@ importers: specifier: ^10.33.0 version: 10.38.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.211.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.39.0)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(rollup@4.57.1)(vue@3.5.27(typescript@5.9.3)) '@tanstack/vue-query': - specifier: 5.90.7 - version: 5.90.7(vue@3.5.27(typescript@5.9.3)) + specifier: 5.101.4 + version: 5.101.4(vue@3.5.27(typescript@5.9.3)) '@types/three': specifier: ^0.172.0 version: 0.172.0 @@ -671,8 +671,8 @@ importers: specifier: workspace:* version: link:../utils '@tanstack/vue-query': - specifier: 5.90.7 - version: 5.90.7(vue@3.5.27(typescript@5.9.3)) + specifier: 5.101.4 + version: 5.101.4(vue@3.5.27(typescript@5.9.3)) '@tresjs/cientos': specifier: ^4.3.0 version: 4.3.1(@tresjs/core@4.3.6(three@0.172.0)(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)))(@types/three@0.172.0)(react@19.2.8)(three@0.172.0)(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)) @@ -721,12 +721,12 @@ importers: es-toolkit: specifier: ^1.44.0 version: 1.44.0 - flatpickr: - specifier: ^4.6.13 - version: 4.6.13 fabric: specifier: ^7.4.0 version: 7.4.0 + flatpickr: + specifier: ^4.6.13 + version: 4.6.13 floating-vue: specifier: ^5.2.2 version: 5.2.2(@nuxt/kit@3.21.0(magicast@0.5.1))(vue@3.5.27(typescript@5.9.3)) @@ -4453,11 +4453,11 @@ packages: resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==} engines: {node: '>=12'} - '@tanstack/query-core@5.90.7': - resolution: {integrity: sha512-6PN65csiuTNfBMXqQUxQhCNdtm1rV+9kC9YwWAIKcaxAauq3Wu7p18j3gQY3YIBJU70jT/wzCCZ2uqto/vQgiQ==} + '@tanstack/query-core@5.101.4': + resolution: {integrity: sha512-gNwcvOJcRbLWPOLG/2OBm+zM+Yv+MKsXKEOWC57USuZDEsI71hEErQsiEGx5wX9rzWWkfwM0fVSPoiIFSsxfiw==} - '@tanstack/vue-query@5.90.7': - resolution: {integrity: sha512-2h0esebc2qVRVDge3gFArhss5+qn/Wb4abXuaEliSy+/xPWQMrEX7Ny0UKkCy1HcMZZjvfTtNRUfpYrx+vpipw==} + '@tanstack/vue-query@5.101.4': + resolution: {integrity: sha512-UYjkUZhnWQIFGNb7SdgjCitAftNyYQfOIVUh6vBUQAG4SQKNMSBKeQERFDubpxLAMpIBJTaOrE8fM4c1kZcIGQ==} peerDependencies: '@vue/composition-api': ^1.1.2 vue: ^2.6.0 || ^3.3.0 @@ -10381,8 +10381,8 @@ packages: vue-component-type-helpers@3.2.4: resolution: {integrity: sha512-05lR16HeZDcDpB23ku5b5f1fBOoHqFnMiKRr2CiEvbG5Ux4Yi0McmQBOET0dR0nxDXosxyVqv67q6CzS3AK8rw==} - vue-component-type-helpers@3.3.10: - resolution: {integrity: sha512-t7IQivQ3oD4D01b7s7a9AWzHAcr3DGBIa/1jZREsFQJcFgSL92gqUkqNiHTYgzTt7QDuJa0I9wCeDwEtZICoBQ==} + vue-component-type-helpers@3.3.11: + resolution: {integrity: sha512-LwcxzeliO9fkQcpJG0PoX8X5kmAhKmH9wkpDLxNabwzkQ9Zeib2YVHwFV4pcWmMLfXVfjr/dSV+DaJ3cIPgSNA==} vue-confetti-explosion@1.0.2: resolution: {integrity: sha512-80OboM3/6BItIoZ6DpNcZFqGpF607kjIVc5af56oKgtFmt5yWehvJeoYhkzYlqxrqdBe0Ko4Ie3bWrmLau+dJw==} @@ -14128,7 +14128,7 @@ snapshots: storybook: 10.2.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) type-fest: 2.19.0 vue: 3.5.27(typescript@5.9.3) - vue-component-type-helpers: 3.3.10 + vue-component-type-helpers: 3.3.11 '@stripe/stripe-js@7.9.0': {} @@ -14255,12 +14255,12 @@ snapshots: dependencies: remove-accents: 0.5.0 - '@tanstack/query-core@5.90.7': {} + '@tanstack/query-core@5.101.4': {} - '@tanstack/vue-query@5.90.7(vue@3.5.27(typescript@5.9.3))': + '@tanstack/vue-query@5.101.4(vue@3.5.27(typescript@5.9.3))': dependencies: '@tanstack/match-sorter-utils': 8.19.4 - '@tanstack/query-core': 5.90.7 + '@tanstack/query-core': 5.101.4 '@vue/devtools-api': 6.6.4 vue: 3.5.27(typescript@5.9.3) vue-demi: 0.14.10(vue@3.5.27(typescript@5.9.3)) @@ -21551,7 +21551,7 @@ snapshots: vue-component-type-helpers@3.2.4: {} - vue-component-type-helpers@3.3.10: {} + vue-component-type-helpers@3.3.11: {} vue-confetti-explosion@1.0.2(vue@3.5.27(typescript@5.9.3)): dependencies: