feat: migrate from moment.js to date-fns for better performance and bundle size#5019
feat: migrate from moment.js to date-fns for better performance and bundle size#5019harshdhankhar10 wants to merge 2 commits intoasyncapi:masterfrom
Conversation
- Remove moment.js dependency (67.8KB) - Add date-fns with tree-shaking support (~3KB) - Create date adapter utility for smooth migration - Update all date components, - Update date helpers and utility functions - All existing tests pass - Bundle size reduction: ~65KB (26% improvement) Closes asyncapi#5014
📝 WalkthroughWalkthroughThe PR migrates the codebase from Moment.js to date-fns for improved performance and bundle size reduction. A new utility module introduces date helpers for formatting, comparison, and arithmetic operations. Moment imports are removed from components, pages, and scripts, replaced with corresponding date-fns-based helpers. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Deploy Preview for asyncapi-website ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
⚡️ Lighthouse report for the changes in this PR:
Lighthouse ran on https://deploy-preview-5019--asyncapi-website.netlify.app/ |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
components/navigation/EventFilter.tsx (1)
26-53: Remove unusedformatDateimport and movecurrentDateinside the effect to prevent unnecessary re-runs.
new Date()creates a new object each render. IncludingcurrentDatein the dependency array causes the effect to run on every render, which can create a render loop viasetData. Move it inside the effect and remove it from dependencies. Also remove the unusedformatDateimport.🐛 Proposed fix
-import { formatDate, isDateAfter, isDateBefore } from '@/utils/dateHelpers'; +import { isDateAfter, isDateBefore } from '@/utils/dateHelpers'; const currentDate = new Date(); const filterList: string[] = ['All', 'Upcoming', 'Recorded']; const [active, setActive] = useState<string>('All'); useEffect(() => { + const currentDate = new Date(); switch (active) { case ActiveState.All: setData(getEvents(data)); @@ - }, [active, data, setData, currentDate]); + }, [active, data, setData]);components/navigation/EventPostItem.tsx (1)
28-57: Guard against invalid dates — parseISO won’t throw, but format will.
parseDatereturns an Invalid Date for non‑ISO input; the try/catch won’t catch that andformatDatecan throw at render time. Add a validity check (orisValid) before settingactive=true.🐛 Proposed fix
- let postDate: Date = new Date(); - - try { - postDate = parseDate(post.date); - if (isDateBefore(postDate, currentDate)) { - active = false; - } - } catch { - active = false; - } + let postDate: Date = new Date(); + try { + postDate = parseDate(post.date); + if (Number.isNaN(postDate.getTime()) || isDateBefore(postDate, currentDate)) { + active = false; + } + } catch { + active = false; + }Also applies to: 84-84
🤖 Fix all issues with AI agents
In `@components/Calendar.tsx`:
- Around line 49-55: Prettier CI failed due to formatting in the Calendar
component around the JSX that renders event date and title; run Prettier (or
your project's formatter) on the Calendar.tsx block containing the JSX with
formatDate(event.date, 'd') and formatDateWithTimezone(event.date) so
spacing/indentation and line breaks match project rules (adjust the
span/div/h2/p indentation and wrap attributes consistently), then re-stage the
changes so CI passes.
In `@components/layout/BlogLayout.tsx`:
- Line 9: The formatDate helper currently uses parseISO and can produce an
Invalid Date for non-ISO inputs; update formatDate to catch parse errors and
fall back to native Date parsing, then verify validity with isValid before
formatting: in the formatDate function (and any duplicate at line ~74), try
parsing with parseISO for strings but catch exceptions and assign new Date(date)
as a fallback, then return format(parsedDate, formatStr) only if
isValid(parsedDate), otherwise return a safe placeholder like 'Invalid date' to
avoid broken rendered output and invalid dateTime attributes.
In `@components/navigation/BlogPostItem.tsx`:
- Around line 1-8: The import order in BlogPostItem.tsx fails CI; reorder
imports (or run the repo's import-sorting autofix) so external packages come
first (react, next, react-text-truncate), then type imports, then local project
imports—ensuring Link, React/forwardRef, TextTruncate are grouped before
BlogPostType, formatDate, and IBlogPost; run the project's autofix (e.g.,
yarn/npm script or eslint --fix) after reordering to satisfy the linter.
In `@components/navigation/EventFilter.tsx`:
- Line 4: Remove the unused import symbol formatDate from the import statement
in EventFilter.tsx; update the import to only include the used helpers
(isDateAfter, isDateBefore) so the line reads an import of those two functions,
and run lint to confirm the unused-import error is resolved (target the import
that currently reads import { formatDate, isDateAfter, isDateBefore } from
'@/utils/dateHelpers';).
In `@components/navigation/EventPostItem.tsx`:
- Line 51: Remove the trailing whitespace reported by Prettier in the
EventPostItem component file; open components/navigation/EventPostItem.tsx,
locate the EventPostItem component (around the area flagged) and delete any
extra spaces at the end of the line(s) (e.g., line ~51) so the file no longer
contains trailing spaces and passes formatting checks.
In `@components/newsroom/FeaturedBlogPost.tsx`:
- Around line 1-7: The import order in FeaturedBlogPost.tsx is failing CI; run
the project's import-sorting autofix (e.g., eslint --fix or the configured
import sorter) or manually reorder imports so external modules (react,
next/link, react-text-truncate) come first, then a blank line, then local
project imports (formatDate, BlogPostType, IBlogPost) and ensure
alphabetical/group ordering matches the repo lint rules; adjust the import
statements for Link, React, TextTruncate, formatDate, BlogPostType, and
IBlogPost accordingly and re-run lint.
In `@pages/community/index.tsx`:
- Around line 134-136: Prettier CI failed due to JSX formatting around the span
that renders {formatDateWithTimezone(event.date)}; re-run Prettier (or your
editor formatter) and update the JSX so it matches the project's Prettier
rules—ensure the span with className 'text-xs text-gray-500 md:text-sm' and the
{formatDateWithTimezone(event.date)} expression are formatted according to the
formatter (no extra spaces/line breaks), then save and commit the reformatted
pages/community/index.tsx changes.
In `@utils/dateHelpers.ts`:
- Around line 1-47: Validate parsed dates with date-fns isValid before using
format, isAfter, isBefore, or difference* to avoid RangeError on Invalid Date:
import isValid from 'date-fns' and in each function (formatDate, formatDateTime,
formatDateWithTimezone, isDateAfter, isDateBefore, getDaysDifference,
getHoursDifference, getMinutesDifference, parseDate) parse the input the same
way you already do, check if isValid(parsedDate) and if not return a safe
fallback (e.g., for format* functions return an empty string, for
isDateAfter/isDateBefore return false, for get*Difference return NaN or 0 per
app expectations, and for parseDate either throw a clear error or return new
Date(NaN) consistently); ensure formatDateWithTimezone also guards before
calling format/XXX.
| import type { IPosts } from '@/types/post'; | ||
|
|
||
| import BlogContext from '../../context/BlogContext'; | ||
| import { formatDate } from '../../utils/dateHelpers'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check frontmatter date fields in markdown files
fd -e md -e mdx | xargs rg -n '^date:\s*' -A 0 || trueRepository: asyncapi/website
Length of output: 12099
🏁 Script executed:
# Find and examine the formatDate implementation
fd -e ts -e tsx -e js -e jsx | xargs rg -l 'formatDate|parseISO' | head -20Repository: asyncapi/website
Length of output: 321
🏁 Script executed:
# Get context around line 74 in BlogLayout.tsx
fd -e tsx | xargs grep -l 'BlogLayout' | head -1 | xargs sed -n '70,80p'Repository: asyncapi/website
Length of output: 543
🏁 Script executed:
# Check dateHelpers implementation
fd -e ts -e tsx -e js -e jsx -path '*/utils/*' | xargs grep -l 'formatDate\|parseISO' || trueRepository: asyncapi/website
Length of output: 228
🏁 Script executed:
# Read dateHelpers.ts implementation
fd -name 'dateHelpers.ts' -o -name 'dateHelpers.js' | xargs catRepository: asyncapi/website
Length of output: 290
🏁 Script executed:
# Check how blog posts are loaded/parsed
fd -name '*blog*' -type f | xargs rg -l 'getAllPosts\|getBlogPosts\|frontmatter\|gray-matter' | head -5Repository: asyncapi/website
Length of output: 290
🏁 Script executed:
# Search for blog data loading in pages or API routes
fd -name 'index.tsx' -o -name 'index.ts' | xargs rg -l 'blog\|post' | head -5Repository: asyncapi/website
Length of output: 290
🏁 Script executed:
# Find and read dateHelpers.ts
find . -name 'dateHelpers.ts' -o -name 'dateHelpers.js' | head -1 | xargs catRepository: asyncapi/website
Length of output: 2086
🏁 Script executed:
# Search for blog data loading utilities
find . -type f -name '*.ts' -o -name '*.tsx' | xargs grep -l 'getAllPosts\|getBlogPosts' 2>/dev/null | head -5Repository: asyncapi/website
Length of output: 234
🏁 Script executed:
# Check BlogLayout context around line 74 and 9
find . -name 'BlogLayout.tsx' | xargs catRepository: asyncapi/website
Length of output: 3720
🏁 Script executed:
# Find where blog posts are loaded/parsed
find . -type f \( -name '*.ts' -o -name '*.tsx' \) | xargs grep -l 'post.date\|getPosts\|getAllPosts' 2>/dev/null | head -10Repository: asyncapi/website
Length of output: 410
🏁 Script executed:
# Check for blog data transformation/frontmatter parsing
find . -type f \( -name '*.ts' -o -name '*.tsx' \) | xargs grep -l 'frontmatter\|gray-matter\|parseISO' 2>/dev/null | head -10Repository: asyncapi/website
Length of output: 188
🏁 Script executed:
# Look for the types definition to understand what post.date is
find . -type f -name 'post.ts' -o -name 'post.d.ts' -o -name '*.ts' | xargs grep -l 'interface IPosts\|type IPosts' 2>/dev/null | head -5Repository: asyncapi/website
Length of output: 75
🏁 Script executed:
# Read the post types definition
cat ./types/post.tsRepository: asyncapi/website
Length of output: 621
🏁 Script executed:
# Read build-post-list.ts to see date processing
cat ./scripts/build-post-list.tsRepository: asyncapi/website
Length of output: 13127
🏁 Script executed:
# Check utils/api.ts for date handling
cat ./utils/api.tsRepository: asyncapi/website
Length of output: 1359
Add error handling for date parsing in formatDate.
parseISO from date-fns will fail on non-ISO dates and return Invalid Date, which breaks both the rendered date display and the dateTime attribute. While most blog dates are ISO-8601 compliant, malformed dates with missing leading zeros (e.g., 7:26:58 instead of 07:26:58) have been found in the frontmatter and will cause rendering issues. Add a fallback to gracefully handle parsing failures:
export function formatDate(date: string | Date, formatStr: string): string {
let parsedDate: Date;
try {
parsedDate = typeof date === 'string' ? parseISO(date) : date;
} catch (e) {
parsedDate = new Date(date); // fallback to native Date parsing
}
return isValid(parsedDate) ? format(parsedDate, formatStr) : 'Invalid date';
}Also applies to: 74-74
🤖 Prompt for AI Agents
In `@components/layout/BlogLayout.tsx` at line 9, The formatDate helper currently
uses parseISO and can produce an Invalid Date for non-ISO inputs; update
formatDate to catch parse errors and fall back to native Date parsing, then
verify validity with isValid before formatting: in the formatDate function (and
any duplicate at line ~74), try parsing with parseISO for strings but catch
exceptions and assign new Date(date) as a fallback, then return
format(parsedDate, formatStr) only if isValid(parsedDate), otherwise return a
safe placeholder like 'Invalid date' to avoid broken rendered output and invalid
dateTime attributes.
| import Link from 'next/link'; | ||
| import type { Ref } from 'react'; | ||
| import React, { forwardRef } from 'react'; | ||
| import TextTruncate from 'react-text-truncate'; | ||
|
|
||
| import { BlogPostType } from '@/types/components/navigation/BlogPostType'; | ||
| import { formatDate } from '@/utils/dateHelpers'; | ||
| import type { IBlogPost } from '@/types/post'; |
There was a problem hiding this comment.
Import order is failing CI.
The pipeline reports “Run autofix to sort these imports!”. Please run the repo’s import‑sorting autofix or reorder imports to satisfy lint.
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project
[error] 1-1: Run autofix to sort these imports!
🤖 Prompt for AI Agents
In `@components/navigation/BlogPostItem.tsx` around lines 1 - 8, The import order
in BlogPostItem.tsx fails CI; reorder imports (or run the repo's import-sorting
autofix) so external packages come first (react, next, react-text-truncate),
then type imports, then local project imports—ensuring Link, React/forwardRef,
TextTruncate are grouped before BlogPostType, formatDate, and IBlogPost; run the
project's autofix (e.g., yarn/npm script or eslint --fix) after reordering to
satisfy the linter.
- Add isValid() validation to dateHelpers.ts - Fix import order in multiple components - Remove unused imports - Fix Prettier formatting - Revert unrelated config/tools.json changes - Address CodeRabbit review comments
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #5019 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 22 22
Lines 796 796
Branches 146 146
=========================================
Hits 796 796 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Please close you PR , author has already shown interest in solving the issue. |
|
Thanks for the PR but I have merged another PR from the issue author |
This PR migrates the project from moment.js to date-fns, resulting in significant bundle size reduction and improved performance.
Changes:
Removed moment.js dependency (67.8KB minified)
Added date-fns with tree-shaking support (~3KB for used functions)
Created centralized date utility helper (dateHelpers.ts) for consistent date operations
Updated 11 components and utility files to use date-fns:
Calendar.tsx
BlogLayout.tsx
FeaturedBlogPost.tsx
BlogPostItem.tsx
EventFilter.tsx
EventPostItem.tsx
AnnouncementRemainingDays.tsx
index.tsx
staticHelpers.ts
compose.ts
All date formatting, parsing, and comparison logic preserved
No breaking changes to existing functionality
Benefits:
Bundle size reduction: ~65KB (significant improvement in page load performance)
Better tree-shaking support with date-fns
Modern, actively maintained library
Immutable date operations by default
Improved code maintainability with centralized date utilities
Testing:
All existing functionality verified
Date formatting outputs match previous behavior
Event filtering and sorting work correctly
Blog post dates display properly
Related issue(s)
Closes #5014
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.