enable HTTP caching for pet appearances
This commit is contained in:
parent
9f11c83b20
commit
ffde7172de
2 changed files with 69 additions and 33 deletions
|
@ -9,31 +9,31 @@ import { useQuery } from "@apollo/react-hooks";
|
|||
export default function useOutfitAppearance(outfitState) {
|
||||
const { wornItemIds, speciesId, colorId, pose } = outfitState;
|
||||
|
||||
const { loading, error, data } = useQuery(
|
||||
// We split this query out from the other one, so that we can HTTP cache it.
|
||||
//
|
||||
// While Apollo gives us fine-grained caching during the page session, we can
|
||||
// only HTTP a full query at a time.
|
||||
//
|
||||
// This is a minor optimization with respect to keeping the user's cache
|
||||
// populated with their favorite species/color combinations. Once we start
|
||||
// caching the items by body instead of species/color, this could make color
|
||||
// changes really snappy!
|
||||
//
|
||||
// The larger optimization is that this enables the CDN to edge-cache the
|
||||
// most popular species/color combinations, for very fast previews on the
|
||||
// HomePage. At time of writing, Vercel isn't actually edge-caching these, I
|
||||
// assume because our traffic isn't enough - so let's keep an eye on this!
|
||||
const { loading: loading1, error: error1, data: data1 } = useQuery(
|
||||
gql`
|
||||
query OutfitAppearance(
|
||||
$wornItemIds: [ID!]!
|
||||
$speciesId: ID!
|
||||
$colorId: ID!
|
||||
$pose: Pose!
|
||||
) {
|
||||
query OutfitPetAppearance($speciesId: ID!, $colorId: ID!, $pose: Pose!) {
|
||||
petAppearance(speciesId: $speciesId, colorId: $colorId, pose: $pose) {
|
||||
...PetAppearanceForOutfitPreview
|
||||
}
|
||||
|
||||
items(ids: $wornItemIds) {
|
||||
id
|
||||
appearanceOn(speciesId: $speciesId, colorId: $colorId) {
|
||||
...ItemAppearanceForOutfitPreview
|
||||
}
|
||||
}
|
||||
}
|
||||
${itemAppearanceFragment}
|
||||
${petAppearanceFragment}
|
||||
`,
|
||||
{
|
||||
variables: {
|
||||
wornItemIds,
|
||||
speciesId,
|
||||
colorId,
|
||||
pose,
|
||||
|
@ -42,16 +42,46 @@ export default function useOutfitAppearance(outfitState) {
|
|||
}
|
||||
);
|
||||
|
||||
const itemAppearances = React.useMemo(
|
||||
() => (data?.items || []).map((i) => i.appearanceOn),
|
||||
[data]
|
||||
);
|
||||
const visibleLayers = React.useMemo(
|
||||
() => getVisibleLayers(data?.petAppearance, itemAppearances),
|
||||
[data, itemAppearances]
|
||||
const { loading: loading2, error: error2, data: data2 } = useQuery(
|
||||
gql`
|
||||
query OutfitItemsAppearance(
|
||||
$speciesId: ID!
|
||||
$colorId: ID!
|
||||
$wornItemIds: [ID!]!
|
||||
) {
|
||||
items(ids: $wornItemIds) {
|
||||
id
|
||||
appearanceOn(speciesId: $speciesId, colorId: $colorId) {
|
||||
...ItemAppearanceForOutfitPreview
|
||||
}
|
||||
}
|
||||
}
|
||||
${itemAppearanceFragment}
|
||||
`,
|
||||
{
|
||||
variables: {
|
||||
speciesId,
|
||||
colorId,
|
||||
wornItemIds,
|
||||
},
|
||||
skip: speciesId == null || colorId == null || wornItemIds.length === 0,
|
||||
}
|
||||
);
|
||||
|
||||
return { loading, error, visibleLayers };
|
||||
const itemAppearances = React.useMemo(
|
||||
() => (data2?.items || []).map((i) => i.appearanceOn),
|
||||
[data2]
|
||||
);
|
||||
const visibleLayers = React.useMemo(
|
||||
() => getVisibleLayers(data1?.petAppearance, itemAppearances),
|
||||
[data1, itemAppearances]
|
||||
);
|
||||
|
||||
return {
|
||||
loading: loading1 || loading2,
|
||||
error: error1 || error2,
|
||||
visibleLayers,
|
||||
};
|
||||
}
|
||||
|
||||
export function getVisibleLayers(petAppearance, itemAppearances) {
|
||||
|
|
|
@ -68,7 +68,8 @@ const typeDefs = gql`
|
|||
appearanceOn(speciesId: ID!, colorId: ID!): ItemAppearance
|
||||
}
|
||||
|
||||
type PetAppearance {
|
||||
# Cache for 1 week (unlikely to change)
|
||||
type PetAppearance @cacheControl(maxAge: 604800) {
|
||||
id: ID!
|
||||
species: Species!
|
||||
color: Color!
|
||||
|
@ -84,7 +85,8 @@ const typeDefs = gql`
|
|||
restrictedZones: [Zone!]!
|
||||
}
|
||||
|
||||
type AppearanceLayer {
|
||||
# Cache for 1 week (unlikely to change)
|
||||
type AppearanceLayer @cacheControl(maxAge: 604800) {
|
||||
id: ID!
|
||||
zone: Zone!
|
||||
imageUrl(size: LayerImageSize): String
|
||||
|
@ -98,7 +100,8 @@ const typeDefs = gql`
|
|||
svgUrl: String
|
||||
}
|
||||
|
||||
type Zone {
|
||||
# Cache for 1 week (unlikely to change)
|
||||
type Zone @cacheControl(maxAge: 604800) {
|
||||
id: ID!
|
||||
depth: Int!
|
||||
label: String!
|
||||
|
@ -109,12 +112,14 @@ const typeDefs = gql`
|
|||
items: [Item!]!
|
||||
}
|
||||
|
||||
type Color {
|
||||
# Cache for 1 week (unlikely to change)
|
||||
type Color @cacheControl(maxAge: 604800) {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
type Species {
|
||||
# Cache for 1 week (unlikely to change)
|
||||
type Species @cacheControl(maxAge: 604800) {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
|
@ -138,8 +143,8 @@ const typeDefs = gql`
|
|||
}
|
||||
|
||||
type Query {
|
||||
allColors: [Color!]! @cacheControl(maxAge: 10800) # Cache for 3 hours
|
||||
allSpecies: [Species!]! @cacheControl(maxAge: 10800) # Cache for 3 hours
|
||||
allColors: [Color!]! @cacheControl(maxAge: 10800) # Cache for 3 hours (we might add more!)
|
||||
allSpecies: [Species!]! @cacheControl(maxAge: 10800) # Cache for 3 hours (we might add more!)
|
||||
allValidSpeciesColorPairs: [SpeciesColorPair!]! # deprecated
|
||||
items(ids: [ID!]!): [Item!]!
|
||||
itemSearch(query: String!): ItemSearchResult!
|
||||
|
@ -151,8 +156,9 @@ const typeDefs = gql`
|
|||
limit: Int
|
||||
): ItemSearchResult!
|
||||
petAppearance(speciesId: ID!, colorId: ID!, pose: Pose!): PetAppearance
|
||||
@cacheControl(maxAge: 604800) # Cache for 1 week (unlikely to change)
|
||||
petAppearances(speciesId: ID!, colorId: ID!): [PetAppearance!]!
|
||||
|
||||
@cacheControl(maxAge: 10800) # Cache for 3 hours (we might add more!)
|
||||
outfit(id: ID!): Outfit
|
||||
|
||||
petOnNeopetsDotCom(petName: String!): Outfit
|
||||
|
@ -371,7 +377,7 @@ const resolvers = {
|
|||
return allPairs;
|
||||
},
|
||||
items: (_, { ids }) => {
|
||||
return ids.map(id => ({ id }));
|
||||
return ids.map((id) => ({ id }));
|
||||
},
|
||||
itemSearch: async (_, { query }, { itemSearchLoader }) => {
|
||||
const items = await itemSearchLoader.load(query.trim());
|
||||
|
|
Loading…
Reference in a new issue