Skip to content

Commit

Permalink
Improve landing performance (#858)
Browse files Browse the repository at this point in the history
This PR:
- makes sure to only use one H1 tag on the page
- shrinks the hero image from `371 KB` to `77.8 KB` and sets the `width`
and `height` attributes to prevent layout shift
- compresses videos used on landing by `50%`
- lazy loads videos using intersection observer – videos will only be
loaded when in view
- during video loading a lightweight placeholder is shown to prevent
layout shifts
- this is important because we used to load 10MB of video on page load
even for users which never scrolled down the page
  
 See before:
<img width="387" alt="image"
src="https://github.com/user-attachments/assets/34fad20d-6cdd-452f-9dbf-78a3e354867f"
/>
  • Loading branch information
kacperkapusciak authored Dec 16, 2024
1 parent dbf16c3 commit 7d0607f
Show file tree
Hide file tree
Showing 26 changed files with 53 additions and 15 deletions.
3 changes: 2 additions & 1 deletion packages/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"motion": "^11.11.17",
"prism-react-renderer": "^1.3.5",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"react-intersection-observer": "^9.14.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.4.3",
Expand Down
9 changes: 8 additions & 1 deletion packages/docs/src/components/Hero/StartScreen/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@ const StartScreen = () => {
animate={{ x: 0 }}
transition={{ duration: 0.5 }}>
<div className={styles.heroImageWrapper}>
<img className={styles.heroImage} src={useBaseUrl("/img/hero.png")} draggable={false} />
<img
className={styles.heroImage}
src={useBaseUrl("/img/hero.webp")}
alt="Radon IDE in action"
width={1678}
height={1025}
draggable={false}
/>
</div>
</motion.div>
<div className={styles.heading}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
width: 100%;
height: auto;
margin-bottom: -10px;
background-color: #232736;
}

.logo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,45 @@ import React from "react";
import styles from "./styles.module.css";
import { track } from "@vercel/analytics";
import LinkButton from "@site/src/components/LinkButton";
import { InView } from "react-intersection-observer";

interface Props {
label: string;
title: string;
body: string;
mediaSrc?: string;
placeholderSrc?: string;
}

const OverviewItem = ({ label, title, body, mediaSrc }: Props) => {
const OverviewItem = ({ label, title, body, mediaSrc, placeholderSrc }: Props) => {
const handleButtonClick = () => {
track("Overview CTA", { section: label });
};
return (
<>
<section className={styles.description}>
<p className={styles.itemLabel}>{label}</p>
<h2 className={styles.itemTitle}>{title}</h2>
<h3 className={styles.itemTitle}>{title}</h3>
<p className={styles.itemBody}>{body}</p>
<LinkButton
title="Get started for free"
href="https://marketplace.visualstudio.com/items?itemName=swmansion.react-native-ide"
onClick={handleButtonClick}
/>
</section>
<div className={styles.media}>
<video autoPlay loop muted playsInline>
<source src={mediaSrc} type="video/mp4" />
</video>
</div>
<InView triggerOnce>
{({ inView, ref }) => (
<div className={styles.media} ref={ref}>
{inView ? (
<video autoPlay loop muted playsInline poster={placeholderSrc}>
<source src={mediaSrc} type="video/mp4" />
</video>
) : (
<img src={placeholderSrc} alt={title} fetchPriority="high" />
)}
</div>
)}
</InView>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
justify-content: center;
}

.media video {
.media video,
.media img {
width: 100%;
border-style: solid;
}
Expand Down Expand Up @@ -43,13 +44,15 @@
.itemTitle {
font-size: 24px;
}
.media video {
.media video,
.media img {
border-width: 1.5rem !important;
}
}

@media (max-width: 430px) {
.media video {
.media video,
.media img {
border-width: 10px !important;
}
.itemTitle {
Expand Down
11 changes: 10 additions & 1 deletion packages/docs/src/components/Sections/Overview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,56 @@ const items = [
title: "Integrated experience",
body: "See the preview of your application right where you need it the most – close to your codebase. \n\nRadon IDE runs IOS Simulator and Android emulator directly in your Visual Studio Code and Cursor project.",
mediaSrc: "video/1_sztudio_integrated.mp4",
placeholderSrc: "video/placeholders/1_sztudio_integrated_placeholder.webp",
},
{
label: "Element Inspector",
title: "Click to inspect",
body: "Using the built-in inspector you can jump directly from preview to a file where your component is defined. It can't really get simpler than that.",
mediaSrc: "video/2_sztudio_inspect.mp4",
placeholderSrc: "video/placeholders/2_sztudio_inspect_placeholder.webp",
},
{
label: "Debugger",
title: "Use breakpoints right in VSCode",
body: "Without any additional setup the extension allows to add a breakpoints in Visual Studio Code to debug your React Native application. It. Just. Works.\n\nIDE also automatically stops at runtime exceptions showing you the exact line of code where they happened.",
mediaSrc: "video/3_sztudio_debugger.mp4",
placeholderSrc: "video/placeholders/3_sztudio_debugger_placeholder.webp",
},
{
label: "Router integration",
title: "Navigation made easier",
body: "The Radon IDE integrates tightly with your deep-linked application allowing you to jump around the navigation structure (supports both React Navigation and Expo Router projects).",
mediaSrc: "video/4_sztudio_url_bar.mp4",
placeholderSrc: "video/placeholders/4_sztudio_url_bar_placeholder.webp",
},
{
label: "Logs",
title: "Search through the logs easily",
body: "Radon IDE uses the built-in VSCode console allowing you to filter through the logs.\n\nThe links displayed in the console are automatically linking back to your source code.",
mediaSrc: "video/5_sztudio_logs_panel.mp4",
placeholderSrc: "video/placeholders/5_sztudio_logs_panel_placeholder.webp",
},
{
label: "Previews",
title: "Develop components in isolation",
body: "Radon IDE comes with a package allowing to preview components in full isolation.\n\nDevelop your components individually without distractions.",
mediaSrc: "video/6_sztudio_preview.mp4",
placeholderSrc: "video/placeholders/6_sztudio_preview_placeholder.webp",
},
{
label: "Device settings",
title: "Adjust device settings on the fly",
body: "You can adjust text size and light/dark mode right from the Radon IDE.\n\nFocus just on your app without switching between windows.",
mediaSrc: "video/7_sztudio_device_settings.mp4",
placeholderSrc: "video/placeholders/7_sztudio_device_settings_placeholder.webp",
},
{
label: "Screen recording",
title: "Instant replays",
body: "Missed a bug? At any time you can re-watch what just happened on the device.\n\nNo need to manually start the recording ever again.",
mediaSrc: "video/ide_screen_recording.mp4",
placeholderSrc: "video/placeholders/ide_screen_recording_placeholder.webp",
},
];

Expand All @@ -62,7 +70,7 @@ const Overview = () => {
<Elipse isSmall className={styles.elipse} />
</div>
<div className={styles.overview}>
<h1 className={styles.overviewHeading}>How it works?</h1>
<h2 className={styles.overviewHeading}>How it works?</h2>
<div className={styles.overviewItemsContainer}>
{items.map((item, idx) => (
<div key={idx} className={styles.item}>
Expand All @@ -71,6 +79,7 @@ const Overview = () => {
title={item.title}
body={item.body}
mediaSrc={item.mediaSrc}
placeholderSrc={item.placeholderSrc}
/>
</div>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
flex-direction: column;
}

.item:nth-of-type(2n) video {
.item:nth-of-type(2n) video,
.item:nth-of-type(2n) img {
border-color: var(--swm-green-light-60);
border-width: 1.5rem;
}

.item:nth-of-type(2n + 1) video {
.item:nth-of-type(2n + 1) video,
.item:nth-of-type(2n + 1) img {
border-color: var(--swm-navy-light-20);
border-width: 2.75rem 2.5rem;
}
Expand Down
Binary file removed packages/docs/static/img/hero.png
Binary file not shown.
Binary file added packages/docs/static/img/hero.webp
Binary file not shown.
Binary file modified packages/docs/static/video/1_sztudio_integrated.mp4
Binary file not shown.
Binary file modified packages/docs/static/video/2_sztudio_inspect.mp4
Binary file not shown.
Binary file modified packages/docs/static/video/3_sztudio_debugger.mp4
Binary file not shown.
Binary file modified packages/docs/static/video/4_sztudio_url_bar.mp4
Binary file not shown.
Binary file modified packages/docs/static/video/5_sztudio_logs_panel.mp4
Binary file not shown.
Binary file modified packages/docs/static/video/6_sztudio_preview.mp4
Binary file not shown.
Binary file modified packages/docs/static/video/7_sztudio_device_settings.mp4
Binary file not shown.
Binary file modified packages/docs/static/video/ide_screen_recording.mp4
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
5 changes: 5 additions & 0 deletions packages/docs/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6656,6 +6656,11 @@ react-helmet-async@^1.3.0:
react-fast-compare "^3.2.0"
shallowequal "^1.1.0"

react-intersection-observer@^9.14.0:
version "9.14.0"
resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.14.0.tgz#37bf6fbfbbb03bae55db50dfae79118b29b180d8"
integrity sha512-AYqlmDZn85VUmlODwYym9y5OlqY2cFyIu41dkN0GJWvhdbd19Mh16mz5IH6fO1gp5V4FfQOO4m0zGc04Tj13rQ==

react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
Expand Down

0 comments on commit 7d0607f

Please sign in to comment.