diff --git a/website/theme/components/HomeFooter/index.tsx b/website/theme/components/HomeFooter/index.tsx
index 1a21451e8c75..8a9cfeacd97f 100644
--- a/website/theme/components/HomeFooter/index.tsx
+++ b/website/theme/components/HomeFooter/index.tsx
@@ -1,3 +1,4 @@
+import { memo } from 'react';
import { useLang } from 'rspress/runtime';
import { Link } from 'rspress/theme';
import { useI18n } from '../../i18n/index';
@@ -96,7 +97,7 @@ function useFooterData() {
];
}
-export function HomeFooter() {
+export const HomeFooter = memo(() => {
const footerData = useFooterData();
return (
);
-}
+});
diff --git a/website/theme/components/Landingpage/Benchmark/index.tsx b/website/theme/components/Landingpage/Benchmark/index.tsx
index 3aa8e6bdfcc1..4d8b0bc3ad47 100644
--- a/website/theme/components/Landingpage/Benchmark/index.tsx
+++ b/website/theme/components/Landingpage/Benchmark/index.tsx
@@ -3,6 +3,7 @@ import {
type BenchmarkData,
} from './BaseBenchmark';
+import { memo } from 'react';
// TODO: extract to @rstack-dev/doc-ui/benchmark
// import {
// Benchmark as BaseBenchmark,
@@ -86,7 +87,7 @@ const BENCHMARK_DATA: BenchmarkData = {
},
};
-export function Benchmark() {
+export const Benchmark = memo(() => {
const t = useI18n();
return (
@@ -109,4 +110,4 @@ export function Benchmark() {
);
-}
+});
diff --git a/website/theme/components/Landingpage/BuiltWithRspack/index.tsx b/website/theme/components/Landingpage/BuiltWithRspack/index.tsx
index a14120780b17..a34c08591a91 100644
--- a/website/theme/components/Landingpage/BuiltWithRspack/index.tsx
+++ b/website/theme/components/Landingpage/BuiltWithRspack/index.tsx
@@ -1,3 +1,4 @@
+import { memo } from 'react';
import { Link } from 'rspress/theme';
import { useI18n } from '../../../i18n';
import sharedStyles from '../shared.module.scss';
@@ -71,7 +72,7 @@ const CompanyItem = ({ item }: { item: Company }) => {
);
};
-const BuiltWithRsPack: React.FC = () => {
+const BuiltWithRsPack: React.FC = memo(() => {
const t = useI18n();
return (
@@ -92,6 +93,6 @@ const BuiltWithRsPack: React.FC = () => {
);
-};
+});
export default BuiltWithRsPack;
diff --git a/website/theme/components/Landingpage/FullyFeatured/index.tsx b/website/theme/components/Landingpage/FullyFeatured/index.tsx
index b696e1316167..584c8c216ded 100644
--- a/website/theme/components/Landingpage/FullyFeatured/index.tsx
+++ b/website/theme/components/Landingpage/FullyFeatured/index.tsx
@@ -1,3 +1,4 @@
+import { memo } from 'react';
import { useNavigate } from 'rspress/runtime';
import { Link } from 'rspress/theme';
import { useI18n, useI18nUrl } from '../../../i18n';
@@ -23,7 +24,7 @@ type Feature = {
link: string;
};
-const FullyFeatured = () => {
+const FullyFeatured = memo(() => {
const t = useI18n();
const tUrl = useI18nUrl();
const navigate = useNavigate();
@@ -151,6 +152,6 @@ const FullyFeatured = () => {
);
-};
+});
export default FullyFeatured;
diff --git a/website/theme/components/Landingpage/Hero/index.tsx b/website/theme/components/Landingpage/Hero/index.tsx
index d0baf9801845..e8bd53bd2356 100644
--- a/website/theme/components/Landingpage/Hero/index.tsx
+++ b/website/theme/components/Landingpage/Hero/index.tsx
@@ -1,4 +1,4 @@
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useNavigate } from 'rspress/runtime';
import { useI18n, useI18nUrl } from '../../../i18n';
import BackgroundStar from './BackgroundStar';
@@ -55,7 +55,7 @@ const stars = positions.map(([top, left], i) => {
);
});
-const Hero = () => {
+const Hero = memo(() => {
const tUrl = useI18nUrl();
const t = useI18n();
@@ -101,6 +101,6 @@ const Hero = () => {
);
-};
+});
export default Hero;
diff --git a/website/theme/components/Landingpage/ToolStack/index.tsx b/website/theme/components/Landingpage/ToolStack/index.tsx
index 53f488cc5e85..84b9ae4fad4d 100644
--- a/website/theme/components/Landingpage/ToolStack/index.tsx
+++ b/website/theme/components/Landingpage/ToolStack/index.tsx
@@ -1,11 +1,12 @@
import type React from 'react';
+import { memo } from 'react';
import { useLang } from 'rspress/runtime';
import { Link } from 'rspress/theme';
import { useI18n } from '../../../i18n';
import sharedStyles from '../shared.module.scss';
import styles from './index.module.scss';
-const ToolStack: React.FC = () => {
+const ToolStack: React.FC = memo(() => {
const lang = useLang();
const t = useI18n();
const isEn = lang === 'en';
@@ -74,6 +75,6 @@ const ToolStack: React.FC = () => {
);
-};
+});
export default ToolStack;
diff --git a/website/theme/components/Landingpage/WhyRspack/index.tsx b/website/theme/components/Landingpage/WhyRspack/index.tsx
index a0eca5d07921..72e2fc29e70b 100644
--- a/website/theme/components/Landingpage/WhyRspack/index.tsx
+++ b/website/theme/components/Landingpage/WhyRspack/index.tsx
@@ -1,3 +1,4 @@
+import { memo } from 'react';
import { Link } from 'rspress/theme';
import { useI18n, useI18nUrl } from '../../../i18n';
import Compatible from './assets/Compatible.svg';
@@ -89,7 +90,8 @@ const WhyRspackCard = () => {
);
};
-const FeatureItem = ({ img, url, title, description }: Feature) => {
+const FeatureItem = memo(({ feature }: { feature: Feature }) => {
+ const { description, img, title, url } = feature;
const {
container,
onMouseEnter,
@@ -164,9 +166,9 @@ const FeatureItem = ({ img, url, title, description }: Feature) => {
);
-};
+});
-const WhyRspack = () => {
+const WhyRspack = memo(() => {
const t = useI18n();
const tUrl = useI18nUrl();
@@ -203,21 +205,13 @@ const WhyRspack = () => {
{/* Why Rspack? */}
- {features.map(({ img, url, title, description }) => {
- return (
-
- );
+ {features.map(feature => {
+ return ;
})}
);
-};
+});
export default WhyRspack;
diff --git a/website/theme/components/Landingpage/index.module.scss b/website/theme/components/Landingpage/index.module.scss
index 7475adf32d68..b48f61ef1dc7 100644
--- a/website/theme/components/Landingpage/index.module.scss
+++ b/website/theme/components/Landingpage/index.module.scss
@@ -3,12 +3,14 @@
}
.background {
+ width: 100%;
position: absolute;
top: calc(-1 * var(--rp-nav-height));
left: 0;
- width: 100%;
+
z-index: -1;
- pointer-events: none;
filter: blur(2px);
+
+ pointer-events: none;
user-select: none;
}
diff --git a/website/theme/components/Landingpage/index.tsx b/website/theme/components/Landingpage/index.tsx
index a5ecbe710e21..e1b28cd973fa 100644
--- a/website/theme/components/Landingpage/index.tsx
+++ b/website/theme/components/Landingpage/index.tsx
@@ -1,3 +1,4 @@
+import { useEffect, useState } from 'react';
import BackgroundUrl from './Background.compressed.png';
import { Benchmark } from './Benchmark';
import BuiltWithRspack from './BuiltWithRspack';
@@ -13,7 +14,38 @@ const Background = () => {
);
};
+const useTopArrived = () => {
+ const [scrollY, setScrollY] = useState(0);
+ const topArrived = scrollY < 100;
+
+ useEffect(() => {
+ const handleScroll = () => {
+ setScrollY(window.scrollY);
+ };
+ window.addEventListener('scroll', handleScroll, {
+ capture: false,
+ passive: true,
+ });
+ return () => {
+ window.removeEventListener('scroll', handleScroll);
+ };
+ }, []);
+
+ return {
+ topArrived,
+ };
+};
+
const LandingPage = () => {
+ const { topArrived } = useTopArrived();
+ useEffect(() => {
+ if (topArrived) {
+ document.body.classList.remove('notTopArrived');
+ } else {
+ document.body.classList.add('notTopArrived');
+ }
+ }, [topArrived]);
+
return (