-
Notifications
You must be signed in to change notification settings - Fork 7
Post-page performance batch: locale diet, chunk-wave diet, early stats fetch, content-visibility #1669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Post-page performance batch: locale diet, chunk-wave diet, early stats fetch, content-visibility #1669
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| "use client"; | ||
|
|
||
| import { useEffect } from "react"; | ||
| import { usePathname } from "next/navigation"; | ||
| import { useQueryClient } from "@tanstack/react-query"; | ||
| import { getPostTipsQueryOptions, getProMembersQueryOptions } from "@ecency/sdk"; | ||
|
|
||
| /* | ||
| Warms the two auth-free queries that paint an entry page's final pixels | ||
| (post tips and pro-members badges), firing with root hydration (#1668). | ||
|
|
||
| Without this, both fetch only when their components mount — and those sit | ||
| under the route-level streamed Suspense boundary, which React hydrates | ||
| lazily AFTER the DeferredRender feature cascade, pushing the requests to | ||
| ~4.5s although hydration completes ~2.9s. Prefetching from the root client | ||
| tree dedupes cleanly: the later component mounts hit the fresh cache entry | ||
| (staleTime 60s tips / 5min pro-members). | ||
|
|
||
| Section names below must stay in lockstep with the entry-vs-section split | ||
| in features/next-middleware/cache-policy.ts, which keeps the union in TWO | ||
| places: NO_CACHE_PROFILE_SECTIONS (wallet/settings/permissions/referrals/ | ||
| insights) plus the inline section array in its 2-segment entry branch. A | ||
| future section missing here costs exactly one throwaway 404 GET, nothing | ||
| more. | ||
| */ | ||
| const PROFILE_SECTIONS = new Set([ | ||
| "wallet", | ||
| "settings", | ||
| "permissions", | ||
| "referrals", | ||
| "insights", | ||
| "posts", | ||
| "blog", | ||
| "comments", | ||
| "replies", | ||
| "communities", | ||
| "trail", | ||
| "followers", | ||
| "following", | ||
| "rss", | ||
| "rss.xml", | ||
| "feed" | ||
| ]); | ||
|
|
||
| // /@author/permlink or /:category/@author/permlink | ||
| const ENTRY_2 = /^\/@([\w.-]+)\/([a-z0-9-]+)\/?$/; | ||
| const ENTRY_3 = /^\/[^/@]+\/@([\w.-]+)\/([a-z0-9-]+)\/?$/; | ||
|
|
||
| export function EntryStatsPrefetch(): null { | ||
| const pathname = usePathname(); | ||
| const queryClient = useQueryClient(); | ||
|
|
||
| useEffect(() => { | ||
| if (!pathname) { | ||
| return; | ||
| } | ||
| const match = ENTRY_2.exec(pathname) ?? ENTRY_3.exec(pathname); | ||
| if (!match) { | ||
| return; | ||
| } | ||
| // The query key must match what the entry components build from | ||
| // entry.author, which is always lowercase on chain. | ||
| const author = match[1].toLowerCase(); | ||
| const permlink = match[2]; | ||
| if (ENTRY_2.exec(pathname) && PROFILE_SECTIONS.has(permlink)) { | ||
| return; | ||
| } | ||
| void queryClient.prefetchQuery(getPostTipsQueryOptions(author, permlink)); | ||
| void queryClient.prefetchQuery(getProMembersQueryOptions()); | ||
| }, [pathname, queryClient]); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| return null; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| import i18n from "i18next"; | ||
|
|
||
| import dayjs from "@/utils/dayjs"; | ||
| import { setDayjsLocale } from "@/utils/dayjs"; | ||
| import * as ls from "@/utils/local-storage"; | ||
|
|
||
| export const langOptions = [ | ||
|
|
@@ -164,7 +164,7 @@ export function initI18next(): Promise<void> { | |
|
|
||
| i18n.on("languageChanged", async function (lang) { | ||
| await loadLocale(lang); | ||
| dayjs.locale(lang); | ||
| await setDayjsLocale(lang); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a user first switches to a locale whose Day.js table is lazy-loaded (for example Useful? React with 👍 / 👎.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confirmed and fixed in faa3f5f, at every language-change choke point rather than in the listener:
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confirmed and fixed in 4fa94d5: the server watcher no longer touches dayjs, and |
||
| }); | ||
|
|
||
| // Load the user's preferred locale on demand | ||
|
|
@@ -173,6 +173,7 @@ export function initI18next(): Promise<void> { | |
| if (userLang !== "en-US") { | ||
| await loadLocale(userLang); | ||
| } | ||
| await setDayjsLocale(userLang); | ||
| await i18n.changeLanguage(userLang); | ||
| })(); | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.