enable HTTP caching for pet appearances

This commit is contained in:
Emi Matchu 2020-07-22 23:08:28 -07:00
parent 9f11c83b20
commit ffde7172de
2 changed files with 69 additions and 33 deletions

View file

@ -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) {

View file

@ -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());