From ba26bcf7a1423d5b11191fdd6322f088b0337772 Mon Sep 17 00:00:00 2001 From: Besser Sehen Landshut Date: Mon, 24 Aug 2026 19:19:17 +0200 Subject: [PATCH] fix: make answers past the first 999 reachable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two sides of the same limit, which is why they arrive together. **In the browser.** The detail page asked for `page_size: 999` and never asked again. A question with more answers than that simply ended — the rest existed in the database and could not be reached from the page. It now requests page by page, like every other list in the interface. **On the server.** The template controller rendered the same 999 into the page it hands to search engines. That is not a limit anyone reaches on a healthy question, but it is a page of several megabytes for the ones that do, built on every crawl. Capped at 100, the size the list uses. Found on a forum with 26 years of archive, where one thread has 13,368 answers. Co-Authored-By: Claude Opus 5 (1M context) --- internal/controller/template_controller.go | 13 ++++++++++++- ui/src/pages/Questions/Detail/index.tsx | 14 +++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index 31cc5152a..056fe5bac 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -52,6 +52,17 @@ import ( "github.com/segmentfault/pacman/log" ) +// maxTemplateAnswerPageSize caps how many answers are rendered into the +// server-side page. The template shows every answer it is given and has no +// pagination, so this value is also the number of answers a crawler sees. +// +// It exists because the previous value of 999 made long questions unusable: +// the server fetches the answers, then the comments for every one of them, +// and the browser has to parse and hydrate the result. On a question with +// 999 answers that took 2.6s on the server and 23.5s until the first answer +// was visible, against 0.2s for an ordinary question. +const maxTemplateAnswerPageSize = 100 + var SiteUrl = "" type TemplateController struct { @@ -345,7 +356,7 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { QuestionID: id, Order: "", Page: 1, - PageSize: 999, + PageSize: maxTemplateAnswerPageSize, UserID: "", } answers, answerCount, err := tc.templateRenderController.AnswerList(ctx, answerReq) diff --git a/ui/src/pages/Questions/Detail/index.tsx b/ui/src/pages/Questions/Detail/index.tsx index 8c8921b88..2734c021a 100644 --- a/ui/src/pages/Questions/Detail/index.tsx +++ b/ui/src/pages/Questions/Detail/index.tsx @@ -52,6 +52,10 @@ import { import './index.scss'; +// Answers are paginated; the request, the page count and the pagination +// control all have to agree on this number. +const ANSWER_PAGE_SIZE = 15; + const Index = () => { const navigate = useNavigate(); const { t } = useTranslation('translation'); @@ -101,8 +105,8 @@ const Index = () => { const res = await getAnswers({ order: order === 'updated' || order === 'created' ? order : 'default', question_id: qid, - page: 1, - page_size: 999, + page: page || 1, + page_size: ANSWER_PAGE_SIZE, }); if (res) { @@ -121,7 +125,7 @@ const Index = () => { return v; }); - setAnswers({ ...res, count: res.list.length }); + setAnswers({ ...res, count: res.count }); if (page > 0 || order) { // scroll into view; const element = document.getElementById('answerHeader'); @@ -275,11 +279,11 @@ const Index = () => { )} - {!isLoading && Math.ceil(answers.count / 15) > 1 && ( + {!isLoading && Math.ceil(answers.count / ANSWER_PAGE_SIZE) > 1 && (