<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Constantine</title>
    <description>The latest articles on DEV Community by Constantine (@qostya).</description>
    <link>https://dev.to/qostya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1103674%2Fb7523449-5e44-4903-8c84-e61f82b08d2d.jpeg</url>
      <title>DEV Community: Constantine</title>
      <link>https://dev.to/qostya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/qostya"/>
    <language>en</language>
    <item>
      <title>Vivaldi Browser: Must-have extensions for developers</title>
      <dc:creator>Constantine</dc:creator>
      <pubDate>Sun, 14 Jul 2024 07:19:25 +0000</pubDate>
      <link>https://dev.to/qostya/vivaldi-browser-must-have-extensions-for-developers-30f4</link>
      <guid>https://dev.to/qostya/vivaldi-browser-must-have-extensions-for-developers-30f4</guid>
      <description>&lt;p&gt;Having the right tools can help a lot in web development. Vivaldi is flexible and customizable, which makes it a good choice for developers who want to work better.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Getting to know the Vivaldi browser: A developer's best friend&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Vivaldi is a simple and user-friendly browser with many features for developers. It has an easy interface and performs well, making it good for coding and testing websites. You can customize it to suit your needs, making it a valuable tool for web development.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why Vivaldi stands out for developers&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Vivaldi lets users customize a lot, setting it apart from other browsers. It has tools to manage tabs, take notes, and use web panels, helping developers stay organized and work well on different tasks. Also, Vivaldi cares about privacy and security, so developers can work without worrying about their data.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Productivity and workflow: Streamline your tasks for optimal efficiency&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Efficient task management is essential for maximizing productivity and workflow. Vivaldi provides a variety of extensions designed to streamline daily tasks and boost overall efficiency.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tab management made easy&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Having many tabs open can make your browser slow. These tools can help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/chphlpgkkbolifaimnlloiipkdnihall" rel="noopener noreferrer"&gt;OneTab&lt;/a&gt;&lt;/strong&gt;: Changes all your open tabs into a simple list, making your computer run better.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/iohcojnlgnfbmjfjfkbhahhmppcggdog" rel="noopener noreferrer"&gt;Eversync&lt;/a&gt;&lt;/strong&gt;: Syncs your bookmarks and tabs on different devices, making them accessible anywhere.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://maxfoc.us/" rel="noopener noreferrer"&gt;MaxFocus: Link Preview&lt;/a&gt;&lt;/strong&gt;: Shows previews of links so you can look at pages without opening new tabs, keeping your browser clean.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccjvs8ktwon6x5sp46hf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccjvs8ktwon6x5sp46hf.png" alt="MaxFocus: Link Preview extension in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Time management tools for enhanced productivity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Managing your time well is important to stay focused and get things done. Here are some extensions to help you manage your time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/laankejkbhbdhmipfmgcngdelahlfoji" rel="noopener noreferrer"&gt;StayFocusd&lt;/a&gt;&lt;/strong&gt; blocks websites that waste your time. You can block everything except allowed sites, helping you stay focused. It also has a "Nuclear Mode" for instant blocking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/bdakmnplckeopfghnlpocafcepegjeap" rel="noopener noreferrer"&gt;RescueTime&lt;/a&gt;&lt;/strong&gt; tracks your time spent on websites and apps. It shows you your habits so you can make better choices and be more productive.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By incorporating these productivity and time management extensions into your Vivaldi browser, you can optimize your workflow, stay organized, and boost your productivity levels to achieve your development goals efficiently.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Coding and development tools: Enhance your coding experience&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In coding, the right tools help you work better. Vivaldi is a simple, customizable browser. It has many useful extensions for developers. Adding these tools to Vivaldi makes coding easier and helps you work more efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Code editors and viewers: Simplify your coding tasks&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You need tools to help write and fix your code when you code. Vivaldi has helpful add-ons for this. These add-ons make writing and fixing code easier. They help you quickly find and fix errors. Adding these tools to your Vivaldi browser makes your coding work smoother and better.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/bfbameneiokkgbdmiekhjnmfkcnldhhm" rel="noopener noreferrer"&gt;Web Developer&lt;/a&gt;&lt;/strong&gt;: Adds a button to your browser and gives you many web development tools. You can inspect elements, debug JavaScript, and manage CSS styles anywhere. It makes changing and testing your web pages more accessible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/eifflpmocdbdmepbjaopkkhbfmdgijcc" rel="noopener noreferrer"&gt;JSON Viewer Pro&lt;/a&gt;&lt;/strong&gt;: Helps with working on JSON data. It shows JSON data clearly. You can expand and collapse parts to see the structure better. This helps you find and fix errors more easily.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools make your coding more efficient and correct, allowing you to focus more on creating robust and good code.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Debugging and testing: Ensure code quality and functionality&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Debugging and testing are essential steps in making sure your code works everywhere. Vivaldi has tools to help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/aicmkgpgakddgnaphhhpliifpcfhicfo" rel="noopener noreferrer"&gt;Postman Interceptor&lt;/a&gt;&lt;/strong&gt;: Helps test and document APIs quickly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/blipmdconlkpinefehnmjammfjpmpbjk" rel="noopener noreferrer"&gt;Lighthouse&lt;/a&gt;&lt;/strong&gt;: A Google tool that makes web pages faster and better by giving tips after running tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/gppongmhjkpfnbhagpmjfkannfbllamg" rel="noopener noreferrer"&gt;Wappalyzer&lt;/a&gt;&lt;/strong&gt;: Shows what technologies websites use, making debugging easier.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools help you find and fix problems early, ensuring your code works well.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Version control and collaboration: streamline development processes and teamwork&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In version control and teamwork, good tools make development more accessible and help the team work well together. Vivaldi has add-ons that improve version control and help the team work smoothly. This keeps projects on track and makes sure everyone understands each other.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Git integration for Seamless Code Management&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When managing code, Git integration is handy. Vivaldi has extensions to help with this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/bkhaagjahfmjljalopjnoealnfndnagc" rel="noopener noreferrer"&gt;Octotree&lt;/a&gt;&lt;/strong&gt;: This tool shows a code tree for GitHub projects. It makes it easy to move through big codebases and find files. Octotree simplifies reading and reviewing code, which is good for developers working on big projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/dodmmooeoklaejobgleioelladacbeki" rel="noopener noreferrer"&gt;Gitpod&lt;/a&gt;&lt;/strong&gt;: This tool is for GitHub users and lets developers work on code in the browser. It removes the need to set up complex environments and has features like code editing and sharing. Gitpod helps developers work well together and improve the quality of their code. It makes teamwork smoother and boosts productivity.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Design and UI/UX tools: Elevate your design experience&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In design and user experience, the right tools can make your projects look and work better. Vivaldi is flexible and easy to use, which makes it great for designers and UI/UX professionals. It has many extensions that help these users. Adding these tools to your Vivaldi browser can make your design work easier and boost your creativity.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Color and font pickers: Enhance your visual palette&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Picking the right colors and fonts is important for making good designs. Vivaldi has some extensions to help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/bhlhnicpbhignbdhedgjhgdocnmhomnp" rel="noopener noreferrer"&gt;ColorZilla&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A color picker and gradient tool.&lt;/li&gt;
&lt;li&gt;  Helps you choose and use colors easily.&lt;/li&gt;
&lt;li&gt;  Creates good color schemes and gradients.&lt;/li&gt;
&lt;li&gt;  Lets you adjust your project's color choices.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/jabopobgcpjmedljpbcaablpmlmfcogm" rel="noopener noreferrer"&gt;WhatFont&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Finds fonts used on any webpage with one click.&lt;/li&gt;
&lt;li&gt;  Helps keep your design consistent.&lt;/li&gt;
&lt;li&gt;  Makes sure fonts match your brand and design goals.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;These tools make the design process easier. ColorZilla helps you select the best colors for your project. WhatFont lets you find fonts quickly, helping keep your design consistent. Adding these extensions to Vivaldi can improve your design work and make you more efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Design Inspiration and prototyping: Bring your ideas to life&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When you need ideas and tools for designs, these Vivaldi extensions can help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/imjkkofdknonmlapjelmafbikikbegbi" rel="noopener noreferrer"&gt;Designer Daily Report&lt;/a&gt;&lt;/strong&gt;: Gives you design tips and daily ideas. Keeps you updated on new trends.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/glcipcfhmopcgidicgdociohdoicpdfc" rel="noopener noreferrer"&gt;Muzli&lt;/a&gt;&lt;/strong&gt;: Shows daily design trends and examples. Keeps your ideas fresh.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/haafibkemckmbknhfkiiniobjpgkebko" rel="noopener noreferrer"&gt;Panda&lt;/a&gt;&lt;/strong&gt;: Brings top ideas from several sites like Product Hunt and Dribbble. It keeps you updated without needing to visit many sites.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These Vivaldi tools can help you get ideas and complete your designs.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Security and privacy: Safeguard your online presence&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Cybersecurity threats are constantly changing, so it is important to protect your private information. Vivaldi offers extensions to keep your online activities safe and private.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Password management: Securely store and manage your credentials&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Good password management is crucial for protecting your accounts and sensitive information. Vivaldi offers great password management tools like LastPass and Bitwarden to help you securely store and auto-fill your passwords.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/hdokiejnpimakedhajhdlcegeplioahd" rel="noopener noreferrer"&gt;LastPass&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Keeps your passwords and private information safe.&lt;/li&gt;
&lt;li&gt;  Gives you easy access to your passwords with strong encryption.&lt;/li&gt;
&lt;li&gt;  Auto-fills passwords to save time.&lt;/li&gt;
&lt;li&gt;  Lets you access your saved passwords easily.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/nngceckbapebfimnlniiiahkandclblb" rel="noopener noreferrer"&gt;Bitwarden&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  An open-source password manager.&lt;/li&gt;
&lt;li&gt;  Provides a secure place for storing and using passwords on different devices.&lt;/li&gt;
&lt;li&gt;  Keeps your private information safe.&lt;/li&gt;
&lt;li&gt;  Allows sharing of passwords with trusted people.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Using these tools helps protect your data and makes managing passwords simpler.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Privacy enhancements: Shield yourself from online threats&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Protecting your browsing privacy is important to stop unwanted tracking and data collection. Vivaldi has privacy tools like uBlock Origin and HTTPS Everywhere that help protect you online.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/ddkjiahejlhfcafbddmgiahcphecmpfh" rel="noopener noreferrer"&gt;uBlock Origin Lite&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Blocks ads and trackers.&lt;/li&gt;
&lt;li&gt;  Makes browsing cleaner and faster.&lt;/li&gt;
&lt;li&gt;  Keeps your privacy by stopping tracking.&lt;/li&gt;
&lt;li&gt;  Saves data by blocking unwanted content.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://maxfoc.us/" rel="noopener noreferrer"&gt;MaxFocus: Link Preview&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Lets you &lt;a href="https://maxfoc.us/blog/how-to-open/" rel="noopener noreferrer"&gt;preview links&lt;/a&gt; without opening new tabs.&lt;/li&gt;
&lt;li&gt;  Warns you if a previewed website is malicious.&lt;/li&gt;
&lt;li&gt;  Removes tracking from previewed URLs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Using these tools, you can browse with more privacy and security, keeping your data safe from threats.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Browser extensions for specialized development needs&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Besides the usual tools, some extensions meet specific development needs. These tools support different parts of web development.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Accessibility tools: Make the web accessible&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Making websites usable for everyone, including those with disabilities, is crucial. These tools help check and ensure your site meets accessibility standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/lhdoppojpmngadmnindnejefpokejbdd" rel="noopener noreferrer"&gt;axe DevTools - Web Accessibility Testing&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Checks websites for accessibility issues.&lt;/li&gt;
&lt;li&gt;  Gives detailed reports and fixes.&lt;/li&gt;
&lt;li&gt;  Ensures you meet accessibility standards.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/jbbplnpkjmmeebjpijfedlgcdilocofh" rel="noopener noreferrer"&gt;WAVE Evaluation Tool&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Provides visual feedback on web content accessibility.&lt;/li&gt;
&lt;li&gt;  Identifies and shows accessibility errors.&lt;/li&gt;
&lt;li&gt;  Helps improve the user experience for all visitors.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Using these tools ensures your site is user-friendly for everyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  SEO Tools: Enhance Search Engine Performance
&lt;/h3&gt;

&lt;p&gt;To make your sites easy to find, use these SEO extensions for search engines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/akdgnmcogleenhbclghghlkkdndkjdjc" rel="noopener noreferrer"&gt;SEOquake&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Analyzes SEO metrics for webpages.&lt;/li&gt;
&lt;li&gt;  Provides insights on keyword density, links, and more.&lt;/li&gt;
&lt;li&gt;  Helps improve search engine rankings.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/nljcdkjpjnhlilgepggmmagnmebhadnk" rel="noopener noreferrer"&gt;Website SEO Checker&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Offers instant SEO checks.&lt;/li&gt;
&lt;li&gt;  Reviews meta tags and keywords.&lt;/li&gt;
&lt;li&gt;  Helps boost your site's SEO.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Using these tools in Vivaldi helps optimize your sites for search engines, drawing more visitors to your projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;API Development: Simplify API Workflows&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For developers working with APIs, these tools ease testing and documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/biemppheiopfggogojnfpkngdkchelik" rel="noopener noreferrer"&gt;Swagger Inspector&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Tests REST APIs.&lt;/li&gt;
&lt;li&gt;  Provides a simple interface for API requests.&lt;/li&gt;
&lt;li&gt;  Helps document your API endpoints.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://chromewebstore.google.com/detail/ehafadccdcdedbhcbddihehiodgcddpl" rel="noopener noreferrer"&gt;Yet Another REST Client&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Tests and debugs RESTful APIs.&lt;/li&gt;
&lt;li&gt;  Sends HTTP requests, inspects responses, and analyzes headers.&lt;/li&gt;
&lt;li&gt;  Supports various authentication methods.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Using these API tools simplifies development and ensures your endpoints work well.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion: Boost your development with Vivaldi extensions&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In conclusion, using extensions makes development work easier and more productive. Adding these tools to your Vivaldi browser can help streamline your tasks, improve your coding, and speed up your work. It's important to see how useful these extensions can be, as they offer specific solutions for developers' needs.&lt;/p&gt;

&lt;p&gt;As you start using Vivaldi for development, try the many extensions available and set up your browser to match your needs. Tools like &lt;a href="https://maxfoc.us" rel="noopener noreferrer"&gt;MaxFocus: Link Preview&lt;/a&gt; help you manage tabs better, keeping your browser neat. Whether you need tools for work, coding, teamwork, design, or keeping data safe, Vivaldi has options for everyone. Take the time to try different extensions and customize your browsing experience.&lt;/p&gt;

&lt;p&gt;Read after: &lt;a href="https://maxfoc.us/blog/make-your-own-arc-at-home/" rel="noopener noreferrer"&gt;Make your own Arc alternative at home&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devex</category>
      <category>browser</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Make your own Arc alternative at home</title>
      <dc:creator>Constantine</dc:creator>
      <pubDate>Sun, 23 Jun 2024 10:29:21 +0000</pubDate>
      <link>https://dev.to/qostya/make-your-own-arc-at-home-4cn7</link>
      <guid>https://dev.to/qostya/make-your-own-arc-at-home-4cn7</guid>
      <description>&lt;p&gt;Arc Browser is gaining popularity with its cool features and easy-to-use interface. However, some long-time Chrome or Firefox users may not want to switch over completely, and some Windows users have experienced performance issues with Arc.&lt;/p&gt;

&lt;p&gt;Fortunately, you don’t have to give up Chrome or Firefox to enjoy some of Arc’s most remarkable features. This article will show how to use extensions to bring Arc’s best features into your current browser. Whether you’re looking to preview links without leaving your page, organize your tabs more efficiently, or want a fresh look, we have solutions for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replace Arc’s Peek feature with MaxFocus
&lt;/h2&gt;

&lt;p&gt;Great for browsers: Chrome, Edge, Firefox, Opera, Vivaldi, and Brave.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Arc’s Peek feature&lt;/strong&gt;: Peek lets you quickly preview the content of a link without opening it in a new tab. It’s handy for checking the content without losing your current page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz0yicecektdqo79xcvc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz0yicecektdqo79xcvc.png" alt="Preview with Little Arc" width="800" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MaxFocus&lt;/strong&gt;: &lt;a href="https://maxfoc.us/" rel="noopener noreferrer"&gt;This link preview extension&lt;/a&gt; provides a similar feature to other browsers. It lets you preview links in various ways, such as hovering, long-clicking, or using a keyboard shortcut. This keeps you focused on your current task by letting you see what’s behind a link without navigating away.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqn9ki12og0rrxtxpkz0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqn9ki12og0rrxtxpkz0.png" alt="Preview with MaxFocus" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why you’ll love MaxFocus
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Customizable previews&lt;/strong&gt;: hover over, long-click, drag a link, or use a keyboard shortcut &lt;a href="https://maxfoc.us/blog/how-to-open/" rel="noopener noreferrer"&gt;to preview links&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reader mode&lt;/strong&gt;: enjoy a clean, ad-free reading experience for news and articles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced navigation&lt;/strong&gt;: you can preview webpages, articles, or &lt;a href="https://www.youtube.com/watch?v=mkHMrwfqN6U" rel="noopener noreferrer"&gt;videos&lt;/a&gt; before fully committing to opening them in a new tab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highly customizable&lt;/strong&gt;: adjust preview settings, color schemes, and power-saving options to suit your needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI features&lt;/strong&gt;: ask questions right in the preview, get prompt suggestions, and dive deeper into the content.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Replace vertical tabs from Arc with the Side Space extension
&lt;/h2&gt;

&lt;p&gt;Great for browsers: Chrome, Opera&lt;br&gt;
You can also enable native vertical tabs in Edge, Vivaldi, and Brave.&lt;br&gt;
For Firefox, try Sidebery or Tree Style Tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz20dmdjovqvgvol4bers.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz20dmdjovqvgvol4bers.png" alt="Vertical tab management in Arc" width="800" height="724"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Arc’s vertical tabs feature is incredibly convenient if you enjoy using vertical tabs. But if you’re seeking a similar experience in your browser, you should check out &lt;a href="https://www.sidespace.app/" rel="noopener noreferrer"&gt;the Side Space&lt;/a&gt; extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Side Space?
&lt;/h3&gt;

&lt;p&gt;Side Space is a vertical tabs manager in a side panel of your browser. Imagine all your tabs neatly lined up in work, life, or school categories, making it easy to find exactly what you need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F572zk3b44hugzlfxgoa9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F572zk3b44hugzlfxgoa9.png" alt="Vertical tab management with Side Space" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why you’ll love Side Space:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Organized spaces&lt;/strong&gt;: With Side Space, your tabs are neatly categorized into vertical spaces in a side panel. This means you can quickly find, manage, and focus on your tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Group tabs easily using AI&lt;/strong&gt;: Side Space uses AI to help organize and group your tabs efficiently, so you spend less time sorting and doing more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto sync across devices&lt;/strong&gt;: Your tabs automatically sync across devices. You can access your saved spaces from anywhere by logging in to your account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dark mode &amp;amp; Custom themes&lt;/strong&gt;: Browse comfortably at night with dark mode, and customize the space color palette to make it feel more like you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pin &amp;amp; Search tabs&lt;/strong&gt;: Pin key tabs for quick access and instantly find any tab or space with fuzzy search.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Try it out
&lt;/h3&gt;

&lt;p&gt;If you like the vertical tabs in Arc, you’ll love Side Space. It makes tab management easier, giving you more options and control. Side Space helps you keep track of many tabs while working, shopping, or browsing online.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced: Make an Arc-like UI in your Firefox
&lt;/h2&gt;

&lt;p&gt;Love the Arc Browser design but prefer Firefox? Use &lt;a href="https://github.com/KiKaraage/ArcWTF" rel="noopener noreferrer"&gt;the ArcWTF theme&lt;/a&gt; to customize your Firefox to look like Arc!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4l2ccowj1lg42zg30zvs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4l2ccowj1lg42zg30zvs.png" alt="ArcWTF theme. Screenshot from Reddit" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why you’ll love ArcWTF:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sleek design&lt;/strong&gt;: Vertical tabs, rounded corners, and a polished look.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced browsing&lt;/strong&gt;: Combine with add-ons like Sidebery for better tab management.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;If you’re looking for a new browser, Arc is a great choice. It’s fast, secure, and has a clean interface. But if you’re happy with your current browser, you can still enjoy some of Arc’s best features with extensions like &lt;strong&gt;&lt;a href="https://maxfoc.us" rel="noopener noreferrer"&gt;MaxFocus&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;Side Space&lt;/strong&gt;, and &lt;strong&gt;ArcWTF&lt;/strong&gt;. Give them a try and see how they can improve your browsing experience.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>browser</category>
      <category>extensions</category>
      <category>diy</category>
    </item>
    <item>
      <title>The Speculation Rules API: A Guide to Faster Websites</title>
      <dc:creator>Constantine</dc:creator>
      <pubDate>Mon, 06 May 2024 08:58:19 +0000</pubDate>
      <link>https://dev.to/qostya/the-speculation-rules-api-a-guide-to-faster-websites-43b2</link>
      <guid>https://dev.to/qostya/the-speculation-rules-api-a-guide-to-faster-websites-43b2</guid>
      <description>&lt;p&gt;In the pursuit of seamless user experiences, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API"&gt;the Speculation Rules API&lt;/a&gt; offers web developers a powerful tool to combat the latency that often accompanies web page navigation. By instructing the browser about likely user actions, this API enables proactive resource prefetching and even full-page prerendering, leading to significantly faster-perceived load times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding the Speculation Rules API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The core principle of the Speculation Rules API is providing predictive hints to the browser. Developers have the flexibility to indicate potential page navigations, empowering the browser to anticipate user behaviour and optimize resource loading ahead of time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefetching vs. Prerendering&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prefetching&lt;/strong&gt;: The browser downloads a target document and its associated resources (images, scripts, etc.) and stores them in its cache for later use. This ensures immediate availability if the user navigates to that page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prerendering&lt;/strong&gt;: This takes preloading further by instructing the browser to render the entire document (including JavaScript execution) in a hidden state. The user clicks the link, the prerendered page is displayed almost instantaneously.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Speculation Rules in Practice: Code Examples&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Speculation Rules are expressed in JSON format and can be embedded either inline in the HTML or served as a separate file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;E-commerce Product Listings:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;   
            &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; 
                &lt;/span&gt;&lt;span class="s2"&gt;"/product/12345"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
                &lt;/span&gt;&lt;span class="s2"&gt;"/product/56789"&lt;/span&gt;&lt;span class="w"&gt; 
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Blog Pagination:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;   
            &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/blog/page/2"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Search Results with “Next page” Link:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"prerender"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/list*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"expects_no_vary_search"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"params=(&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;page&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example: &lt;code&gt;&amp;lt;a href="/list?page=2"&amp;gt;Next page&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Injecting rules dynamically:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;preloadPages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;specType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prefetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prerender&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prefetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;HTMLScriptElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;supports&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;HTMLScriptElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supports&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;speculationrules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;specScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;specRules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;specType&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;source&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;specScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;speculationrules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;specScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specRules&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specScript&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Speculation Rules API &lt;a href="https://caniuse.com/mdn-html_elements_script_type_speculationrules"&gt;is currently supported&lt;/a&gt; in Chromium-based browsers (like Chrome, Edge, and Opera), which cover approximately 70% of the global browser market. While it doesn’t yet function in Firefox or Safari, it won’t break anything if you start using it today. Users on other platforms will gradually experience its benefits as browser support expands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yyibgzsa7e3n0whupf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yyibgzsa7e3n0whupf7.png" alt="Speculation API browser support" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need 100% coverage, you can use the old APIs &lt;em&gt;&lt;/em&gt; and &lt;em&gt;&lt;/em&gt;. More information from Addy Osmani: &lt;a href="https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf"&gt;https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How we use it in our extension&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We use the Speculation Rules API in &lt;a href="https://maxfoc.us/"&gt;the MaxFocus: Link Preview extension&lt;/a&gt; to improve preview loading speeds. When a user’s behaviour indicates they prefer the “Open on a long click” method, we dynamically inject Speculation Rules with the “prefetch” directive on the ‘mouse down’ event. This tells the browser to start preloading the linked page’s resources in the background, ensuring a near-instant preview experience when the user finally long-clicks to open it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiabrren2e7953ygdyex3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiabrren2e7953ygdyex3.png" alt="MaxFocus: Link preview extension" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Documentation from Mozilla &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;API updates in the Google for Developers blog: &lt;a href="https://developer.chrome.com/s/results?q=Speculation%20Rules"&gt;https://developer.chrome.com/s/results?q=Speculation%20Rules&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Optimizing data flow with the keep-unchanged-values library</title>
      <dc:creator>Constantine</dc:creator>
      <pubDate>Fri, 01 Dec 2023 08:19:11 +0000</pubDate>
      <link>https://dev.to/qostya/optimizing-data-flow-with-the-keep-unchanged-values-library-19c</link>
      <guid>https://dev.to/qostya/optimizing-data-flow-with-the-keep-unchanged-values-library-19c</guid>
      <description>&lt;p&gt;Hello everyone! If you're dealing with frequent data updates in your frontend development projects, especially from sources like backend servers or &lt;code&gt;localStorage&lt;/code&gt;, this article is essential for you. Discover how the &lt;code&gt;keep-unchanged-values&lt;/code&gt; library can enhance your React applications by optimizing data updates and minimizing performance issues. You need this if you're navigating through regular updates from various data sources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Frequent data updates in large objects and lists cause performance issues&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; &lt;code&gt;keep-unchanged-values&lt;/code&gt; combined with &lt;code&gt;React.memo&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pass two entities to the &lt;code&gt;keepUnchangedValues&lt;/code&gt; function you want to "merge". The result is the second entity, and it will keep references to unchanged objects from the first entity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;

 &lt;span class="c1"&gt;// result is equal to [2, 3, 4, { a: 1 }]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;keepUnchangedValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// logs true; result[3] will be a reference to oldArray[1] since they have the same link to the object&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;oldArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Update data from external storage periodically &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Merge" new data with existing using &lt;code&gt;keepUnchangedValues&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update your state with "merged" data: the old nested objects will be the same, new data will be applied&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;keepUnchangedValues&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keep-unchanged-values&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyListComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setList&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Fetch data from API&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newItems&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Update the list with new items, maintaining unchanged ones&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;keepUnchangedValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newItems&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// if nothing changed, returns the same list&lt;/span&gt;
        &lt;span class="nf"&gt;setList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Fetch initial data&lt;/span&gt;
    &lt;span class="nf"&gt;fetchHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// Set up polling&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intervalId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Polling every 5 seconds&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;intervalId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MemoizedListItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MemoizedListItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Rerenders only if the current item changes.&lt;/span&gt;
  &lt;span class="c1"&gt;// Works with shallow comparison because keepUnchangedValues maintains unchanged values&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;somethingIneficient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;MyListComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Unchanged list items retain their references&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;React.memo&lt;/code&gt; performs shallow comparisons and skips re-renders for unchanged items&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result? Smooth, efficient data updates!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Github:&lt;/strong&gt; &lt;a href="https://github.com/CascaSpace/keep-unchanged-values"&gt;https://github.com/CascaSpace/keep-unchanged-values&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Package:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/keep-unchanged-values"&gt;https://www.npmjs.com/package/keep-unchanged-values&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More examples can be seen in the library tests &lt;a href="https://github.com/CascaSpace/keep-unchanged-values/blob/main/src/index.test.js"&gt;https://github.com/CascaSpace/keep-unchanged-values/blob/main/src/index.test.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to learn more, check this article where we show how we optimized our Chrome Extension &lt;a href="https://cascaspace.substack.com/p/optimizing-performance-how-our-extension"&gt;https://cascaspace.substack.com/p/optimizing-performance-how-our-extension&lt;/a&gt; &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>opensource</category>
      <category>performance</category>
    </item>
    <item>
      <title>Optimizing performance: how our extension became lightning fast</title>
      <dc:creator>Constantine</dc:creator>
      <pubDate>Fri, 20 Oct 2023 14:41:55 +0000</pubDate>
      <link>https://dev.to/qostya/optimizing-performance-how-our-extension-became-lightning-fast-j16</link>
      <guid>https://dev.to/qostya/optimizing-performance-how-our-extension-became-lightning-fast-j16</guid>
      <description>&lt;p&gt;This article is for website creators who have some knowledge of backend and NGINX. It's about how we improved our browser extension to make it faster and better. By reading it, you'll learn about the tools and tricks we use to fix slow loading and other annoying problems.  &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Casca?
&lt;/h2&gt;

&lt;p&gt;Casca is a browser &lt;a href="https://casca.space/get/dev"&gt;extension&lt;/a&gt; that replaces your default new tab into a personalized dashboard. It lets you set up different workspaces (like one for work and one for personal stuff), customize your dashboard with helpful widgets, interact with ChatGPT, choose nice backgrounds, preview websites and more. It’s all about making your online space tidy and efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why Speed is Important to Us&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At Casca, we prioritize the speed and performance of our extension for several reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced User Experience&lt;/strong&gt;: Our main focus is to make sure our users have a fast and responsive browsing. Applications that are slow can make devices perform poorly and cause browsers to be slow as well. That's why our aim is to give our users a smooth and enjoyable online experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized Resource Usage&lt;/strong&gt;: We know that many users have devices that don't have a lot of power and that don't last long on a single charge. Apps that take a long time to load can use up these resources and make the device work slower. It is designed to use as little of these resources as possible, so users can browse the internet without their device slowing down or feeling laggy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Productivity and Efficiency&lt;/strong&gt;: A quick app saves time and helps you get things done faster. By reducing the time it takes to load and respond, it allows users to work more efficiently and complete tasks more quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability and Trust&lt;/strong&gt;: A slow and unresponsive app can make users lose trust. Our goal is to provide a browsing solution that is dependable and fast. By prioritizing speed and responsiveness, we demonstrate our commitment to delivering a top-notch product that meets user expectations.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Our tech stack
&lt;/h2&gt;

&lt;p&gt;To build Casca Extension, we used a bunch of different technologies such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React, Tailwind and React Grid Layout&lt;/strong&gt; to make the extension fast, scalable and beautiful&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IndexedDB&lt;/strong&gt; to store large data right in the browser&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js, Express and MongoDB&lt;/strong&gt; to proxy, map and cache external API requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharp library&lt;/strong&gt; to compress large images&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NGINX&lt;/strong&gt; serves as a load balancer for all requests and utilizes &lt;strong&gt;NGINX Content Caching&lt;/strong&gt; to cache slow responses from the &lt;strong&gt;Sharp&lt;/strong&gt; &lt;strong&gt;library&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How We Fixed Things&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Fixing Images &amp;amp; Favicons&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By using &lt;strong&gt;NGINX Content Caching&lt;/strong&gt; and &lt;strong&gt;IndexedDB&lt;/strong&gt;, we have improved the way we get large background images and multiple favicons. This means we can quickly save and retrieve images from a cache so they can be accessed immediately in the future.&lt;/p&gt;

&lt;p&gt;A part of our NGINX configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;proxy_cache_path  /var/www/cache/nginx levels=1:2 keys_zone=background-images:8m max_size=3000m inactive=1200m;
proxy_temp_path /var/www/cache/nginx/tmp;

location /api/casca/favicon {
  proxy_pass &amp;lt;SERVICE_ADDRESS&amp;gt;/api/casca/favicon;
  proxy_cache my-cache;
  proxy_cache_valid  200 302  24h;
  proxy_cache_valid  404      5m;
}

location /api/optimize {
  proxy_pass &amp;lt;SERVICE_ADDRESS&amp;gt;/api/optimize;
  proxy_cache background-images;
  proxy_cache_valid  200 302  7d;
  proxy_cache_valid  404      1h;
  add_header Access-Control-Allow-Origin *;
  #limit_req zone=one;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Express.js middleware:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/optimize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="nx"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// webp is a modern image format that provides lossless and lossy compression for images on the web&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;// compress image to 90% of original quality. It doesn't mean that the image will be 10% smaller&lt;/span&gt;
      &lt;span class="na"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="c1"&gt;// resize image to 1920px width. It's a pretty common resolution for desktops&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1920&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="c1"&gt;// make a blob and send it to the client side&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toBuffer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;binary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;And usage on the client side:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Background.jsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;imageURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;VITE_RESIZE_ORIGIN&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/optimize?url=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageURL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Background image"&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These optimizations made a big difference. For example, our background image used to be a large 1.9MB, but with the Sharp library, it's now just 334kB. This not only speeds up loading but also saves on network data and RAM usage. This makes the Casca Extension work smoothly, even on devices with less memory, providing a better user experience.&lt;/p&gt;

&lt;p&gt;The original image and our highly optimized copy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2gXKsEad--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qhdohqm9nxug5tm0o0ka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2gXKsEad--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qhdohqm9nxug5tm0o0ka.png" alt="Image optimization example. From 1.9mb to 334kb" width="800" height="869"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The differences in quality are not noticeable to the naked eye.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Dealing with slow requests&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To fetch data from other websites, we used &lt;strong&gt;Node.js&lt;/strong&gt; and &lt;strong&gt;Express&lt;/strong&gt; to create a middleware. It allows to save and serve the data quickly, even if the original website is slow.&lt;/p&gt;

&lt;p&gt;In addition, we store the fetched data in the localStorage cache. Therefore, the data is accessed offline and updated only when subsequent requests are fulfilled.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Stopping unneeded re-renders&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;useMemo, useEvent&lt;/strong&gt;: We memoized immutable data and functions to avoid redundant re-renders, ensuring that only the components witnessing data alterations are re-rendered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation of the &lt;code&gt;useEvent&lt;/code&gt; hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cbRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Update the callback reference when the callback function changes&lt;/span&gt;
  &lt;span class="nx"&gt;cbRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;

  &lt;span class="c1"&gt;// Return a memoized callback function. No hook dependencies are needed&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;((...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cbRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. It will always return the same function&lt;/span&gt;
  &lt;span class="c1"&gt;// 2. There will be the actual value in the closure&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleIncrement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useEvent&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SomeLargeComponent&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleIncrement&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are multiple names for this hook. You can find the documentation under the names &lt;a href="https://github.com/reactjs/rfcs/blob/useevent/text/0000-useevent.md"&gt;useEvent&lt;/a&gt; or &lt;a href="https://react.dev/reference/react/experimental_useEffectEvent"&gt;useEffectEvent&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;keep-unchanged-values&lt;/strong&gt;: This library is specifically deployed for regular data fetching scenarios. It prevents unnecessary re-renders by keeping unchanged values and only updating altered data.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// useStorageData.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useStorageData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectorFn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;selectorFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storageKey&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;onStorageChange&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selectorFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keepUnchangedValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectedData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- the usage is here&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextData&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// TodoItems.jsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;TodoItems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storageData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useStorageData&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todoItems&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;storageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MemoizedTodo&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Don't need to use deepEquals to check the props equality&lt;/span&gt;
&lt;span class="c1"&gt;// keepUnchangedValues returns an unchanged item&lt;/span&gt;
&lt;span class="c1"&gt;// if it finds it in the previous array (prevProps.data === nextProps.data is true)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MemoizedTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information you can check the library documentation at &lt;a href="https://github.com/CascaSpace/keep-unchanged-values"&gt;https://github.com/CascaSpace/keep-unchanged-values&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tips for Extension Developers&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To build a fast browser extension, it's important to consider more than just writing efficient code. Here are some tips for frontend developers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Optimize images and assets:&lt;/strong&gt;
Large images can slow down your extension. Compress images and use formats like WebP. Implement lazy loading to load images only when needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed up server requests:&lt;/strong&gt;
Slow server requests can be a performance bottleneck. Use caching, CDNs, and browser caching. Minimize unnecessary API calls by storing data locally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid unnecessary re-renders:&lt;/strong&gt;
Prevent components from re-rendering when data hasn't changed. Use techniques like &lt;code&gt;useEvent&lt;/code&gt;, &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;React.memo&lt;/code&gt; in React to optimize rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimize data storage:&lt;/strong&gt;
Choose the right data storage method. IndexedDB is great for storing large data sets in the browser. Manage data efficiently and plan for offline access and synchronization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus on user experience:&lt;/strong&gt;
Speed should improve the user experience. Test with users and gather feedback to identify areas for improvement. Prioritize a smooth and responsive interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep an eye on memory usage:&lt;/strong&gt;
High memory usage can slow down your extension and the browser. Keep an eye on memory consumption and optimize your code to reduce unnecessary memory use.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By following these tips, you can make sure that your browser extension runs well and efficiently, giving your users a better experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Wrapping Up&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Leveraging technologies like React, Tailwind, and React Grid Layout, we have created a visually appealing and scalable extension.&lt;/li&gt;
&lt;li&gt;We have optimized the handling of large images and favicons through NGINX Content Caching and IndexedDB.&lt;/li&gt;
&lt;li&gt;Slow requests have been addressed by implementing Node.js and Express middleware.&lt;/li&gt;
&lt;li&gt;Techniques like &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useEvent&lt;/code&gt; hooks have minimized unnecessary re-renders.&lt;/li&gt;
&lt;li&gt;The integration of the &lt;code&gt;keep-unchanged-values&lt;/code&gt; library has further improved performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have made the &lt;a href="https://casca.space/"&gt;Casca Extension&lt;/a&gt; much faster and more efficient by using different technologies. We fixed problems like slow loading of images and favicons, dealing with slow requests, and reducing unnecessary re-renders. As a result, our users now enjoy a quick and smooth browsing experience. We prioritize speed and responsiveness to ensure a seamless and enjoyable online experience without using too much of your device's resources. We will continue to improve our technology to keep Casca lightweight and efficient for our users.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>architecture</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
