mirror of
https://github.com/modrinth/code.git
synced 2026-08-25 00:55:25 +00:00
perf: further reduce memory (#7015)
* feat: server source maps * perf: strip unused fields from search results * perf: reduce game version memory usage
This commit is contained in:
@@ -68,11 +68,16 @@ export interface GeneratedState extends GloballyUsedState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Composable for accessing the globally used generated state.
|
||||
* This includes both fetched data and runtime-defined constants.
|
||||
* Built once per module load rather than via `useState`, because every `useState` value is
|
||||
* serialized into the SSR payload of every page. This is build-time constant data that the
|
||||
* client already has via the static import above, so putting it in the payload would ship a
|
||||
* second copy for no benefit.
|
||||
*
|
||||
* Consequence: on the server this object is shared by every request in the isolate, so it must
|
||||
* stay immutable there. Runtime refreshes are client-only and go through `setGameVersions`.
|
||||
*/
|
||||
export const useGeneratedState = () =>
|
||||
useState<GeneratedState>('generatedState', () => ({
|
||||
const generatedState = shallowRef<GeneratedState>(
|
||||
Object.freeze({
|
||||
// Cast JSON data to typed API responses
|
||||
categories: (categories ?? []) as Labrinth.Tags.v2.Category[],
|
||||
loaders: (loaders ?? []) as Labrinth.Tags.v2.Loader[],
|
||||
@@ -147,4 +152,24 @@ export const useGeneratedState = () =>
|
||||
errors,
|
||||
|
||||
buildYear: new Date().getFullYear(),
|
||||
}))
|
||||
}) as GeneratedState,
|
||||
)
|
||||
|
||||
/**
|
||||
* Composable for accessing the globally used generated state.
|
||||
* This includes both fetched data and runtime-defined constants.
|
||||
*/
|
||||
export const useGeneratedState = () => generatedState
|
||||
|
||||
/**
|
||||
* Replaces the build-time game versions with a freshly fetched list. Client-only: mutating this
|
||||
* on the server would leak across every request sharing the isolate.
|
||||
*/
|
||||
export function setGameVersions(versions: Labrinth.Tags.v2.GameVersion[]) {
|
||||
if (import.meta.server) return
|
||||
|
||||
generatedState.value = Object.freeze({
|
||||
...generatedState.value,
|
||||
gameVersions: versions,
|
||||
}) as GeneratedState
|
||||
}
|
||||
|
||||
@@ -228,6 +228,19 @@ function parseSearchParams(requestParams: string): Labrinth.Search.SearchParams
|
||||
}
|
||||
}
|
||||
|
||||
// Search returns expanded dependency data that no card renders and that isn't part of
|
||||
// ResultSearchProject. On modpacks it is ~90% of the response, and everything cached here
|
||||
// is serialized into the SSR payload, so drop it before it reaches the query cache.
|
||||
function stripUnrenderedFields(
|
||||
hits: Labrinth.Search.v3.ResultSearchProject[],
|
||||
): Labrinth.Search.v3.ResultSearchProject[] {
|
||||
return hits.map((hit) => {
|
||||
const { dependencies, dependency_project_ids, compatible_dependency_project_ids, ...rendered } =
|
||||
hit as Labrinth.Search.v3.ResultSearchProject & Record<string, unknown>
|
||||
return rendered as Labrinth.Search.v3.ResultSearchProject
|
||||
})
|
||||
}
|
||||
|
||||
async function fetchSearch(requestParams: string) {
|
||||
debug('search() called', {
|
||||
requestParams: requestParams.substring(0, 100),
|
||||
@@ -241,17 +254,19 @@ async function fetchSearch(requestParams: string) {
|
||||
|
||||
debug('search() response', { total_hits: raw.total_hits, hitCount: raw.hits?.length })
|
||||
|
||||
const hits = stripUnrenderedFields(raw.hits ?? [])
|
||||
|
||||
if (isServerType.value) {
|
||||
return {
|
||||
projectHits: [],
|
||||
serverHits: raw.hits,
|
||||
serverHits: hits,
|
||||
total_hits: raw.total_hits,
|
||||
per_page: raw.hits_per_page,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
projectHits: raw.hits,
|
||||
projectHits: hits,
|
||||
serverHits: [],
|
||||
total_hits: raw.total_hits,
|
||||
per_page: raw.hits_per_page,
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
|
||||
import { setGameVersions } from '~/composables/generated'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
// Deferred until after hydration: the server renders with the build-time game versions, so
|
||||
// swapping them in during setup would make the first client render disagree with the markup.
|
||||
nuxtApp.hook('app:suspense:resolve', async () => {
|
||||
try {
|
||||
const gameVersions = await $fetch<Labrinth.Tags.v2.GameVersion[]>('/api/tags/game-versions')
|
||||
|
||||
if (gameVersions && gameVersions.length > 0) {
|
||||
setGameVersions(gameVersions)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Game Version Updater] Failed to fetch:', error)
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
|
||||
export default defineNuxtPlugin(async () => {
|
||||
try {
|
||||
const gameVersions = await $fetch<Labrinth.Tags.v2.GameVersion[]>('/api/tags/game-versions')
|
||||
|
||||
if (gameVersions && gameVersions.length > 0) {
|
||||
const state = useState<{ gameVersions: Labrinth.Tags.v2.GameVersion[] }>('generatedState')
|
||||
|
||||
if (state.value) {
|
||||
state.value.gameVersions = gameVersions
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Game Version Updater] Failed to fetch:', error)
|
||||
}
|
||||
})
|
||||
@@ -10,6 +10,7 @@
|
||||
"routes": ["modrinth.com/*"],
|
||||
"preview_urls": true,
|
||||
"workers_dev": true,
|
||||
"upload_source_maps": true,
|
||||
"limits": {
|
||||
"cpu_ms": 5000
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user