Open
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
perf: enable webpack production mode and optimization
perf: add compression middleware and optimize cache headers
Perf/webpack babel
perf: migrate Tailwind CSS from CDN runtime to build-time PostCSS Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf: migrate Tailwind CSS from CDN runtime to build-time PostCSS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: replace jQuery, moment.js, lodash, bluebird with native APIs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: keep Buffer in ProvidePlugin (needed by CoveredImage until PR6) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf: migrate Tailwind CSS from CDN runtime to build-time PostCSS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: replace jQuery, moment.js, lodash, bluebird with native APIs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: add route-based code splitting with React.lazy and dynamic imports Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: add route-based code splitting with React.lazy and dynamic imports Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ci: add CI workflow for lint, typecheck, build, and E2E Add GitHub Actions CI workflow that runs on PRs and pushes to main. Jobs run in parallel (lint, typecheck, build) with E2E depending on build. E2E uses continue-on-error since Linux VRT snapshots are not yet available. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ci): run corepack enable before setup-node setup-node's pnpm cache requires pnpm to be on PATH, so corepack enable must run before setup-node, not after. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve typecheck and formatting errors Remove unused RequestHandler import in static.ts and apply oxfmt formatting fixes to pass CI checks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ci): correct build artifact path to application/dist/ Webpack outputs to application/dist/, not application/client/dist/. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ci: parallelize E2E tests with sharding and cache Playwright browsers Split E2E tests into 3 shards running in parallel, cache Playwright browser binaries across runs, and set E2E_WORKERS=2 to utilize both vCPUs on ubuntu-latest runners. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
chore: add pre-commit hook with lint-staged for automated linting Set up git hooks via .husky/pre-commit to run oxlint and oxfmt on staged files automatically before each commit using lint-staged. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf: migrate Tailwind CSS from CDN runtime to build-time PostCSS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: replace jQuery, moment.js, lodash, bluebird with native APIs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: add route-based code splitting with React.lazy and dynamic imports Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: optimize fonts (WOFF2), images (WebP), and simplify CoveredImage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ci: fix VRT snapshots for Linux CI and add snapshot update workflow - Remove *.png from e2e .gitignore to track VRT snapshots in git - Change Playwright browser from chromium to chrome to match config - Add workflow_dispatch workflow for updating Linux snapshots - Include existing darwin snapshots in git Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace intentionally heavy main-thread patterns with efficient observers: - InfiniteScroll: remove 2^18 DOM read loop, use single check with rAF throttle and passive listeners - DirectMessagePage: replace 1ms setInterval+getComputedStyle with MutationObserver - useHasContentBelow: replace 1ms postTask polling with IntersectionObserver - AspectRatioBox: replace setTimeout(500)+resize listener with ResizeObserver Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
perf: optimize initial render (remove load listener, react-helmet, add font preload)
- Remove window.addEventListener("load") wrapper for immediate React render
- Replace react-helmet with document.title via useEffect across all containers
- Add font preload links for WOFF2 files in index.html
- Add decoding="async" to CoveredImage img tag
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
perf: reduce bundle size (splitChunks, remove polyfills, native compression) - Add webpack splitChunks cacheGroups for React vendor chunk + maxSize 200KB - Remove standardized-audio-context ProvidePlugin (use native AudioContext) - Replace pako gzip with native CompressionStream API - Switch react-syntax-highlighter to light build with selective language registration Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
perf: subset fonts (3.8MB→260KB) and dynamic import katex CSS - Subset ReiNoAreMincho WOFF2 fonts to only include used characters (1255 chars) - Regular: 3.8MB → 262KB, Heavy: 3.9MB → 260KB - Move katex CSS import to dynamic import for code-split chunk loading Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
perf: optimize media (native GIF rendering, direct audio URL) - Replace gifler/omggif canvas-based GIF decoding with native <img> tag - Use direct audio URL in <audio> element instead of fetchBinary + blob URL - SoundWaveSVG fetches audio internally on demand instead of receiving ArrayBuffer - Remove gifler, omggif, @types/omggif dependencies Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
) - Replace 1ms scheduler.postTask polling in useSearchParams with popstate/pushState interception - Add React.memo to TimelineItem, PostItem, ChatMessage - Extract Markdown plugin arrays to module scope in ChatMessage - Debounce sentiment analysis (300ms) in SearchPage - Debounce BM25 suggestion search (200ms) in ChatInput - Scope MutationObserver to message list container in DirectMessagePage Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add indexes to FK columns (Post, Comment, DirectMessage, DirectMessageConversation, User) - Optimize DirectMessage afterSave hook (skip redundant findByPk, use unscoped) - Merge dual search queries into single query with Op.or - Use unscoped() in DM list endpoint to control eager loading Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf: add Brotli compression via shrink-ray-current - Replace compression middleware with shrink-ray-current for Brotli support - Remove compression and @types/compression dependencies - Add pnpm.onlyBuiltDependencies for native build deps (iltorb, node-zopfli-es) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add negaposi-analyzer-ja to onlyBuiltDependencies The negaposi-analyzer-ja package downloads its dictionary file (pn_ja.dic.json) via a postinstall script. Without listing it in pnpm.onlyBuiltDependencies, the script is blocked and the build fails with a missing module error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove node-zopfli-es from onlyBuiltDependencies node-zopfli-es fails to build with node-gyp on Node 24 (both CI and local). It is only used for zopfli compression by shrink-ray-current and is not required for Brotli. Removing it from the allowlist lets pnpm skip its broken native build. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
npx was resolving to the latest global version (0.41.0) instead of the project-pinned version (0.36.0), causing formatting check failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove core-js, image-size (installed but never imported) - Remove buffer package and Buffer ProvidePlugin from webpack - Replace encoding-japanese with native TextDecoder in extract_metadata_from_sound Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: add SubmissionError guard for search form validation on React 19 redux-form 8.x relies on UNSAFE_componentWillReceiveProps for initial syncErrors hydration. React 19's batching changes prevent this from firing on mount when initialValues are provided, leaving the store without syncErrors and allowing invalid submissions to bypass validation. Adding explicit validate + SubmissionError in onSubmit ensures the error message is displayed even when redux-form's internal sync validation pipeline is not triggered. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…26) shrink-ray-current depends on iltorb, a deprecated native Brotli module that fails to build with node-gyp on Linux (Docker). Replace it with the compression middleware which uses Node.js built-in zlib and requires no native compilation. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: make AuthModalContainer static import to prevent sign-in dialog timeout
AuthModalContainer was lazy-loaded with <Suspense fallback={null}>, which meant
the <dialog> element didn't exist in the DOM until the chunk finished loading.
When the sign-in button (using Invoker Commands API: command="show-modal") was
clicked before the chunk loaded, nothing happened — causing E2E test timeouts.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove default loading="lazy" and fetchPriority="low" from CoveredImage so above-fold images use browser native heuristics instead of being forced lazy - Correctly identify first image post in Timeline for isAboveFold marking - Set profile images in viewport to loading="eager" - Change PostItem (detail page) profile image to loading="eager" - Parallelize waveform computation in static.ts with Promise.all - Pre-compute all waveforms at server startup to warm cache and eliminate TTFB blocking on first home page request Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: use inline style for dynamic background color in UserProfileHeader
Tailwind CSS cannot detect dynamically generated class names like
`bg-[${averageColor}]` at build time, so the average color extracted
from the profile image was never applied (header stayed white instead
of the expected color). Switch to an inline `style` attribute to
ensure the computed color is rendered correctly.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
perf: defer modal chunk loading to reduce TBT variability AuthModalContainer and NewPostModalContainer were loaded via React.lazy() + Suspense on every page, causing their chunk parse/eval to sometimes fall within the FCP→TTI measurement window and inflate TBT scores unpredictably (0–30 range). Replace with DeferredModal component that: - Renders a lightweight placeholder <dialog> immediately (preserving commandfor compat) - Loads the actual chunk via requestIdleCallback (outside measurement window) - Falls back to toggle-event-driven loading if user interacts before idle load completes Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove FFmpeg WASM / ImageMagick WASM dead code (unused util files) - Move negaposi-analyzer-ja sentiment analysis to server API (/api/v1/sentiment) - Move kuromoji / BM25 suggestion filtering to server API (/api/v1/crok/suggestions?q=) - Move web-llm translation to server API (/api/v1/translate) using MyMemory - Remove 17MB kuromoji dict files from public/dicts/ - Clean up webpack config (aliases, cacheGroups, ignoreWarnings) - Remove 13 client dependencies: @ffmpeg/*, @imagemagick/*, @mlc-ai/web-llm, kuromoji, bayesian-bm25, negaposi-analyzer-ja, common-tags, json-repair-js, langs, piexifjs and related @types Client bundle reduced from ~10MB to ~2.78MB. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use 2-phase query for search API to fix pagination with subQuery: false subQuery: false causes LIMIT to apply after JOIN expansion, so posts with multiple images consume multiple rows. Split into Phase 1 (ID-only query without images JOIN) and Phase 2 (full data fetch by IDs). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: sort search results by createdAt DESC to match original behavior The original search code sorted results by createdAt DESC. The 2-phase query fix needs to preserve this ordering since defaultScope uses id DESC (UUIDs don't correlate with creation time). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf: fix LCP image loading and pre-compute waveforms - Remove default loading="lazy" and fetchPriority="low" from CoveredImage so above-fold images use browser native heuristics instead of being forced lazy - Correctly identify first image post in Timeline for isAboveFold marking - Set profile images in viewport to loading="eager" - Change PostItem (detail page) profile image to loading="eager" - Parallelize waveform computation in static.ts with Promise.all - Pre-compute all waveforms at server startup to warm cache and eliminate TTFB blocking on first home page request Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: add server-side image resizing with disk cache Add sharp-based on-the-fly image resize middleware that intercepts image requests with ?w= query parameter, resizes to the requested width, and caches results to /tmp/image-cache/. All image components now request appropriately sized images (686px for post images, 80-256px for profile images) instead of full-resolution originals. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use nearLossless WebP and skip resize for color-extracted profile image - UserProfileHeader uses FastAverageColor on the profile image, so resizing changes the extracted color and breaks VRT. Use original image here. - Switch WebP encoding to nearLossless for better VRT compatibility. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
chore: improve CLAUDE.md with missing API routes and dev notes - Add complete API route list (including sentiment, translate) - Add GITHUB_TOKEN note to Git & PRs section - Add parallel development workflow section for worktree-based agents Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf: replace redux-form with react-hook-form and remove Redux Migrate all 3 forms (auth, search, DM) from redux-form HOC to react-hook-form hooks. Remove redux, react-redux, redux-form and their type definitions. This eliminates ~55KB gzip from the initial bundle (redux-form + lodash transitive dependency + redux + react-redux). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use mode onChange and show errors after submit attempt - Change react-hook-form mode from onBlur to onChange so isValid updates on every keystroke (matching redux-form's invalid behavior) - Show validation errors after submit attempt (isSubmitted) to match redux-form marking all fields as touched on submit - Remove redundant manual validation in SearchPage onSubmit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Redux removal, Webpack optimization enablement, and heavy dependency cleanup were already done in prior PRs but CLAUDE.md still described the initial unoptimized state. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
) perf: lazy-load Markdown renderer and use startTransition for Crok chat Reduce TBT/INP on Crok AI chat by: - Wrapping onDone state updates in startTransition so React can split the heavy Markdown rendering into interruptible chunks - Extracting MarkdownRenderer (react-markdown + KaTeX + GFM) into a lazy-loaded component with Suspense fallback showing plain text Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update CLAUDE.md to reflect current codebase state Redux removal, Webpack optimization enablement, and heavy dependency cleanup were already done in prior PRs but CLAUDE.md still described the initial unoptimized state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: cache home HTML response and inject initial data for all routes Home page HTML is now cached after first build (with dedup for concurrent requests). Non-home routes (/posts/:id, /users/:username, /search) get server-injected __INITIAL_DATA__ to eliminate the JS→API waterfall. Cache is invalidated on POST /posts and rebuilt on POST /initialize. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: use raw SQL subquery for correct per-conversation latest message in DM list Sequelize 6's `separate: true` + `limit: 1` applies LIMIT globally instead of per-parent, causing each conversation to show an incorrect "latest" message. Replace with a raw SQL subquery that correctly gets MAX(createdAt) per conversation, fixing DM list ordering and preview. Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.