ぼざクリタグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

109 lines
3.5 KiB

  1. import { QueryClient } from '@tanstack/react-query'
  2. import { match } from 'path-to-regexp'
  3. import { fetchPost, fetchPosts, fetchPostChanges } from '@/lib/posts'
  4. import { postsKeys, tagsKeys, wikiKeys } from '@/lib/queryKeys'
  5. import { fetchTagByName } from '@/lib/tags'
  6. import { fetchWikiPageByTitle, fetchWikiPages } from '@/lib/wiki'
  7. type Prefetcher = (qc: QueryClient, url: URL) => Promise<void>
  8. const mPost = match<{ id: string }> ('/posts/:id')
  9. const mWiki = match<{ title: string }> ('/wiki/:title')
  10. const prefetchWikiPagesIndex: Prefetcher = async (qc, url) => {
  11. const title = url.searchParams.get ('title') ?? ''
  12. await qc.prefetchQuery ({
  13. queryKey: wikiKeys.index ({ title }),
  14. queryFn: () => fetchWikiPages ({ title }) })
  15. }
  16. const prefetchWikiPageShow: Prefetcher = async (qc, url) => {
  17. const m = mWiki (url.pathname)
  18. if (!(m))
  19. return
  20. const title = decodeURIComponent (m.params.title)
  21. const version = url.searchParams.get ('version') || undefined
  22. const wikiPage = await qc.fetchQuery ({
  23. queryKey: wikiKeys.show (title, { version }),
  24. queryFn: () => fetchWikiPageByTitle (title, { version }) })
  25. const effectiveTitle = wikiPage.title
  26. await qc.prefetchQuery ({
  27. queryKey: tagsKeys.show (effectiveTitle),
  28. queryFn: () => fetchTagByName (effectiveTitle) })
  29. if (version)
  30. return
  31. const p = { tags: effectiveTitle, match: 'all', page: 1, limit: 8 } as const
  32. await qc.prefetchQuery ({
  33. queryKey: postsKeys.index (p),
  34. queryFn: () => fetchPosts (p) })
  35. }
  36. const prefetchPostsIndex: Prefetcher = async (qc, url) => {
  37. const tags = url.searchParams.get ('tags') ?? ''
  38. const m = url.searchParams.get ('match') === 'any' ? 'any' : 'all'
  39. const page = Number (url.searchParams.get ('page') || 1)
  40. const limit = Number (url.searchParams.get ('limit') || 20)
  41. await qc.prefetchQuery ({
  42. queryKey: postsKeys.index ({ tags, match: m, page, limit }),
  43. queryFn: () => fetchPosts ({ tags, match: m, page, limit }) })
  44. }
  45. const prefetchPostShow: Prefetcher = async (qc, url) => {
  46. const m = mPost (url.pathname)
  47. if (!(m))
  48. return
  49. const { id } = m.params
  50. await qc.prefetchQuery ({
  51. queryKey: postsKeys.show (id),
  52. queryFn: () => fetchPost (id) })
  53. }
  54. const prefetchPostChanges: Prefetcher = async (qc, url) => {
  55. const id = url.searchParams.get ('id')
  56. const page = Number (url.searchParams.get ('page') || 1)
  57. const limit = Number (url.searchParams.get ('limit') || 20)
  58. await qc.prefetchQuery ({
  59. queryKey: postsKeys.changes ({ ...(id && { id }), page, limit }),
  60. queryFn: () => fetchPostChanges ({ ...(id && { id }), page, limit }) })
  61. }
  62. export const routePrefetchers: { test: (u: URL) => boolean; run: Prefetcher }[] = [
  63. { test: u => u.pathname === '/' || u.pathname === '/posts', run: prefetchPostsIndex },
  64. { test: u => (!(['/posts/new', '/posts/changes'].includes (u.pathname))
  65. && Boolean (mPost (u.pathname))),
  66. run: prefetchPostShow },
  67. { test: u => u.pathname === '/posts/changes', run: prefetchPostChanges },
  68. { test: u => u.pathname === '/wiki', run: prefetchWikiPagesIndex },
  69. { test: u => (!(['/wiki/new', '/wiki/changes'].includes (u.pathname))
  70. && Boolean (mWiki (u.pathname))),
  71. run: prefetchWikiPageShow },
  72. ]
  73. export const prefetchForURL = async (qc: QueryClient, urlLike: string): Promise<void> => {
  74. const u = new URL (urlLike, location.origin)
  75. const jobs = routePrefetchers.filter (r => r.test (u)).map (r => r.run (qc, u))
  76. if (jobs.length === 0)
  77. return
  78. await Promise.all (jobs)
  79. }