-
-
Notifications
You must be signed in to change notification settings - Fork 581
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
462 additions
and
179 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
.next | ||
node_modules | ||
.env |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
export function Cursor({ | ||
color, | ||
x, | ||
y, | ||
}: { | ||
color: string; | ||
x: number; | ||
y: number; | ||
}) { | ||
return ( | ||
<svg | ||
style={{ | ||
position: 'absolute', | ||
left: 0, | ||
top: 0, | ||
transform: `translateX(${x}px) translateY(${y}px)`, | ||
zIndex: 1000, | ||
}} | ||
width="24" | ||
height="36" | ||
viewBox="0 0 24 36" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<path | ||
d="M5.65376 12.3673H5.46026L5.31717 12.4976L0.500002 16.8829L0.500002 1.19841L11.7841 12.3673H5.65376Z" | ||
fill={color} | ||
/> | ||
</svg> | ||
); | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import { useRouter } from 'next/router'; | ||
import { useEffect } from 'react'; | ||
import { | ||
RoomProvider, | ||
useOthers, | ||
useUpdateMyPresence, | ||
} from '../liveblocks.config'; | ||
import { Cursor } from './cursor'; | ||
|
||
const COLORS = [ | ||
'#E57373', | ||
'#9575CD', | ||
'#4FC3F7', | ||
'#81C784', | ||
'#FFF176', | ||
'#FF8A65', | ||
'#F06292', | ||
'#7986CB', | ||
]; | ||
|
||
function useLiveCursors() { | ||
const updateMyPresence = useUpdateMyPresence(); | ||
|
||
useEffect(() => { | ||
const scroll = { | ||
x: window.scrollX, | ||
y: window.scrollY, | ||
}; | ||
|
||
let lastPosition: { x: number; y: number } | null = null; | ||
|
||
function transformPosition(cursor: { x: number; y: number }) { | ||
return { | ||
x: cursor.x / window.innerWidth, | ||
y: cursor.y, | ||
}; | ||
} | ||
|
||
function onPointerMove(event: PointerEvent) { | ||
event.preventDefault(); | ||
const position = { | ||
x: event.pageX, | ||
y: event.pageY, | ||
}; | ||
lastPosition = position; | ||
updateMyPresence({ | ||
cursor: transformPosition(position), | ||
}); | ||
} | ||
|
||
function onPointerLeave() { | ||
lastPosition = null; | ||
updateMyPresence({ cursor: null }); | ||
} | ||
|
||
function onDocumentScroll() { | ||
if (lastPosition) { | ||
const offsetX = window.scrollX - scroll.x; | ||
const offsetY = window.scrollY - scroll.y; | ||
const position = { | ||
x: lastPosition.x + offsetX, | ||
y: lastPosition.y + offsetY, | ||
}; | ||
lastPosition = position; | ||
updateMyPresence({ | ||
cursor: transformPosition(position), | ||
}); | ||
} | ||
scroll.x = window.scrollX; | ||
scroll.y = window.scrollY; | ||
} | ||
|
||
document.addEventListener('scroll', onDocumentScroll); | ||
document.addEventListener('pointermove', onPointerMove); | ||
document.addEventListener('pointerleave', onPointerLeave); | ||
|
||
return () => { | ||
document.removeEventListener('scroll', onDocumentScroll); | ||
document.removeEventListener('pointermove', onPointerMove); | ||
document.removeEventListener('pointerleave', onPointerLeave); | ||
}; | ||
}, [updateMyPresence]); | ||
|
||
const others = useOthers(); | ||
|
||
const cursors: { | ||
x: number; | ||
y: number; | ||
connectionId: number; | ||
}[] = []; | ||
|
||
for (const { connectionId, presence } of others) { | ||
if (presence.cursor) { | ||
cursors.push({ | ||
x: presence.cursor.x * window.innerWidth, | ||
y: presence.cursor.y, | ||
connectionId, | ||
}); | ||
} | ||
} | ||
|
||
return cursors; | ||
} | ||
|
||
export function Cursors() { | ||
const cursors = useLiveCursors(); | ||
|
||
return cursors.map(({ x, y, connectionId }) => ( | ||
<Cursor | ||
key={connectionId} | ||
color={COLORS[connectionId % COLORS.length]} | ||
x={x} | ||
y={y} | ||
/> | ||
)); | ||
} | ||
|
||
export function getCount() { | ||
const others = useOthers(); | ||
return others.length; | ||
} | ||
|
||
export function LiveProvider({ children }) { | ||
const { pathname } = useRouter(); | ||
return ( | ||
<RoomProvider | ||
id={`million-${pathname}`} | ||
initialPresence={{ | ||
cursor: null, | ||
}} | ||
> | ||
{children} | ||
<Cursors /> | ||
</RoomProvider> | ||
); | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { createClient } from '@liveblocks/client'; | ||
import { createRoomContext } from '@liveblocks/react'; | ||
import type { JsonObject} from '@liveblocks/client'; | ||
|
||
const client = createClient({ | ||
throttle: 16, | ||
publicApiKey: process.env.NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEY!, | ||
}); | ||
interface Presence extends JsonObject { | ||
cursor: { x: number; y: number } | null; | ||
} | ||
|
||
export const { RoomProvider, useOthers, useMyPresence, useUpdateMyPresence } = | ||
createRoomContext<Presence>(client); |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,17 @@ | ||
import '../styles/global.css'; | ||
import { Analytics } from '@vercel/analytics/react'; | ||
import { Inter } from 'next/font/google'; | ||
import { LiveProvider } from '../components/live'; | ||
|
||
export const inter = Inter({ subsets: ['latin'] }); | ||
|
||
export default function App({ Component, pageProps }) { | ||
return ( | ||
<main className={inter.className}> | ||
<Component {...pageProps} /> | ||
<Analytics /> | ||
</main> | ||
<LiveProvider> | ||
<main className={inter.className}> | ||
<Component {...pageProps} /> | ||
<Analytics /> | ||
</main> | ||
</LiveProvider> | ||
); | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
--- | ||
title: 'Case Study: Wyze' | ||
date: OCT 19, 2023 | ||
description: How Million.js helped Wyze speed up the Web View product by 8x in less than a week. | ||
--- | ||
|
||
import Image from 'next/image'; | ||
|
||
<div className="flex justify-center mt-6"> | ||
<a href="https://wyze.com"> | ||
<Image src="/wyze-banner.png" width={500} height={130} /> | ||
</a> | ||
</div> | ||
|
||
<div className="flex flex-col items-center gap-4 text-center"> | ||
|
||
# Case Study: Wyze | ||
|
||
<p> | ||
How Million.js helped Wyze speed up the Web View product by 8x in less than a | ||
week. | ||
</p> | ||
|
||
<small>[AIDEN BAI](https://aidenybai.com) OCT 19 2023</small> | ||
</div> | ||
|
||
Introduction | ||
Wyze.com, a platform renowned for its smart home products, has always been on the lookout for cutting-edge technologies to enhance user interaction and engagement on its web view product. In its quest for a robust, performant, and user-friendly web view, Wyze.com collaborated with Million.js, a lightweight virtual DOM library. | ||
|
||
Challenges | ||
Wyze's web view product was facing challenges with rendering speed and efficiency which was impacting the user experience. The existing technology stack was not adept at handling high-frequency updates and rendering large lists of dynamic content. | ||
|
||
The primary challenge was to find a solution that could significantly enhance rendering performance without compromising on the usability and the existing features of the web view product. Moreover, the solution needed to be lightweight and easy to integrate with the existing technology stack. | ||
|
||
Requirements | ||
|
||
Boost rendering performance significantly. | ||
Ensure a lightweight solution to not burden the existing infrastructure. | ||
Easy integration with the existing technology stack. | ||
Maintain or enhance the current level of usability and features. | ||
Solution and Implementation | ||
Million.js emerged as a promising solution to Wyze.com's challenges. It's a lightweight virtual DOM library that provides high-performance rendering, making it a perfect match for the requirements. | ||
|
||
The implementation process kicked off with a thorough analysis and benchmarking to understand the performance gaps and set clear performance goals. The Wyze.com’s development team, along with the Million.js community, worked in tandem to devise a robust implementation plan. | ||
|
||
The integration of Million.js was smooth, and it was customized to align with the Wyze.com's web view product's architecture. The Million.js library was adept at handling high-frequency updates and rendering large lists of dynamic content efficiently. | ||
|
||
During the implementation, several performance optimization techniques were also employed to further boost the rendering speed. This included optimizing the existing codebase to take full advantage of Million.js's virtual DOM diffing and patching capabilities. | ||
|
||
Results | ||
The integration of Million.js significantly improved the rendering performance of Wyze.com’s web view product. The rendering times were reduced drastically which contributed to a smoother and more responsive user experience. | ||
|
||
Furthermore, the lightweight nature of Million.js ensured that the web view remained highly performant even under heavy loads, showcasing its capability to handle high-frequency updates efficiently. | ||
|
||
The collaboration with Million.js not only addressed the performance challenges but also laid a strong foundation for future enhancements. The success of this integration has spurred Wyze.com to explore further optimizations and additional features to continue enhancing the user experience. | ||
|
||
Conclusion | ||
The case study exemplifies how a focused and collaborative effort between Wyze.com and Million.js led to significant performance improvements. The integration of Million.js proved to be a decisive step towards achieving a superior, user-friendly, and performant web view product on Wyze.com. This collaboration underscores the potential of lightweight virtual DOM libraries like Million.js in addressing performance challenges and enhancing the user experience in web-based applications. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains 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
a723863
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
million-kitchen-sink – ./packages/kitchen-sink
million-kitchen-sink.vercel.app
million-kitchen-sink-git-main-millionjs.vercel.app
million-kitchen-sink-millionjs.vercel.app
a723863
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
sink – ./packages/kitchen-sink
sink-git-main-millionjs.vercel.app
sink.million.dev
sink-millionjs.vercel.app
million-kitchen-sink-atit.vercel.app