feat: support sitemap (#559)
This commit is contained in:
parent
8535a5cf26
commit
b420fc5882
|
|
@ -0,0 +1,60 @@
|
|||
import dayjs from "dayjs"
|
||||
import { NextRequest } from "next/server"
|
||||
|
||||
import { QueryClient } from "@tanstack/react-query"
|
||||
|
||||
import { getSiteLink } from "~/lib/helpers"
|
||||
import { NextServerResponse } from "~/lib/server-helper"
|
||||
import { PageVisibilityEnum } from "~/lib/types"
|
||||
import { fetchGetPagesBySite } from "~/queries/page.server"
|
||||
import { fetchGetSite } from "~/queries/site.server"
|
||||
|
||||
export const GET = async (req: NextRequest) => {
|
||||
const response = new NextServerResponse()
|
||||
|
||||
const queryClient = new QueryClient()
|
||||
// http://localhost:2222/site/innei-4525/sitemap.xml
|
||||
// http://innei-4525.localhost:2222/sitemap.xml
|
||||
// find innei-5425 site handle by regexp
|
||||
const domainOrSubdomain =
|
||||
req.nextUrl.pathname.match(/\/site\/(.*)\/sitemap.xml/)?.[1] ||
|
||||
req.headers.get("x-handle") ||
|
||||
// http://innei-4525.localhost:2222/sitemap.xml
|
||||
req.headers.get("host")?.split(".")[0] ||
|
||||
""
|
||||
|
||||
if (!domainOrSubdomain) {
|
||||
return response.status(400).json({
|
||||
message: "domainOrSubdomain is not validate",
|
||||
})
|
||||
}
|
||||
|
||||
const site = await fetchGetSite(domainOrSubdomain, queryClient)
|
||||
|
||||
const pages = await fetchGetPagesBySite(
|
||||
{
|
||||
characterId: site?.characterId,
|
||||
type: "post",
|
||||
visibility: PageVisibilityEnum.Published,
|
||||
},
|
||||
queryClient,
|
||||
)
|
||||
|
||||
const link = getSiteLink({
|
||||
subdomain: site?.handle || "",
|
||||
})
|
||||
return response.headers({
|
||||
"Content-Type": "text/xml",
|
||||
"Access-Control-Allow-Methods": "GET",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
}).text(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
${pages.list?.map((page) => {
|
||||
return ` <url>
|
||||
<loc>${link}/${page.metadata.content.slug}</loc>
|
||||
<lastmod>${dayjs(page.updatedAt).format("YYYY-MM-DD")}</lastmod>
|
||||
</url>`
|
||||
}).join(`
|
||||
`)}
|
||||
</urlset>`)
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ export const getQuery = (req: Request) => {
|
|||
|
||||
export class NextServerResponse {
|
||||
#status: number = 200
|
||||
#headers = new Headers()
|
||||
constructor() {}
|
||||
|
||||
status(status: number) {
|
||||
|
|
@ -25,12 +26,9 @@ export class NextServerResponse {
|
|||
json(data: any) {
|
||||
const nextData = JSON.stringify(data)
|
||||
|
||||
return new Response(nextData, {
|
||||
status: this.#status,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
this.#headers.set("Content-Type", "application/json")
|
||||
|
||||
return new Response(nextData, this.makeResponseOptions())
|
||||
}
|
||||
|
||||
send(data: any) {
|
||||
|
|
@ -42,11 +40,23 @@ export class NextServerResponse {
|
|||
return this.json(data)
|
||||
}
|
||||
|
||||
return new Response(data, { status: this.#status })
|
||||
return new Response(data, this.makeResponseOptions())
|
||||
}
|
||||
|
||||
text(text: string) {
|
||||
return new Response(text, this.makeResponseOptions())
|
||||
}
|
||||
|
||||
end() {
|
||||
return new Response("", { status: this.#status })
|
||||
return new Response("", this.makeResponseOptions())
|
||||
}
|
||||
|
||||
headers(headers: Record<string, string>) {
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
this.#headers.set(key, value)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
rss(data: any, format = "json") {
|
||||
|
|
@ -72,4 +82,11 @@ export class NextServerResponse {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
private makeResponseOptions() {
|
||||
return {
|
||||
status: this.#status,
|
||||
headers: this.#headers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,7 @@ export default async function middleware(req: NextRequest) {
|
|||
pathname.match(/^\/(workbox|worker|fallback)-\w+\.js(\.map)?$/) ||
|
||||
pathname === "/sw.js" ||
|
||||
pathname === "/sw.js.map" ||
|
||||
pathname === "/robots.txt" ||
|
||||
pathname === "/sitemap.xml"
|
||||
pathname === "/robots.txt"
|
||||
) {
|
||||
return NextResponse.next()
|
||||
}
|
||||
|
|
@ -84,6 +83,7 @@ export default async function middleware(req: NextRequest) {
|
|||
const requestHeaders = new Headers(req.headers)
|
||||
requestHeaders.set("x-pathname", req.nextUrl.pathname)
|
||||
requestHeaders.set("x-search", req.nextUrl.search)
|
||||
requestHeaders.set("x-handle", tenant.subdomain || "")
|
||||
|
||||
if (tenant?.subdomain) {
|
||||
const url = req.nextUrl.clone()
|
||||
|
|
|
|||
Loading…
Reference in New Issue