2022-09-14 18:38:58 -07:00
|
|
|
import React from "react";
|
2022-09-14 18:04:10 -07:00
|
|
|
import Head from "next/head";
|
|
|
|
import type { AppProps } from "next/app";
|
2022-09-14 19:15:48 -07:00
|
|
|
import type { NextPage } from "next";
|
2022-09-14 18:38:58 -07:00
|
|
|
import * as Sentry from "@sentry/react";
|
|
|
|
import { Integrations } from "@sentry/tracing";
|
|
|
|
import { Auth0Provider } from "@auth0/auth0-react";
|
|
|
|
import { CSSReset, ChakraProvider, extendTheme } from "@chakra-ui/react";
|
Fix /outfits/new init + add more SSR
Whew, setting up a cute GraphQL SSR system! I feel like it strikes a good balance of not having actually too many moving parts, though it's still a bit extensive for the problem we're solving 😅
Anyway, by doing SSR at _all_, we solve the problem where Next's "Automatic Static Optimization" was causing problems by setting the outfit state to the default at the start of the page load.
So I figured, why not try to SSR things _good_?
Now, when you navigate to the /outfits/new page, Next.js will go get the necessary GraphQL data to show the image before even putting the page into view. This makes the image show up all snappy-like! (when images.neopets.com is behaving :p)
We could do this with the stuff in the items panel too, but it's a tiny bit more annoying in the code right now, so I'm just gonna not worry about it and see how this performs in practice!
This change _doesn't_ include making the images actually show up before JS loads in, I assume because our JS code tries to validate that the images have loaded before fading them in on the page. Idk if we want to do something smarter there for the SSR case, to try to get them loading in faster!
2022-09-15 02:46:14 -07:00
|
|
|
import { ApolloProvider, NormalizedCacheObject } from "@apollo/client";
|
2022-09-14 18:38:58 -07:00
|
|
|
import { useAuth0 } from "@auth0/auth0-react";
|
|
|
|
import { mode } from "@chakra-ui/theme-tools";
|
|
|
|
|
|
|
|
import buildApolloClient from "../src/app/apolloClient";
|
2022-09-14 19:15:48 -07:00
|
|
|
import PageLayout from "../src/app/PageLayout";
|
|
|
|
|
|
|
|
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
[WIP] Refactor to renderWithLayout function
Okay, when I saw the recipe in the Next.js docs with `getLayout`, I was like "psh this API is so confusing, this should just be a component"
anyway now we see why it wasn't a component: the _whole point_ of it was to circumvent the usual React diffing algorithm's belief that two different components _can't_ ever share UI. But here we were, making different `layoutComponent`s that were meant to share UI, lol!
Anyway, if you just _return JSX in a function_, the React diffing algorithm never sees that it came from a different place, so it's generous when diffing them. Neat!
But I still changed the recipe's `getLayout` name to `renderWithLayout`, because it just confused me so much at first lol, I thought it was going to like, return a layout function? This is much clearer verbing to me imo
2022-09-14 22:50:56 -07:00
|
|
|
renderWithLayout?: (children: JSX.Element) => JSX.Element;
|
2022-09-14 19:15:48 -07:00
|
|
|
};
|
2022-09-14 18:38:58 -07:00
|
|
|
|
|
|
|
const theme = extendTheme({
|
|
|
|
styles: {
|
2023-11-02 16:50:05 -07:00
|
|
|
global: (props: any) => ({
|
2022-09-14 18:38:58 -07:00
|
|
|
html: {
|
|
|
|
// HACK: Chakra sets body as the relative position element, which is
|
|
|
|
// fine, except its `min-height: 100%` doesn't actually work
|
|
|
|
// unless paired with height on the root element too!
|
|
|
|
height: "100%",
|
|
|
|
},
|
|
|
|
body: {
|
|
|
|
background: mode("gray.50", "gray.800")(props),
|
|
|
|
color: mode("green.800", "green.50")(props),
|
|
|
|
transition: "all 0.25s",
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
});
|
[WIP] Run cra-to-next codemod to be on Nextjs
I'm interested in ejecting from Vercel, so I'm trying to get off their proprietary-ish create-react-app + Vercel API thing, and onto Nextjs, which is very similar in shape, but more portable.
I had to disable `craCompat` in `next.config.js` to stop us from crashing on their webpack config, see https://github.com/vercel/next.js/discussions/25858#discussioncomment-1573822
The frontend seems to work at a basic level, but network requests fail, and images don't seem to be working. I'll work on those next!
Note that this commit was forced through despite failing lint checks. We'll need to fix that up too!
Also, after the codemod, I moved `src/pages` to the more canonical location `pages`. Lint tooling seemed surprised to not find a `pages` directory, and I didn't see a config that was making it work correctly in the other location, so I figured it's that Next is willing to check `pages` or `src/pages`? But this is more canonical so yeah!
2021-11-01 21:48:09 -07:00
|
|
|
|
2023-11-02 16:50:05 -07:00
|
|
|
type AppPropsWithLayout = AppProps & {
|
|
|
|
Component: NextPageWithLayout;
|
|
|
|
pageProps: any;
|
|
|
|
};
|
2022-09-14 19:15:48 -07:00
|
|
|
|
|
|
|
export default function DTIApp({ Component, pageProps }: AppPropsWithLayout) {
|
[WIP] Refactor to renderWithLayout function
Okay, when I saw the recipe in the Next.js docs with `getLayout`, I was like "psh this API is so confusing, this should just be a component"
anyway now we see why it wasn't a component: the _whole point_ of it was to circumvent the usual React diffing algorithm's belief that two different components _can't_ ever share UI. But here we were, making different `layoutComponent`s that were meant to share UI, lol!
Anyway, if you just _return JSX in a function_, the React diffing algorithm never sees that it came from a different place, so it's generous when diffing them. Neat!
But I still changed the recipe's `getLayout` name to `renderWithLayout`, because it just confused me so much at first lol, I thought it was going to like, return a layout function? This is much clearer verbing to me imo
2022-09-14 22:50:56 -07:00
|
|
|
const renderWithLayout =
|
|
|
|
Component.renderWithLayout ?? renderWithDefaultLayout;
|
2022-09-14 19:15:48 -07:00
|
|
|
|
2022-09-14 18:38:58 -07:00
|
|
|
React.useEffect(() => setupLogging(), []);
|
|
|
|
|
[WIP] Run cra-to-next codemod to be on Nextjs
I'm interested in ejecting from Vercel, so I'm trying to get off their proprietary-ish create-react-app + Vercel API thing, and onto Nextjs, which is very similar in shape, but more portable.
I had to disable `craCompat` in `next.config.js` to stop us from crashing on their webpack config, see https://github.com/vercel/next.js/discussions/25858#discussioncomment-1573822
The frontend seems to work at a basic level, but network requests fail, and images don't seem to be working. I'll work on those next!
Note that this commit was forced through despite failing lint checks. We'll need to fix that up too!
Also, after the codemod, I moved `src/pages` to the more canonical location `pages`. Lint tooling seemed surprised to not find a `pages` directory, and I didn't see a config that was making it work correctly in the other location, so I figured it's that Next is willing to check `pages` or `src/pages`? But this is more canonical so yeah!
2021-11-01 21:48:09 -07:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<Head>
|
|
|
|
<title>Dress to Impress</title>
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
|
|
</Head>
|
2022-09-14 18:04:10 -07:00
|
|
|
|
2022-09-14 18:38:58 -07:00
|
|
|
<Auth0Provider
|
|
|
|
domain="openneo.us.auth0.com"
|
|
|
|
clientId="8LjFauVox7shDxVufQqnviUIywMuuC4r"
|
|
|
|
redirectUri={
|
|
|
|
process.env.NODE_ENV === "development"
|
|
|
|
? "http://localhost:3000"
|
|
|
|
: "https://impress-2020.openneo.net"
|
|
|
|
}
|
|
|
|
audience="https://impress-2020.openneo.net/api"
|
|
|
|
scope=""
|
|
|
|
>
|
2022-09-15 04:45:44 -07:00
|
|
|
<DTIApolloProvider additionalCacheState={pageProps.graphqlState ?? {}}>
|
2022-09-14 18:38:58 -07:00
|
|
|
<ChakraProvider theme={theme}>
|
|
|
|
<CSSReset />
|
[WIP] Refactor to renderWithLayout function
Okay, when I saw the recipe in the Next.js docs with `getLayout`, I was like "psh this API is so confusing, this should just be a component"
anyway now we see why it wasn't a component: the _whole point_ of it was to circumvent the usual React diffing algorithm's belief that two different components _can't_ ever share UI. But here we were, making different `layoutComponent`s that were meant to share UI, lol!
Anyway, if you just _return JSX in a function_, the React diffing algorithm never sees that it came from a different place, so it's generous when diffing them. Neat!
But I still changed the recipe's `getLayout` name to `renderWithLayout`, because it just confused me so much at first lol, I thought it was going to like, return a layout function? This is much clearer verbing to me imo
2022-09-14 22:50:56 -07:00
|
|
|
{renderWithLayout(<Component {...pageProps} />)}
|
2022-09-14 18:38:58 -07:00
|
|
|
</ChakraProvider>
|
2022-09-15 04:45:44 -07:00
|
|
|
</DTIApolloProvider>
|
2022-09-14 18:38:58 -07:00
|
|
|
</Auth0Provider>
|
[WIP] Run cra-to-next codemod to be on Nextjs
I'm interested in ejecting from Vercel, so I'm trying to get off their proprietary-ish create-react-app + Vercel API thing, and onto Nextjs, which is very similar in shape, but more portable.
I had to disable `craCompat` in `next.config.js` to stop us from crashing on their webpack config, see https://github.com/vercel/next.js/discussions/25858#discussioncomment-1573822
The frontend seems to work at a basic level, but network requests fail, and images don't seem to be working. I'll work on those next!
Note that this commit was forced through despite failing lint checks. We'll need to fix that up too!
Also, after the codemod, I moved `src/pages` to the more canonical location `pages`. Lint tooling seemed surprised to not find a `pages` directory, and I didn't see a config that was making it work correctly in the other location, so I figured it's that Next is willing to check `pages` or `src/pages`? But this is more canonical so yeah!
2021-11-01 21:48:09 -07:00
|
|
|
</>
|
2022-09-14 18:04:10 -07:00
|
|
|
);
|
[WIP] Run cra-to-next codemod to be on Nextjs
I'm interested in ejecting from Vercel, so I'm trying to get off their proprietary-ish create-react-app + Vercel API thing, and onto Nextjs, which is very similar in shape, but more portable.
I had to disable `craCompat` in `next.config.js` to stop us from crashing on their webpack config, see https://github.com/vercel/next.js/discussions/25858#discussioncomment-1573822
The frontend seems to work at a basic level, but network requests fail, and images don't seem to be working. I'll work on those next!
Note that this commit was forced through despite failing lint checks. We'll need to fix that up too!
Also, after the codemod, I moved `src/pages` to the more canonical location `pages`. Lint tooling seemed surprised to not find a `pages` directory, and I didn't see a config that was making it work correctly in the other location, so I figured it's that Next is willing to check `pages` or `src/pages`? But this is more canonical so yeah!
2021-11-01 21:48:09 -07:00
|
|
|
}
|
2022-09-14 18:38:58 -07:00
|
|
|
|
[WIP] Refactor to renderWithLayout function
Okay, when I saw the recipe in the Next.js docs with `getLayout`, I was like "psh this API is so confusing, this should just be a component"
anyway now we see why it wasn't a component: the _whole point_ of it was to circumvent the usual React diffing algorithm's belief that two different components _can't_ ever share UI. But here we were, making different `layoutComponent`s that were meant to share UI, lol!
Anyway, if you just _return JSX in a function_, the React diffing algorithm never sees that it came from a different place, so it's generous when diffing them. Neat!
But I still changed the recipe's `getLayout` name to `renderWithLayout`, because it just confused me so much at first lol, I thought it was going to like, return a layout function? This is much clearer verbing to me imo
2022-09-14 22:50:56 -07:00
|
|
|
function renderWithDefaultLayout(children: JSX.Element) {
|
|
|
|
return <PageLayout>{children}</PageLayout>;
|
|
|
|
}
|
|
|
|
|
2022-09-15 04:45:44 -07:00
|
|
|
function DTIApolloProvider({
|
Fix /outfits/new init + add more SSR
Whew, setting up a cute GraphQL SSR system! I feel like it strikes a good balance of not having actually too many moving parts, though it's still a bit extensive for the problem we're solving 😅
Anyway, by doing SSR at _all_, we solve the problem where Next's "Automatic Static Optimization" was causing problems by setting the outfit state to the default at the start of the page load.
So I figured, why not try to SSR things _good_?
Now, when you navigate to the /outfits/new page, Next.js will go get the necessary GraphQL data to show the image before even putting the page into view. This makes the image show up all snappy-like! (when images.neopets.com is behaving :p)
We could do this with the stuff in the items panel too, but it's a tiny bit more annoying in the code right now, so I'm just gonna not worry about it and see how this performs in practice!
This change _doesn't_ include making the images actually show up before JS loads in, I assume because our JS code tries to validate that the images have loaded before fading them in on the page. Idk if we want to do something smarter there for the SSR case, to try to get them loading in faster!
2022-09-15 02:46:14 -07:00
|
|
|
children,
|
2022-09-15 04:45:44 -07:00
|
|
|
additionalCacheState,
|
Fix /outfits/new init + add more SSR
Whew, setting up a cute GraphQL SSR system! I feel like it strikes a good balance of not having actually too many moving parts, though it's still a bit extensive for the problem we're solving 😅
Anyway, by doing SSR at _all_, we solve the problem where Next's "Automatic Static Optimization" was causing problems by setting the outfit state to the default at the start of the page load.
So I figured, why not try to SSR things _good_?
Now, when you navigate to the /outfits/new page, Next.js will go get the necessary GraphQL data to show the image before even putting the page into view. This makes the image show up all snappy-like! (when images.neopets.com is behaving :p)
We could do this with the stuff in the items panel too, but it's a tiny bit more annoying in the code right now, so I'm just gonna not worry about it and see how this performs in practice!
This change _doesn't_ include making the images actually show up before JS loads in, I assume because our JS code tries to validate that the images have loaded before fading them in on the page. Idk if we want to do something smarter there for the SSR case, to try to get them loading in faster!
2022-09-15 02:46:14 -07:00
|
|
|
}: {
|
|
|
|
children: React.ReactNode;
|
2022-09-15 04:45:44 -07:00
|
|
|
additionalCacheState: NormalizedCacheObject;
|
Fix /outfits/new init + add more SSR
Whew, setting up a cute GraphQL SSR system! I feel like it strikes a good balance of not having actually too many moving parts, though it's still a bit extensive for the problem we're solving 😅
Anyway, by doing SSR at _all_, we solve the problem where Next's "Automatic Static Optimization" was causing problems by setting the outfit state to the default at the start of the page load.
So I figured, why not try to SSR things _good_?
Now, when you navigate to the /outfits/new page, Next.js will go get the necessary GraphQL data to show the image before even putting the page into view. This makes the image show up all snappy-like! (when images.neopets.com is behaving :p)
We could do this with the stuff in the items panel too, but it's a tiny bit more annoying in the code right now, so I'm just gonna not worry about it and see how this performs in practice!
This change _doesn't_ include making the images actually show up before JS loads in, I assume because our JS code tries to validate that the images have loaded before fading them in on the page. Idk if we want to do something smarter there for the SSR case, to try to get them loading in faster!
2022-09-15 02:46:14 -07:00
|
|
|
}) {
|
2022-09-14 18:38:58 -07:00
|
|
|
const auth0 = useAuth0();
|
|
|
|
const auth0Ref = React.useRef(auth0);
|
|
|
|
|
|
|
|
React.useEffect(() => {
|
|
|
|
auth0Ref.current = auth0;
|
|
|
|
}, [auth0]);
|
|
|
|
|
2022-09-15 04:45:44 -07:00
|
|
|
// Save the first `additionalCacheState` we get as our `initialCacheState`,
|
|
|
|
// which we'll use to initialize the client without having to wait a tick.
|
2023-11-02 16:50:05 -07:00
|
|
|
const [initialCacheState, unusedSetInitialCacheState] =
|
|
|
|
React.useState(additionalCacheState);
|
2022-09-15 04:45:44 -07:00
|
|
|
|
2022-09-14 18:38:58 -07:00
|
|
|
const client = React.useMemo(
|
Fix /outfits/new init + add more SSR
Whew, setting up a cute GraphQL SSR system! I feel like it strikes a good balance of not having actually too many moving parts, though it's still a bit extensive for the problem we're solving 😅
Anyway, by doing SSR at _all_, we solve the problem where Next's "Automatic Static Optimization" was causing problems by setting the outfit state to the default at the start of the page load.
So I figured, why not try to SSR things _good_?
Now, when you navigate to the /outfits/new page, Next.js will go get the necessary GraphQL data to show the image before even putting the page into view. This makes the image show up all snappy-like! (when images.neopets.com is behaving :p)
We could do this with the stuff in the items panel too, but it's a tiny bit more annoying in the code right now, so I'm just gonna not worry about it and see how this performs in practice!
This change _doesn't_ include making the images actually show up before JS loads in, I assume because our JS code tries to validate that the images have loaded before fading them in on the page. Idk if we want to do something smarter there for the SSR case, to try to get them loading in faster!
2022-09-15 02:46:14 -07:00
|
|
|
() =>
|
|
|
|
buildApolloClient({
|
|
|
|
getAuth0: () => auth0Ref.current,
|
|
|
|
initialCacheState,
|
|
|
|
}),
|
2023-11-02 16:50:05 -07:00
|
|
|
[initialCacheState],
|
2022-09-14 18:38:58 -07:00
|
|
|
);
|
2022-09-15 04:45:44 -07:00
|
|
|
|
|
|
|
// When we get a new `additionalCacheState` object, merge it into the cache:
|
|
|
|
// copy the previous cache state, merge the new cache state's entries in,
|
|
|
|
// and "restore" the new merged cache state.
|
|
|
|
//
|
|
|
|
// HACK: Using `useMemo` for this is a dastardly trick!! What we want is the
|
|
|
|
// semantics of `useEffect` kinda, but we need to ensure it happens
|
|
|
|
// *before* all the children below get rendered, so they don't fire off
|
|
|
|
// unnecessary network requests. Using `useMemo` but throwing away the
|
|
|
|
// result kinda does that. It's evil! It's nasty! It's... perfect?
|
|
|
|
// (This operation is safe to run multiple times too, in case memo
|
|
|
|
// re-runs it. It's just, y'know, a performance loss. Maybe it's
|
|
|
|
// actually kinda perfect lol)
|
|
|
|
//
|
|
|
|
// I feel like there's probably a better way to do this... like, I want
|
|
|
|
// the semantic of replacing this client with an updated client - but I
|
|
|
|
// don't want to actually replace the client, because that'll break
|
|
|
|
// other kinds of state, like requests loading in the shared layout.
|
|
|
|
// Idk! I'll see how it goes!
|
|
|
|
React.useMemo(() => {
|
|
|
|
const previousCacheState = client.cache.extract();
|
|
|
|
const mergedCacheState = { ...previousCacheState };
|
|
|
|
for (const key of Object.keys(additionalCacheState)) {
|
|
|
|
mergedCacheState[key] = {
|
|
|
|
...mergedCacheState[key],
|
|
|
|
...additionalCacheState[key],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
console.debug(
|
|
|
|
"Merging Apollo cache:",
|
|
|
|
additionalCacheState,
|
2023-11-02 16:50:05 -07:00
|
|
|
mergedCacheState,
|
2022-09-15 04:45:44 -07:00
|
|
|
);
|
|
|
|
client.cache.restore(mergedCacheState);
|
|
|
|
}, [client, additionalCacheState]);
|
|
|
|
|
2022-09-14 18:38:58 -07:00
|
|
|
return <ApolloProvider client={client}>{children}</ApolloProvider>;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setupLogging() {
|
|
|
|
Sentry.init({
|
2023-11-02 16:50:05 -07:00
|
|
|
dsn: "https://c55875c3b0904264a1a99e5b741a221e@o506079.ingest.sentry.io/5595379",
|
2022-09-14 18:38:58 -07:00
|
|
|
autoSessionTracking: true,
|
|
|
|
integrations: [
|
|
|
|
new Integrations.BrowserTracing({
|
|
|
|
beforeNavigate: (context) => ({
|
|
|
|
...context,
|
|
|
|
// Assume any path segment starting with a digit is an ID, and replace
|
|
|
|
// it with `:id`. This will help group related routes in Sentry stats.
|
|
|
|
// NOTE: I'm a bit uncertain about the timing on this for tracking
|
|
|
|
// client-side navs... but we now only track first-time
|
|
|
|
// pageloads, and it definitely works correctly for them!
|
|
|
|
name: window.location.pathname.replaceAll(/\/[0-9][^/]*/g, "/:id"),
|
|
|
|
}),
|
|
|
|
|
|
|
|
// We have a _lot_ of location changes that don't actually signify useful
|
|
|
|
// navigations, like in the wardrobe page. It could be useful to trace
|
|
|
|
// them with better filtering someday, but frankly we don't use the perf
|
|
|
|
// features besides Web Vitals right now, and those only get tracked on
|
|
|
|
// first-time pageloads, anyway. So, don't track client-side navs!
|
|
|
|
startTransactionOnLocationChange: false,
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
denyUrls: [
|
|
|
|
// Don't log errors that were probably triggered by extensions and not by
|
|
|
|
// our own app. (Apparently Sentry's setting to ignore browser extension
|
|
|
|
// errors doesn't do this anywhere near as consistently as I'd expect?)
|
|
|
|
//
|
|
|
|
// Adapted from https://gist.github.com/impressiver/5092952, as linked in
|
|
|
|
// https://docs.sentry.io/platforms/javascript/configuration/filtering/.
|
|
|
|
/^chrome-extension:\/\//,
|
|
|
|
/^moz-extension:\/\//,
|
|
|
|
],
|
|
|
|
|
2023-11-06 12:30:53 -08:00
|
|
|
// Don't actually send anything to Sentry though… we want to focus on
|
|
|
|
// errors from the new main app!
|
|
|
|
// TODO: If this codebase were to continue, we would want to remove Sentry,
|
|
|
|
// or make its output more reliable!
|
|
|
|
sampleRate: 0,
|
|
|
|
tracesSampleRate: 0,
|
2022-09-14 18:38:58 -07:00
|
|
|
});
|
|
|
|
}
|