<?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: Gil Fink</title>
    <description>The latest articles on DEV Community by Gil Fink (@gilfink).</description>
    <link>https://dev.to/gilfink</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%2F141537%2F660af2a4-9833-46bd-81db-d2d5e57cd090.jpg</url>
      <title>DEV Community: Gil Fink</title>
      <link>https://dev.to/gilfink</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gilfink"/>
    <language>en</language>
    <item>
      <title>Progressive Web Components: Unlocking Universal UI with Native APIs</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Fri, 05 Sep 2025 14:59:03 +0000</pubDate>
      <link>https://dev.to/gilfink/progressive-web-components-unlocking-universal-ui-with-native-apis-23lb</link>
      <guid>https://dev.to/gilfink/progressive-web-components-unlocking-universal-ui-with-native-apis-23lb</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fty7lfrtst95hjinfg2la.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fty7lfrtst95hjinfg2la.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The Cross-Framework Conundrum
&lt;/h4&gt;

&lt;p&gt;In the dynamic world of front-end development, we often find ourselves building intricate UI components. These components, born from hours of meticulous design and development, frequently become tethered to a specific framework — be it React, Vue, or Angular. This “framework monogamy” creates a significant challenge: how do you share that expertly crafted component across different projects, used by different teams, potentially leveraging different frameworks, without resorting to painful rewrites or clunky integration hacks?&lt;/p&gt;

&lt;p&gt;The ideal scenario is a truly universal component: one codebase, consumable everywhere, without forcing an entire project into a specific ecosystem. This is where the power of &lt;strong&gt;Progressive Web Components (PWCs)&lt;/strong&gt;, built on native browser APIs, comes into play.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Foundation: Native Web Components
&lt;/h4&gt;

&lt;p&gt;At its core, a Web Component is a custom HTML element, completely defined and encapsulated by the browser’s own standards. It’s not a framework; it’s a browser feature. This means it works inherently in &lt;strong&gt;any&lt;/strong&gt; modern browser and can be seamlessly integrated into &lt;strong&gt;any&lt;/strong&gt; front-end framework (or no framework at all).&lt;/p&gt;

&lt;p&gt;Let’s illustrate this with a practical example: a &lt;strong&gt;collapsible panel&lt;/strong&gt;. This is a common UI element that often requires custom logic for toggling visibility, accessibility attributes, and perhaps some internal content management.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Core Web Component: A Collapsible Panel Example
&lt;/h4&gt;

&lt;p&gt;We’ll build our collapsible panel using the native Web Components API directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// collapsible-panel.js
class CollapsiblePanel extends HTMLElement {
  static get observedAttributes() {
    return ['open'];
  }

  constructor() {
    super();
    this.attachShadow({ mode: 'open' }); 
    this.isOpen = this.hasAttribute('open');
    this.shadowRoot.innerHTML = `
      &amp;lt;style&amp;gt;
        :host {
          display: block;
          border: 1px solid #ccc;
          margin-bottom: 10px;
        }
        .header {
          padding: 10px;
          background-color: #f0f0f0;
          cursor: pointer;
          font-weight: bold;
          display: flex;
          justify-content: space-between;
          align-items: center;
        }
        .content {
          padding: 10px;
          border-top: 1px solid #eee;
        }
        .icon {
          transition: transform 0.2s ease-in-out;
        }
        :host([open]) .icon {
          transform: rotate(90deg);
        }
      &amp;lt;/style&amp;gt;
      &amp;lt;div class="header" role="button" tabindex="0" aria-expanded="${this.isOpen}"&amp;gt;
        &amp;lt;slot name="header"&amp;gt;&amp;lt;/slot&amp;gt;
        &amp;lt;span class="icon"&amp;gt;&amp;amp;#9658;&amp;lt;/span&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="content"&amp;gt;
        &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
      &amp;lt;/div&amp;gt;
    `;
    this._header = this.shadowRoot.querySelector('.header');
    this._content = this.shadowRoot.querySelector('.content');
  }

  connectedCallback() {
    this._header.addEventListener('click', this._togglePanel);
    this._header.addEventListener('keydown', this._handleKeydown);
    this._updateContentVisibility();
  }

  disconnectedCallback() {
    this._header.removeEventListener('click', this._togglePanel);
    this._header.removeEventListener('keydown', this._handleKeydown);
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'open') {
      this.isOpen = newValue !== null;
      this._updateContentVisibility();
      this._header.setAttribute('aria-expanded', this.isOpen);
      this.dispatchEvent(new CustomEvent('panel-toggle', { detail: { open: this.isOpen } }));
    }
  }

  _togglePanel() {
    if (this.isOpen) {
      this.removeAttribute('open');
    } else {
      this.setAttribute('open', '');
    }
  };

  _handleKeydown(event) {
    if (event.key === 'Enter' || event.key === ' ') {
      event.preventDefault();
      this._togglePanel();
    }
  };

  _updateContentVisibility() {
    this._content.style.display = this.isOpen ? '' : 'none';
  }

  toggle() {
    this._togglePanel();
  }
}
customElements.define('collapsible-panel', CollapsiblePanel);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use this component directly in HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;collapsible-panel open&amp;gt;
  &amp;lt;span slot="header"&amp;gt;My Awesome Panel&amp;lt;/span&amp;gt;
  &amp;lt;p&amp;gt;This is some content inside the collapsible panel.&amp;lt;/p&amp;gt;
&amp;lt;/collapsible-panel&amp;gt;
&amp;lt;collapsible-panel&amp;gt;
  &amp;lt;span slot="header"&amp;gt;Another Panel&amp;lt;/span&amp;gt;
  &amp;lt;p&amp;gt;More content here.&amp;lt;/p&amp;gt;
&amp;lt;/collapsible-panel&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The “Progressive” Layer: Framework Enhancements
&lt;/h4&gt;

&lt;p&gt;The Web Component is fully functional on its own. However, in a framework-driven application, developers expect a more “native” integration — passing props, listening to events in a framework-idiomatic way, and potentially leveraging framework context. This is where the “progressive layer” comes in: creating lightweight, framework-specific wrappers that enhance the Web Component’s usability without adding unnecessary overhead to its core.&lt;/p&gt;

&lt;h4&gt;
  
  
  Enhancing for React Example
&lt;/h4&gt;

&lt;p&gt;In React, we want to treat the Web Component like any other React component, managing its open state and listening to its panel-toggle event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// CollapsiblePanelReact.jsx
import React, { useRef, useEffect, useState } from 'react';
import './collapsible-panel';

const CollapsiblePanel = ({ children, header, defaultOpen = false, onToggle }) =&amp;gt; {
  const panelRef = useRef(null);
  const [isOpen, setIsOpen] = useState(defaultOpen);

  useEffect(() =&amp;gt; {
    const currentPanel = panelRef.current;
    if (!currentPanel) return;
    // Synchronize React state to Web Component attribute
    if (isOpen) {
      currentPanel.setAttribute('open', '');
    } else {
      currentPanel.removeAttribute('open');
    }
    const handlePanelToggle = (event) =&amp;gt; {
      setIsOpen(event.detail.open);
      onToggle &amp;amp;&amp;amp; onToggle(event.detail.open);
    };
    currentPanel.addEventListener('panel-toggle', handlePanelToggle);
    return () =&amp;gt; {
      currentPanel.removeEventListener('panel-toggle', handlePanelToggle);
    };
  }, [isOpen, onToggle]);

  return (
    &amp;lt;collapsible-panel ref={panelRef}&amp;gt;
      &amp;lt;span slot="header"&amp;gt;{header}&amp;lt;/span&amp;gt;
      {children}
    &amp;lt;/collapsible-panel&amp;gt;
  );
};

export default CollapsiblePanel;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, a consuming developer can use it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// MyApp.jsx
import React from 'react';
import CollapsiblePanel from './CollapsiblePanelReact';

const MyApp = () =&amp;gt; {
  const handlePanelToggle = (open) =&amp;gt; {
    console.log(`Panel is now ${open ? 'open' : 'closed'}`);
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;CollapsiblePanel header="React Specific Panel" defaultOpen onToggle={handlePanelToggle}&amp;gt;
        &amp;lt;p&amp;gt;This panel integrates seamlessly with React state and events.&amp;lt;/p&amp;gt;
      &amp;lt;/CollapsiblePanel&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; panelRef.current?.toggle()}&amp;gt;Toggle via Ref&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Enhancing for Vue Example
&lt;/h4&gt;

&lt;p&gt;Vue also allows straightforward integration with Web Components. We can create a simple wrapper to align with Vue’s reactivity system and event handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;collapsible-panel :open="isOpen" @panel-toggle="handleToggle"&amp;gt;
    &amp;lt;template v-slot:header&amp;gt;{{ header }}&amp;lt;/template&amp;gt;
    &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
  &amp;lt;/collapsible-panel&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import './collapsible-panel';
export default {
  props: {
    header: String,
    open: Boolean, 
  },
  data() {
    return {
      isOpen: this.open,
    };
  },
  watch: {
    open(newVal) {
      this.isOpen = newVal;
    }
  },
  methods: {
    handleToggle(event) {
      this.isOpen = event.detail.open;
      this.$emit('toggle', event.detail.open); 
    },
    toggle() {
      this.$refs.panel.toggle();
    }
  },
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in a Vue app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;CollapsiblePanelVue header="Vue Specific Panel" :open="isVuePanelOpen" @toggle="handleVueToggle"&amp;gt;
      &amp;lt;p&amp;gt;This content lives happily within a Vue component.&amp;lt;/p&amp;gt;
    &amp;lt;/CollapsiblePanelVue&amp;gt;
    &amp;lt;button @click="toggleVuePanel"&amp;gt;Toggle Vue Panel&amp;lt;/button&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import CollapsiblePanelVue from './CollapsiblePanelVue.vue';
export default {
  components: {
    CollapsiblePanelVue,
  },
  data() {
    return {
      isVuePanelOpen: true,
    };
  },
  methods: {
    handleVueToggle(open) {
      this.isVuePanelOpen = open;
      console.log(`Vue panel is now ${open ? 'open' : 'closed'}`);
    },
    toggleVuePanel() {
      this.isVuePanelOpen = !this.isVuePanelOpen;
    }
  },
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The Advantages of PWC
&lt;/h4&gt;

&lt;p&gt;The Progressive Web Component pattern, leveraging native APIs, offers advantages such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;True Interoperability:&lt;/strong&gt; Your core UI component is truly framework-agnostic. It’s a standard browser element, guaranteeing maximum reusability across diverse tech stacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Development Overhead:&lt;/strong&gt; Instead of developing and maintaining multiple versions of the same component for different frameworks, you maintain one core. The framework wrappers are thin layers, primarily focused on prop/event synchronization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Future-Proofing:&lt;/strong&gt; Native Web Components are part of the web platform. They are not dependent on a specific framework’s lifecycle or popularity, ensuring your components remain functional and relevant for long-term.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible Integration:&lt;/strong&gt; Teams can choose to use the native Web Component directly or opt for the framework-enhanced version, providing flexibility without sacrificing quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Potential Considerations and Challenges
&lt;/h4&gt;

&lt;p&gt;While Progressive Web Components offer great advantages, it’s also important to acknowledge some potential considerations and challenges. Integrating Web Components into existing framework ecosystems, especially older ones, might sometimes introduce minor friction. For instance, some frameworks might require specific configurations to correctly pass complex data types (like objects or arrays) as attributes, or to handle custom events in their own idiomatic way. There’s also a learning curve for teams unfamiliar with native Web Component APIs, which can differ from framework-specific component paradigms. Furthermore, the tooling and development experience for native Web Components, while rapidly improving, might not always be as mature or feature-rich as those tailored for established frameworks. Developers might need to invest more time in setting up development servers, linting, and testing environments compared to a fully integrated framework CLI. These aspects are often manageable with careful planning and good documentation, but they are worth considering during adoption.&lt;/p&gt;

&lt;p&gt;In today’s AI revolution, which includes AI generated code, it is easier and faster to build native Web Components and as a result these challenges become minor and less frightening.&lt;/p&gt;

&lt;h4&gt;
  
  
  Moving Beyond Framework Silos
&lt;/h4&gt;

&lt;p&gt;In an ecosystem brimming with choices, achieving UI consistency and developer efficiency across projects can seem like an uphill battle. Progressive Web Components, built on the solid foundation of native browser APIs, offer a clear path forward. They empower us to design and build components once, knowing they can adapt and integrate smoothly into any environment. This approach allows us to transcend framework-specific silos and build a more cohesive and sustainable web experience.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Beyond the Basics: Building a Responsive Image Processing Pipeline with the Scheduler API</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Sun, 29 Jun 2025 07:52:50 +0000</pubDate>
      <link>https://dev.to/gilfink/beyond-the-basics-building-a-responsive-image-processing-pipeline-with-the-scheduler-api-aoc</link>
      <guid>https://dev.to/gilfink/beyond-the-basics-building-a-responsive-image-processing-pipeline-with-the-scheduler-api-aoc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Frxytuszhw9q7j6i1sx7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Frxytuszhw9q7j6i1sx7p.png" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following up on our discussion about &lt;a href="https://medium.com/@gilfink/task-management-in-javascript-8be9e71fcb3d" rel="noopener noreferrer"&gt;mastering task management in JavaScript&lt;/a&gt; for smoother UIs, this post will take us deeper into the practical application of the Scheduler API. We’ve seen how postTask() and yield() can combat "janky UIs" by intelligently prioritizing and breaking down operations. Now, let's explore a real-world scenario where these capabilities truly shine: creating a responsive image processing pipeline directly in the browser.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Challenge: Client-Side Image Processing and UI Responsiveness
&lt;/h4&gt;

&lt;p&gt;Client-side image processing, such as resizing, applying filters, or watermarking, can be incredibly resource-intensive. If not handled carefully, these operations can easily block the main thread, leading to frozen UIs and frustrated users. Imagine a web application where users upload and manipulate high-resolution images — without proper task management, this could quickly become a nightmare.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Solution: Orchestrating Tasks with the Scheduler API
&lt;/h4&gt;

&lt;p&gt;There are a lot of solutions in the internet that uses Web Workers for image processing task, but this time we are going to leverage the new Scheduler API. The Scheduler API provides the perfect toolkit to manage these computationally heavy tasks without sacrificing responsiveness. We can break down the image processing workflow into smaller, manageable units and assign them appropriate priorities, ensuring that user interactions always take precedence.&lt;/p&gt;

&lt;h4&gt;
  
  
  A Browser-Based Image Editor
&lt;/h4&gt;

&lt;p&gt;Let’s consider a simplified image editor where a user can upload an image, apply a grayscale filter, and then resize it for display. Here’s how we can use the Scheduler API to keep the UI responsive throughout this process:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. User Interaction and Immediate Feedback (User-Blocking Priority)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user clicks to upload an image or apply a filter, the immediate visual feedback (e.g., a loading spinner, a modal window) is essential. These tasks should be user-blocking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function handleImageUpload(event) {
  displayLoadingSpinner();
  await scheduler.postTask(() =&amp;gt; {
    // Simulate a quick file read
    console.log("Image upload started: User-Blocking task");
    // ... actual file reading logic
  }, { priority: 'user-blocking' });
  // Now, transition to user-visible for processing
  processImage(event.target.files[0]);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Image Processing (User-Visible Priority)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The actual image processing (applying a filter, resizing) can be broken down. While important for the user to see the result, these operations can yield periodically to allow the UI to remain interactive. We'll use user-visible priority for these tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function processImage(file) {
  hideLoadingSpinner();
  displayProcessingIndicator();
  const image = await createImageBitmap(file);
  // Apply Grayscale Filter 
  await scheduler.postTask(async () =&amp;gt; {
    console.log("Applying grayscale filter: User-Visible task");
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = image.width;
    canvas.height = image.height;
    ctx.drawImage(image, 0, 0);
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const pixels = imageData.data;
    for (let i = 0; i &amp;lt; pixels.length; i += 4) {
      const avg = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3;
      pixels[i] = avg; // Red
      pixels[i + 1] = avg; // Green
      pixels[i + 2] = avg; // Blue
      // Yield periodically to prevent UI jank
      if (i % 10000 === 0) { // Yield every 10,000 pixels (adjust as needed)
        await scheduler.yield();
        console.log("Yielded during grayscale processing");
      }
    }
    ctx.putImageData(imageData, 0, 0);
    console.log("Grayscale filter applied.");
  }, { priority: 'user-visible' });

  await scheduler.postTask(async () =&amp;gt; {
    console.log("Resizing image: User-Visible task");
    const resizedCanvas = document.createElement('canvas');
    const resizedCtx = resizedCanvas.getContext('2d');
    const targetWidth = 400; 
    const targetHeight = (image.height / image.width) * targetWidth;
    resizedCanvas.width = targetWidth;
    resizedCanvas.height = targetHeight;
    resizedCtx.drawImage(image, 0, 0, targetWidth, targetHeight);
    console.log("Image resized.");
    displayProcessedImage(resizedCanvas.toDataURL());
  }, { priority: 'user-visible' });
  hideProcessingIndicator();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Background Operations (Background Priority)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Perhaps after processing, we want to save a smaller version of the image to local storage, or perform other non-critical operations. These can be handled with background priority:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function cacheImage(imageDataURL) {
  await scheduler.postTask(() =&amp;gt; {
    console.log("Caching image to local storage: Background task");
    // Simulate caching
    // localStorage.setItem('processedImage', imageDataURL);
  }, { priority: 'background' });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Some Considerations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Granularity of Tasks:&lt;/strong&gt; The key is to break down large operations into small enough chunks to allow yield() to be effective. Experiment with the if (i % 10000 === 0) condition in the grayscale example to find the optimal balance for your specific tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoiding Over-Yielding:&lt;/strong&gt; While yielding is good, yielding &lt;em&gt;too&lt;/em&gt; frequently can introduce its own overhead. Find the sweet spot where the UI remains responsive without degrading overall performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;By strategically utilizing postTask() with different priorities and judiciously employing yield() within long-running computations, we can construct highly responsive web applications, even when dealing with demanding tasks like client-side image processing. The Scheduler API empowers us to create seamless UX, ensuring that our JavaScript applications are not just functional, but truly delightful to interact with.&lt;/p&gt;

</description>
      <category>scheduler</category>
      <category>webperf</category>
      <category>taskmanagement</category>
      <category>web</category>
    </item>
    <item>
      <title>Task Management in JavaScript</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Sat, 21 Jun 2025 09:25:08 +0000</pubDate>
      <link>https://dev.to/gilfink/task-management-in-javascript-1756</link>
      <guid>https://dev.to/gilfink/task-management-in-javascript-1756</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2F5d7b0y48nrnv5walfmkn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F5d7b0y48nrnv5walfmkn.png" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Don’t block the main thread!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As front-end developers, we’re constantly producing UI tasks. From rendering complex UI components to processing user input, and from fetching data to running animations, our applications are a built of concurrent operations. Historically, managing these tasks to ensure a smooth and responsive user experience has been a delicate balancing act, often involving a patchwork of setTimeout, requestAnimationFrame, and Promises. But what if we could tell the browser exactly how important each task is? What if we could influence when and how they run, ensuring that user-critical operations always take precedence?&lt;/p&gt;

&lt;p&gt;Enter the &lt;strong&gt;Scheduler API&lt;/strong&gt;. This evolving but powerful Web API is poised to revolutionize how we approach task management in JavaScript, offering fine-grained control over the browser’s main thread and paving the way for significantly smoother user experience.&lt;/p&gt;

&lt;p&gt;In this post, we’ll dive deep into the &lt;strong&gt;Scheduler API&lt;/strong&gt; , understand its core concepts, and explore how to leverage its capabilities to truly master task management in your front-end applications.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Challenge: Janky UIs and Unresponsive Apps
&lt;/h3&gt;

&lt;p&gt;Before we jump into the solution, let’s briefly revisit the problem. Imagine a scenario where a user clicks a button that triggers a long-running JavaScript computation. Without proper task management, this computation can block the main thread, leading to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Janky animations:&lt;/strong&gt; Animations stutter or freeze&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delayed input responses:&lt;/strong&gt; User interactions such as clicks or scrolls feel unresponsive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frozen UI:&lt;/strong&gt; The entire page appears to hang, frustrating the user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Traditional asynchronous patterns like setTimeout(..., 0) offer a way to break up long tasks, but they don't provide any guarantees about when the continuation of your task will run relative to other browser work . This is where the &lt;strong&gt;Scheduler API&lt;/strong&gt;  shines.&lt;/p&gt;
&lt;h3&gt;
  
  
  Introducing the Scheduler API: Your Browser’s Taskmaster
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Scheduler API&lt;/strong&gt; , accessible via scheduler (or window.scheduler in the main thread and self.scheduler in Web Workers), provides two primary functions for managing tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;postTask(): For scheduling new tasks with specified priorities&lt;/li&gt;
&lt;li&gt;yield(): For yielding control of the main thread back to the browser, with the ability to prioritize the continuation of the current task&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s break these functions down.&lt;/p&gt;
&lt;h4&gt;
  
  
  scheduler.postTask(): Prioritizing New Tasks
&lt;/h4&gt;

&lt;p&gt;The postTask() function allows you to add a new task to the browser's task queue with an optional priority, delay, and an AbortSignal for cancellation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding Task Priorities&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API defines three priority levels, each serving a distinct purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;'user-blocking' (highest priority):&lt;/strong&gt; For tasks that are critical for immediate user interaction. Think of operations that directly respond to a user's click or keypress, where any delay would be immediately noticeable and frustrating. Examples include updating UI based on user input, or processing critical data for a new screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;'user-visible' (default priority):&lt;/strong&gt; For tasks that are visible to the user but not immediately blocking. Examples include loading non-critical images, updating less important UI elements, or performing background data synchronization that doesn't impact immediate user flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;'background' (lowest priority):&lt;/strong&gt; For tasks that are not time-critical and can run when the browser is idle. Examples include analytics reporting, pre-fetching resources for future navigation, or processing data that isn't immediately displayed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Basic Usage of&lt;/strong&gt; &lt;strong&gt;postTask()&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s see it in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Check for feature support in the browser
if (scheduler &amp;amp;&amp;amp; scheduler.postTask) {
  scheduler.postTask(() =&amp;gt; {
    console.log("User-blocking task executed!");
    // Perform critical UI updates or calculations
  }, { priority: 'user-blocking' });

  scheduler.postTask(() =&amp;gt; {
    console.log("User-visible task executed!");
    // Load an image, update a sidebar widget
  });

  scheduler.postTask(() =&amp;gt; {
    console.log("Background task executed!");
    // Send analytics data, pre-fetch content
  }, { priority: 'background' });

} else {
  console.warn("Scheduler API not supported. Falling back to traditional methods.");
  // Implement fallback using setTimeout or other techniques
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple example illustrates how you can declare your intentions to the browser. The browser’s scheduler will then do its best to execute these tasks according to their priority, ensuring that higher-priority tasks are given preference.&lt;/p&gt;

&lt;h4&gt;
  
  
  scheduler.yield(): Keeping the UI Responsive During Long Operations
&lt;/h4&gt;

&lt;p&gt;While postTask() is excellent for scheduling &lt;em&gt;new&lt;/em&gt; tasks, what about long-running operations that &lt;em&gt;must&lt;/em&gt; execute on the main thread and can't be easily broken into entirely separate tasks? This is where scheduler.yield() comes into play.&lt;/p&gt;

&lt;p&gt;scheduler.yield() allows you to yield control of the main thread back to the browser. It returns a Promise that resolves when the browser determines it's a good time to resume the yielded task. The crucial advantage of scheduler.yield() over setTimeout(..., 0) is that the continuation of the yielded task is often prioritized over other pending tasks of similar priority. This means your long-running operation can be chunked, allowing the browser to process user input or render updates in between chunks, leading to a much more responsive UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Breaking Up a Long Calculation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider a function that performs a computationally intensive loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function processLargeDataset() {
  const data = Array.from({ length: 100000 }, (_, i) =&amp;gt; i); // Simulate large dataset
  const results = [];
  for (let i = 0; i &amp;lt; data.length; i++) {
    // This is an intensive calculation
    let sum = 0;
    for (let j = 0; j &amp;lt; 1000; j++) {
      sum += Math.sqrt(data[i] * j);
    }
    results.push(sum);
    // Yield control to the browser periodically
    if (i % 1000 === 0) { // Yield every 1000 iterations
      await scheduler.yield();
      console.log(`Yielded at iteration ${i}`);
    }
  }
  console.log("Dataset processing complete!");
  return results;
}

document.getElementById('start-btn').addEventListener('click', async () =&amp;gt; {
  console.log("Starting large dataset processing...");
  // Show a loading indicator immediately
  document.getElementById('status').textContent = "Processing...";
  const processedData = await processLargeDataset();
  console.log("Processed data:", processedData);
  document.getElementById('status').textContent = "Done!";
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, by strategically placing await scheduler.yield(), we allow the browser to interleave its own critical work (like rendering or handling user input) with our long-running calculation. The user will experience a much smoother application, even during heavy processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Good Practices and Considerations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feature Detection:&lt;/strong&gt; Always check for scheduler before using the API, as it's still relatively new. Provide fallbacks for older browsers. There is also a good polyfill for the API &lt;a href="https://www.npmjs.com/package/scheduler-polyfill" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don’t Over-Yield:&lt;/strong&gt; While scheduler.yield() is powerful, don't yield too frequently. Each yield incurs a small overhead. Find a balance that keeps your UI responsive without introducing unnecessary delays.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Appropriate Priority:&lt;/strong&gt; Carefully consider the true priority of your tasks. Overusing user-blocking can negate the benefits of the API and lead to a less responsive overall application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offloading Heavy Computation:&lt;/strong&gt; For truly massive computations that don’t need direct DOM access, Web Workers remain the go-to solution. The Scheduler API complements Web Workers by managing tasks on the main thread more effectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling:&lt;/strong&gt; Remember that postTask() returns a Promise, so use .then().catch() or async/await with try...catch blocks to handle potential errors or task abortions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive Enhancement:&lt;/strong&gt; Design your applications to work without the Scheduler API first, then enhance the experience if the API is available.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;The Scheduler API is a significant step forward in giving developers more control over the browser’s scheduling mechanisms. By understanding and effectively utilizing postTask() and yield() we can build more responsive, fluid, and user-friendly web applications. As this API gains wider adoption, it will undoubtedly become a cornerstone of modern front-end performance optimization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Prioritized_Task_Scheduling_API" rel="noopener noreferrer"&gt;Prioritized Task Scheduling API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.dev/articles/optimize-long-tasks" rel="noopener noreferrer"&gt;Optimize long tasks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>performance</category>
      <category>taskmanagement</category>
      <category>api</category>
      <category>tasks</category>
    </item>
    <item>
      <title>Quick Tip — Using Callback Refs in React</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Mon, 13 Nov 2023 09:24:09 +0000</pubDate>
      <link>https://dev.to/gilfink/quick-tip-using-callback-refs-in-react-4gef</link>
      <guid>https://dev.to/gilfink/quick-tip-using-callback-refs-in-react-4gef</guid>
      <description>&lt;h3&gt;
  
  
  Quick Tip — Using Callback Refs in React
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F79kiq3mc1gh4rd7nj5bx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F79kiq3mc1gh4rd7nj5bx.png" width="800" height="406"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Post Code in Code Sandbox&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of the usages I see a lot with &lt;strong&gt;useEffect&lt;/strong&gt; in React code is to run some JavaScript code on an element reference which is stored as ref as soon as this element is mounted. For example, when an element is mounted, animate it’s content using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API" rel="noopener noreferrer"&gt;Web Animation API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The following code is doing exactly that:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the code above, you set the ref to the heading element and when the component is mounted, it’s animating the heading with some premade animation.&lt;/p&gt;

&lt;p&gt;That is easy, so why should you bother reading this post at all?&lt;br&gt;&lt;br&gt;
Because there is a better alternative to do exactly the same thing but without &lt;strong&gt;useEffect&lt;/strong&gt; and *&lt;em&gt;useRef *&lt;/em&gt; hooks.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;ref&lt;/strong&gt; attribute is expecting that you will set it with one of the following types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RefCallback&amp;lt;T&amp;gt; | RefObject&amp;lt;T&amp;gt; | null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A &lt;strong&gt;RefCallback&lt;/strong&gt; is just a function that accepts the element node and returns void. In a matter of fact, whenever you use &lt;strong&gt;RefObject&lt;/strong&gt; , it’s just a syntactic sugar to set the reference on the element to the &lt;strong&gt;current&lt;/strong&gt; accessor of the &lt;strong&gt;useRef&lt;/strong&gt; created reference. The following code is what is going to happen when you set a &lt;strong&gt;ref&lt;/strong&gt; like in the first code block in this post:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1
  ref={(node) =&amp;gt; {
    ref.current = node;
  }}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;strong&gt;RefCallback&lt;/strong&gt; function is going to run after the component is mounted, re-rendered or unmounted.&lt;/p&gt;

&lt;p&gt;Now, packed with this knowledge, how you can refactor the above code and stop using &lt;strong&gt;useEffect&lt;/strong&gt; and &lt;strong&gt;useRef&lt;/strong&gt; combination?&lt;/p&gt;

&lt;p&gt;The following code will do exactly that:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Let’s try to understand what is going on. In the code, you use the &lt;strong&gt;useCallback&lt;/strong&gt; function with an empty dependency array to wrap the callback ref function. This will make sure that React runtime will run this function only on mount and that is it. No need to use the &lt;strong&gt;useRef&lt;/strong&gt; or &lt;strong&gt;useEffect&lt;/strong&gt; hook and you achieve the same functionality. You gain two adeed bonueses when you use callback ref. The first one is that you don’t get double rendering in development mode like you will get when you use &lt;strong&gt;useEffect&lt;/strong&gt;. The second bonus is that in the case of using &lt;strong&gt;forwardRef&lt;/strong&gt; and conditional rendering, the callback &lt;strong&gt;ref&lt;/strong&gt; code will stay stable and work while the &lt;strong&gt;useEffect&lt;/strong&gt; code might not work as expected if the element isn’t rendered due to the conditional rendering.&lt;/p&gt;

&lt;p&gt;If you want to look at the provided code and see how it works, you can play with the previous code in this sandbox:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/9c583e21c4c620c5e9138e5c7bb3d6be/href" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/9c583e21c4c620c5e9138e5c7bb3d6be/href" rel="noopener noreferrer"&gt;https://medium.com/media/9c583e21c4c620c5e9138e5c7bb3d6be/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For further reading about callback refs, you can look at React documentation: &lt;a href="https://legacy.reactjs.org/docs/refs-and-the-dom.html#callback-refs" rel="noopener noreferrer"&gt;https://legacy.reactjs.org/docs/refs-and-the-dom.html#callback-refs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ref</category>
      <category>react</category>
      <category>usecallback</category>
      <category>useeffect</category>
    </item>
    <item>
      <title>Integrating D3 in Qwik Apps</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Fri, 30 Jun 2023 17:11:41 +0000</pubDate>
      <link>https://dev.to/gilfink/integrating-d3-in-qwik-apps-4c21</link>
      <guid>https://dev.to/gilfink/integrating-d3-in-qwik-apps-4c21</guid>
      <description>&lt;p&gt;In the past I wrote a bunch of posts that explained how to integrate D3 library and React. In this post I’ll do the same but this time I’ll show you how to integrate D3 in Qwik apps. We will build together a D3 tree and host it inside a basic Qwik app.&lt;/p&gt;

&lt;p&gt;Are you ready?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Things to do before you start adding the suggested code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a new Qwik app using the &lt;strong&gt;npm create qwik@latest&lt;/strong&gt; &lt;em&gt;.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add a new route to your app, which will be used to show the D3 graph.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Creating a Qwik D3 Container Component
&lt;/h4&gt;

&lt;p&gt;First you are going to add a new &lt;strong&gt;TreeContainer&lt;/strong&gt; component. This component will be responsible to hold the D3 container, which will be used to create the graph.&lt;/p&gt;

&lt;p&gt;Let’s look at the code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;strong&gt;TreeContainer&lt;/strong&gt; is going to be the div that D3 will use to create the graph. You use a signal to reference the rendered &lt;strong&gt;div&lt;/strong&gt; , so you will be able to use it’s in-memory Html element representation later on.&lt;br&gt;&lt;br&gt;
Another thing that you can notice is the usage of &lt;strong&gt;useVisibileTask$&lt;/strong&gt;. Since D3 runs only in the client, you should use the &lt;strong&gt;useVisibileTask$&lt;/strong&gt; hook that makes sure that the code which is responsible to creates the graph runs after the component’s client rendering.&lt;/p&gt;
&lt;h4&gt;
  
  
  Building the Graph Generator
&lt;/h4&gt;

&lt;p&gt;Once the container is ready it’s time to write the &lt;strong&gt;createGraph&lt;/strong&gt; function.&lt;/p&gt;

&lt;p&gt;Here is the full function code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s analyze the code to understand what is going on. We will start in the beginning with the &lt;strong&gt;processSymbols&lt;/strong&gt; function.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Sometimes we have a model that doesn’t fit into the way the D3 graphs expect their data. The &lt;strong&gt;processSymbols&lt;/strong&gt; function will transform the symbols array to the needed graph representation.&lt;/p&gt;

&lt;p&gt;At the start of the &lt;strong&gt;createGraph&lt;/strong&gt; function you set the d3 tree in-memory implementation. This is happening in these lines of code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Then, you create the tree visual representation using D3 API that creates SVG elements such as paths, circles, text and more:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The data that is being used in the example is the following symbols array:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After you wire everything you can run the app to see the following graph on your screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F3eadyd991wrh86pgqj5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F3eadyd991wrh86pgqj5z.png" width="800" height="377"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Symbol Graph&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;In the post I showed you how easy it is to integrate D3 in Qwik apps. The post guided you how to create the graph container and then how to create the graph by using D3 functionality.&lt;/p&gt;

&lt;p&gt;You can take a look at the whole example in the &lt;a href="https://github.com/gilf/qwik-d3-example" rel="noopener noreferrer"&gt;qwik-d3-example&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>qwik</category>
      <category>javascript</category>
      <category>trees</category>
      <category>d3js</category>
    </item>
    <item>
      <title>Adding Authentication to a Qwik App</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Tue, 28 Feb 2023 12:41:45 +0000</pubDate>
      <link>https://dev.to/gilfink/adding-authentication-to-a-qwik-app-3m8l</link>
      <guid>https://dev.to/gilfink/adding-authentication-to-a-qwik-app-3m8l</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2F9hi3tsjt35sojck4s5bc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F9hi3tsjt35sojck4s5bc.png" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Authentication is a basic feature that is implemented in most of the apps and websites. Today there are many ways to authenticate users and the most popular front-end library for authentication is probably &lt;a href="https://authjs.dev/" rel="noopener noreferrer"&gt;auth.js&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
But how can you use the library in your Qwik app?&lt;/p&gt;

&lt;p&gt;This post will explain how to integrate qwik-auth package into your Qwik app.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The qwik-auth package is still experimental and some of the shown code might change in the future.&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Setting the qwik-auth Package
&lt;/h4&gt;

&lt;p&gt;The first thing to do when you want to use &lt;strong&gt;qwik-auth&lt;/strong&gt; is to install it. Since &lt;strong&gt;auth.js&lt;/strong&gt; is a peer dependency, you will have to install it as well. Run the following command to install the libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm i "@builder.io/qwik-auth" "@auth/core"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the installation finishes, you will need to update the &lt;strong&gt;vite.config.js&lt;/strong&gt; and include the &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/auth"&gt;@auth&lt;/a&gt;/core&lt;/strong&gt; library to the &lt;strong&gt;optimizeDeps&lt;/strong&gt; config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { defineConfig } from 'vite';
import { qwikVite } from '@builder.io/qwik/optimizer';
import { qwikCity } from '@builder.io/qwik-city/vite';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig(() =&amp;gt; {
  return {
    optimizeDeps: {
      include: ['@auth/core'],
    },
    plugins: [qwikCity(), qwikVite(), tsconfigPaths()],
    preview: {
      headers: {
        'Cache-Control': 'public, max-age=600',
      },
    },
  };
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: This is a workaround to a bug that is currently exists in qwik-auth which is&lt;/em&gt; &lt;em&gt;SyntaxError: The requested module '/node_modules/.pnpm/&lt;a href="mailto:cookie@0.5.0"&gt;cookie@0.5.0&lt;/a&gt;/node_modules/cookie/index.js?v=849ea94b' does not provide an export named 'parse'&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you updated the &lt;strong&gt;vite.config.js&lt;/strong&gt; you will have to add a secret string for your app. The place to put it is in the app  &lt;strong&gt;.env&lt;/strong&gt; file. In my demo app I called the variable &lt;strong&gt;VITE_AUTH_SECRET&lt;/strong&gt; , but you can put any name that you like as long as you will use that name in the relevant place.&lt;/p&gt;

&lt;h4&gt;
  
  
  Generating the qwik-auth Actions and Loaders
&lt;/h4&gt;

&lt;p&gt;Everything is set up and now you can go and use &lt;strong&gt;qwik-auth&lt;/strong&gt; in your app. &lt;strong&gt;qwik-auth&lt;/strong&gt; exposes a &lt;strong&gt;serverAuth$&lt;/strong&gt; generator function that will generate all the actions and loaders you need for login, logout or getting the current session. Once you give it a callback that returns a configuration object with all the authentication providers, it will generate the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;useAuthSignin &lt;/strong&gt; — action that can be used to run the login process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;useAuthSignout&lt;/strong&gt;  — action that can be used to run the logout process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;useAuthSession &lt;/strong&gt; — loader to get the current session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use any of the &lt;a href="https://authjs.dev/reference/providers/oauth-builtin" rel="noopener noreferrer"&gt;authentication providers&lt;/a&gt; that &lt;strong&gt;auth.js&lt;/strong&gt; exposes. The following code shows you how I used the credentials provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { Provider } from '@auth/core/providers';
import CredentialsProvider from '@auth/core/providers/credentials';
import { serverAuth$ } from '@builder.io/qwik-auth';
import { users } from '~/data/users';

export const { useAuthSignin, useAuthSignout, useAuthSession, onRequest } = serverAuth$(
  () =&amp;gt; {
    return ({
      secret: import.meta.env.VITE_AUTH_SECRET,
      trustHost: true,
      providers: [
        CredentialsProvider({
          name: 'Login',
          authorize: (credentials) =&amp;gt; {
            if (credentials) {
              const user = users.get(credentials.username as string);
              if (user) {
                if (user.password === credentials.password) {
                  return { id: user.username, name: user.username, email: `${@gmail.com"&amp;gt;user.username}@gmail.com`};
                }
              }
            }
            return null;
          },
          credentials: {
            username: { label: 'Username', type: 'text' },
            password: { label: 'Password', type: 'password' },
          },
        }),
      ] as Provider[],
    })});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the credentials provider, I plug into the &lt;strong&gt;authorize&lt;/strong&gt; function and check the existence of a user inside an in-memory map object. In real-world, you will check that against a database but I wanted a simplified example.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pay attention that the place to put the code I showed is inside the app&lt;/em&gt; &lt;strong&gt;_routes _&lt;/strong&gt; &lt;em&gt;folder.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Using The Generated qwik-auth Actions and Loaders
&lt;/h4&gt;

&lt;p&gt;Once you generated the &lt;strong&gt;qwik-auth&lt;/strong&gt; actions and loaders instances, you can use them in your app. To run the login process, you will first have to run the &lt;strong&gt;useAuthSignin&lt;/strong&gt; action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const loginAction = useAuthSignin();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can wire it to a trigger button inside a *&lt;em&gt;Form *&lt;/em&gt; element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Form action={loginAction}&amp;gt;
  &amp;lt;div class="container"&amp;gt;
    &amp;lt;input
      type="hidden"
      name="provider"
      value="credentials"
    /&amp;gt;
    &amp;lt;div class="login"&amp;gt;
      &amp;lt;button&amp;gt;Login&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/Form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pay attention to the hidden input with the provider name. This input holds the requested provider and you need to put it inside the form.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To run the logout process you will do the same as with the login but this time with the &lt;strong&gt;useAuthSignout&lt;/strong&gt; action. If you want to use the current session you will use the &lt;strong&gt;useAuthSession&lt;/strong&gt; loader and in it’s &lt;strong&gt;value&lt;/strong&gt; property you will find the current user.&lt;br&gt;&lt;br&gt;
In my example, I used the session in the main layout and passed a &lt;strong&gt;loggedIn&lt;/strong&gt; Boolean to the header component, which is later used to show/hide the logout button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default component$(() =&amp;gt; {
  const serverTime = useServerTimeLoader();
  const userSignal = useAuthSession();

  return (
    &amp;lt;&amp;gt;
      &amp;lt;main&amp;gt;
        &amp;lt;Header loggedIn={userSignal.value?.user !== undefined} /&amp;gt;
        &amp;lt;section&amp;gt;
          &amp;lt;Slot /&amp;gt;
        &amp;lt;/section&amp;gt;
      &amp;lt;/main&amp;gt;
      &amp;lt;footer&amp;gt;
        &amp;lt;a href="https://www.builder.io/" target="_blank"&amp;gt;
          Made with ♡ by Builder.io
          &amp;lt;div&amp;gt;{serverTime.value.date}&amp;lt;/div&amp;gt;
        &amp;lt;/a&amp;gt;
      &amp;lt;/footer&amp;gt;
    &amp;lt;/&amp;gt;
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to look at the full example, you can find it &lt;a href="https://github.com/gilf/qwik-auth-example" rel="noopener noreferrer"&gt;online&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;In the post I showed how you can install and then use the &lt;strong&gt;qwik-auth&lt;/strong&gt; package. This package is part of Qwik and is currently experimenatal. There is no documentation for the package yet, so I hope that this post will help you get started with it if you want to use it today.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>authentication</category>
      <category>qwikcity</category>
      <category>qwik</category>
    </item>
    <item>
      <title>Using a QwikCity Loader to Load Database Data</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Sat, 18 Feb 2023 10:05:56 +0000</pubDate>
      <link>https://dev.to/gilfink/using-a-qwikcity-loader-to-load-database-data-4o13</link>
      <guid>https://dev.to/gilfink/using-a-qwikcity-loader-to-load-database-data-4o13</guid>
      <description>&lt;p&gt;Yesterday I wrote a post called “&lt;a href="https://dev.to/gilfink/using-qwikcity-loaders-to-load-data-2gm7"&gt;Using QwikCity Loaders to Load Data&lt;/a&gt;” that shorty explains how to load data using the new &lt;strong&gt;QwikCity&lt;/strong&gt; loader’s API. When I wrote the post I used an in-memory array and just returned it as the example data. One of the questions I got was how to do the same, but this time by working against a database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F2dzbzqlkc1kmsqsqww4a.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F2dzbzqlkc1kmsqsqww4a.jpeg" width="298" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post I’m going to show you exactly that 😉&lt;/p&gt;

&lt;h4&gt;
  
  
  Enter Prisma
&lt;/h4&gt;

&lt;p&gt;In this post I’m going to use &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt;, which is a popular Node.js Object Relation Mapper (ORM), and work against a MySQL products database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fsma3y2j0xxj13wtc8jcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fsma3y2j0xxj13wtc8jcj.png" width="517" height="135"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Products Database Table&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post isn’t going to explain the concepts of ORM but to summarize it in one line — ORMs bridge the gap between in-memory app objects and relational databases.&lt;/p&gt;

&lt;p&gt;Let’s drill down and see how to do use Prisma.&lt;/p&gt;
&lt;h4&gt;
  
  
  Setting up Prisma Inside a QwikCity App
&lt;/h4&gt;

&lt;p&gt;When you want to start using Prisma, you will have to add it to the QwikCity app. First thing, install Prisma CLI using your command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm install prisma --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, run the prisma initialization command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx prisma init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command is going to do 2 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a folder named &lt;strong&gt;prisma&lt;/strong&gt; with a schema.prisma file. You are going to use this file to configure the schema and database connection.&lt;/li&gt;
&lt;li&gt;If a .env file doesn’t exists, it will create it. You use this file to add environment variables to your project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Go to the generated .env file and replace the DATABASE_URL variable with your database connection. Now you are ready to run Prisma introspection script to investigate and create a schema out of your existing database. Use the following command to do exactly that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx prisma db pull
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have the same table like I do, the schema.prisma file will be updated and might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url = env("DATABASE_URL")
}

model products {
  id Int @id
  name String? @db.VarChar(80)
  description String? @db.VarChar(300)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last thing to do is to install the @prisma/client package, which will help you run queries against the database. Use the following command to install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm install @prisma/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the client is installed run the following command to generate all the client code from the previous schema.prisma file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx prisma generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can move on and update the loader I used in my &lt;a href="https://dev.to/gilfink/using-qwikcity-loaders-to-load-data-2gm7"&gt;previous post&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use a QwikCity Loader with Prisma
&lt;/h4&gt;

&lt;p&gt;Prisma is set up in the app and now you can use Prisma client to retrieve data from the database or change your data. How can you do that? First create a new service file to hold all the Prisma code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient();

export async function getProducts() {
    return await prisma.products.findMany();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that I created the PrismaClient instance and then use it to query the products table in the getProducts function. Now you can use this new function inside QwikCity loader. Here is the new loader code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const useProductsLoader = loader$(async () =&amp;gt; {
  return await getProducts();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay attention to the &lt;strong&gt;async/await&lt;/strong&gt; usage here. Working with databases is being done asynchronously and we need to &lt;strong&gt;await&lt;/strong&gt; to the query to return the data and to Prisma to create the objects our of it.&lt;/p&gt;

&lt;p&gt;When you will run the app it should look exactly like in the &lt;a href="https://dev.to/gilfink/using-qwikcity-loaders-to-load-data-2gm7"&gt;previous post&lt;/a&gt;, but this time you work with a real database underneath.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F6btd8j73ikudkebz4o09.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F6btd8j73ikudkebz4o09.png" width="800" height="383"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Working App&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;QwikCity, like any other meta framework, can work with databases. In this post I showed you how to wire Prisma into QwikCity and then use the new QwikCity data loader API to load data from database to your components.&lt;/p&gt;

&lt;p&gt;I hope you will find this post helpful 😃&lt;/p&gt;

</description>
      <category>prisma</category>
      <category>qwik</category>
      <category>qwikcity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using QwikCity Loaders to Load Data</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Fri, 17 Feb 2023 14:47:33 +0000</pubDate>
      <link>https://dev.to/gilfink/using-qwikcity-loaders-to-load-data-2gm7</link>
      <guid>https://dev.to/gilfink/using-qwikcity-loaders-to-load-data-2gm7</guid>
      <description>&lt;p&gt;One of the new features that QwikCity include is the new loaders features. What is a QwikCity loader? How can you use it?&lt;/p&gt;

&lt;p&gt;In this post you will get the answers to these questions.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is a QwikCity Loader?
&lt;/h4&gt;

&lt;p&gt;A loader is a new feature that was added to QwikCity lately. A loader purpose is enable Qwik components to load data from the server in a seamless way. You don’t need to write &lt;strong&gt;fetch&lt;/strong&gt; code or use the &lt;strong&gt;XmlHttpRequest&lt;/strong&gt; object or even expose an endpoint for some piece of data. Just write a loader with the loader syntax and then you can use it as part of your component. QwikCity will do the heavy lifting of fetching the data on the server and have it ready for the component usage.&lt;/p&gt;

&lt;p&gt;Sounds great, so how can I create a loader?&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating a QwikCity Loader
&lt;/h4&gt;

&lt;p&gt;Creating a loader is as simple as to use the &lt;strong&gt;loader$&lt;/strong&gt; higher order function. The &lt;strong&gt;loader$&lt;/strong&gt; function receives a callback function that is going to be used in the server to load the data. The callback function’s returned value will be added to the consuming Qwik component and you will be able to use it when the component is mounted.&lt;/p&gt;

&lt;h4&gt;
  
  
  Loader Creation Example
&lt;/h4&gt;

&lt;p&gt;Let’s say we have a simple &lt;strong&gt;productsDB&lt;/strong&gt; file with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface Product {
  id: number;
  name: string;
  description: string;
}

export const products: Product[] = [
  {
    id: 1,
    name: "Wood Table",
    description: "A wood table",
  },
  {
    id: 2,
    name: "Plastic Table",
    description: "A plastic table",
  },
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I want to create a loader that will fetch all the products data, it might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { products } from "~/data/productsDB";

export const useProductsLoader = loader$(() =&amp;gt; {
  return products;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pay attention to the usage of the&lt;/em&gt; &lt;strong&gt;&lt;em&gt;use*&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;convention in the loader name.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that you have the loader’s code, how can you consume it from a Qwik component?&lt;/p&gt;

&lt;p&gt;This is straight forward. Just run the loader function in the component code and use the returned value.&lt;/p&gt;

&lt;h4&gt;
  
  
  Loader Usage Example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default component$(() =&amp;gt; {
  const products = useProductsLoader();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;ul&amp;gt;
        {products.value.map((product) =&amp;gt; {
          return (
            &amp;lt;li&amp;gt;
              &amp;lt;div&amp;gt;{product.name}&amp;lt;/div&amp;gt;
              &amp;lt;div&amp;gt;{product.description}&amp;lt;/div&amp;gt;
            &amp;lt;/li&amp;gt;
          );
        })}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, I use the previous loader as a function. Then, in the rendering code I use the products.value to get a hold of the products data and render them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fdg8n1q5n3acqrt1cnx8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdg8n1q5n3acqrt1cnx8g.png" width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code I showed is simple but what else can you do with a loader?&lt;/p&gt;

&lt;p&gt;Use the loader context.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Loader Context
&lt;/h4&gt;

&lt;p&gt;Loaders run in a context of a QwikCity &lt;strong&gt;RequestEvent&lt;/strong&gt;. That means you can have the request context as an argument of the callback function. What can you do with this context?&lt;br&gt;&lt;br&gt;
You can investigate the request headers, url, cookies, params and more. All this content can help you to do decisions about which data to send back and in which conditions.&lt;/p&gt;

&lt;p&gt;Let’s look at a simple usage example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const useProductsLoader = loader$(({ url, method }) =&amp;gt; {
  if (method === 'GET') {
    return { url, products };
  }
  return { url, products: [] };
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous loader was refactored to return the &lt;strong&gt;url&lt;/strong&gt; with the &lt;strong&gt;products&lt;/strong&gt; if the request was a HttpGet else to return the &lt;strong&gt;url&lt;/strong&gt; with an empty array. I know it’s something that you probably won’t do in real world scenario, but for now it’s just showing you how to use the context. In real world, you might examine the &lt;strong&gt;cookies&lt;/strong&gt; to see if a user is authenticated, check the &lt;strong&gt;params&lt;/strong&gt; for existence of some specific parameter such as an id and etc.&lt;/p&gt;

&lt;p&gt;The consuming component will need to change as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default component$(() =&amp;gt; {
  const products = useProductsLoader();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;{products.value.url.href}&amp;lt;/div&amp;gt;
      &amp;lt;ul&amp;gt;
        {products.value.products.map((product) =&amp;gt; {
          return (
            &amp;lt;li&amp;gt;
              &amp;lt;div&amp;gt;{product.name}&amp;lt;/div&amp;gt;
              &amp;lt;div&amp;gt;{product.description}&amp;lt;/div&amp;gt;
            &amp;lt;/li&amp;gt;
          );
        })}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the change is how I consume the returned value of the url and the products.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;Qwik and QwikCity are evolving and adding new features, which are very useful for developer experience with the frameworks. One of these new features is the data loader. In this post I covered what is a data loader and how to use it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you have any questions about the subject, write them in the comments section.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>qwik</category>
      <category>qwikcity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Writing Your First Qwik Component</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Sun, 16 Oct 2022 14:14:44 +0000</pubDate>
      <link>https://dev.to/gilfink/writing-your-first-qwik-component-17h3</link>
      <guid>https://dev.to/gilfink/writing-your-first-qwik-component-17h3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Focoag89cza9mug037wji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Focoag89cza9mug037wji.png" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the last few weeks I’m deep diving into &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; framework in preparation to a session I’ll deliver about it in &lt;a href="https://techradarcon.com/schedule/index.html#session-4400" rel="noopener noreferrer"&gt;TechRadarCon 2022&lt;/a&gt;. I also implemented a &lt;a href="https://github.com/gilf/the-agency-qwik" rel="noopener noreferrer"&gt;full demo app&lt;/a&gt; with Qwik and QwikCity to get the feeling about the developer experience with the framework.&lt;/p&gt;

&lt;p&gt;In this post I’m going to show you how you can develop a simple Qwik component and expose you to some things you need to know while developing your components.&lt;/p&gt;

&lt;h4&gt;
  
  
  Qwik Playground
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fx0dcfic396mlvpsezyuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fx0dcfic396mlvpsezyuc.png" width="800" height="382"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Qwik Playground&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of the nice features that is part of Qwik website is the &lt;a href="https://qwik.builder.io/playground" rel="noopener noreferrer"&gt;Qwik Playground&lt;/a&gt;. In the playground you can write components using Qwik syntax and in the right pane you can get info about the component’s rendering, errors, symbols and can even configure how things are rendered using the &lt;strong&gt;Options&lt;/strong&gt; tab at the bottom.&lt;br&gt;&lt;br&gt;
You can use the playground as the environment to build the component I’ll implement in the post or you can create a new project using Qwik CLI and add the component there.&lt;/p&gt;
&lt;h4&gt;
  
  
  Building the Component
&lt;/h4&gt;

&lt;p&gt;In this post we are going to build a simple collapsible panel component. The component will have a clickable header, which will collapse it’s content. The content will be injected from the outside.&lt;/p&gt;

&lt;p&gt;So, let’s do it :)&lt;/p&gt;

&lt;p&gt;The following code is the complete example, which will be broken to explanations later on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { component$, useStore, useStylesScoped$, $, Slot } from '@builder.io/qwik';

export const App = component$(() =&amp;gt; {
  return (
    &amp;lt;CollapsiblePanel title="Click me!"&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;Qwik is awsome&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;Collapsible item&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/CollapsiblePanel&amp;gt;
  );
});

interface IProps {
  title: string;
}

export const CollapsiblePanel = component$(({ title }: IProps) =&amp;gt; {
  useStylesScoped$(`
    .collapsible {
      border: black dashed 1px;
    }

header {
      background: blue;
      color: white;
      cursor: pointer;
      padding: 2px;
    }
  `);

const store = useStore({
    collapsed: false
  });

const toggle = $(async () =&amp;gt; {
    store.collapsed = !store.collapsed;
  });

return (
    &amp;lt;div className="collapsible"&amp;gt;
        &amp;lt;header onClick$={toggle}&amp;gt;
          {title}
        &amp;lt;/header&amp;gt;
        &amp;lt;section hidden={store.collapsed}&amp;gt;
          &amp;lt;Slot /&amp;gt;
        &amp;lt;/section&amp;gt;
      &amp;lt;/div&amp;gt;
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Let’s Break it Down
&lt;/h4&gt;

&lt;p&gt;Qwik embraces TypeScript, so at first we will create an interface for the props that the component will receive. Here is the interface implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface IProps {
  title: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have the interface, let’s use it and let’s declare the component using Qwik syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const CollapsiblePanel = component$(({ title }: IProps) =&amp;gt; {
   ...
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see you use the &lt;strong&gt;component$&lt;/strong&gt; function to create a Qwik component. The &lt;strong&gt;$&lt;/strong&gt; sign is there to direct &lt;a href="https://qwik.builder.io/docs/advanced/optimizer/" rel="noopener noreferrer"&gt;Qwik optimizer&lt;/a&gt; to treat this function in a specific way (in this case, as a Qwik component).&lt;/p&gt;

&lt;p&gt;Note: I’m not going to discuss the optimizer and I encourage you to read about it &lt;a href="https://qwik.builder.io/docs/advanced/optimizer/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we declared the component let’s implement it. Qwik uses JSX to write how you will render your component. At the end of the component we will return the following JSX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return (
    &amp;lt;div className="collapsible"&amp;gt;
        &amp;lt;header onClick$={toggle}&amp;gt;
          {title}
        &amp;lt;/header&amp;gt;
        &amp;lt;section hidden={store.collapsed}&amp;gt;
          &amp;lt;Slot/&amp;gt;
        &amp;lt;/section&amp;gt;
     &amp;lt;/div&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As can be seen, we return a &lt;strong&gt;div&lt;/strong&gt; with some implementation. I marked 3 important things in the code which you should be aware of. The &lt;strong&gt;onClick$&lt;/strong&gt; is the way we wire events in Qwik with the &lt;strong&gt;$&lt;/strong&gt; sign at the end. Again, the &lt;strong&gt;$&lt;/strong&gt; sign is there for the Qwik optimizer. The &lt;strong&gt;Slot&lt;/strong&gt; component is a special Qwik component that enables content injection into our component. We will discuss the store later on.&lt;/p&gt;

&lt;p&gt;Now let’s add some style. If you want to create a style barrier between your component and the outside you can use the &lt;strong&gt;useStylesScoped$&lt;/strong&gt; hook. The &lt;strong&gt;useStylesScoped$&lt;/strong&gt; hook receives the style you want to encapsulate inside your component and impose it on the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useStylesScoped$(`
    .collapsible {
      border: black dashed 1px;
    }

    header {
      background: blue;
      color: white;
      cursor: pointer;
      padding: 2px;
    }
`);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above we add style to the container div and to the header element. When rendered, Qwik will make sure that the style will be specific only to the component and therefore the style won’t leak from it.&lt;/p&gt;

&lt;p&gt;In order to have an inner component state, which can be serialized by Qwik you will need to use the &lt;strong&gt;useStore&lt;/strong&gt; hook. The hook creates a store that it’s content can be tracked by Qwik and also can be serialized. In the collapsible panel example the store is storing the collapsed state of the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const store = useStore({
    collapsed: false
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last but not least, we implement the &lt;strong&gt;toggle&lt;/strong&gt; function which will be used to toggle the content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const toggle = $(async () =&amp;gt; {
    store.collapsed = !store.collapsed;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the toggle function isn’t inline in the component’s JSX, you need to use the &lt;strong&gt;$(async () =&amp;gt; { … })&lt;/strong&gt; syntax to make sure that Qwik optimizer will understand that this is going to be Qwik component function that is being used in the JSX.&lt;/p&gt;

&lt;p&gt;That is it. You now can play with the component.&lt;/p&gt;

&lt;p&gt;The following code is a consuming component that runs our component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const App = component$(() =&amp;gt; {
  return (
    &amp;lt;CollapsiblePanel title="Click me!"&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;Qwik is awsome&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;Collapsible item&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/CollapsiblePanel&amp;gt;
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.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%2Fomk0n5bskoc3ybumdt1d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fomk0n5bskoc3ybumdt1d.png" width="800" height="380"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Collapsible Panel Component in Qwik Playground&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;In the post we implemented a Qwik collapsible panel component. This is a simple component but it shows some of the concepts you will need to be familiar with if you are writing Qwik components.&lt;/p&gt;

&lt;p&gt;As always, if you have any feedback, let me know.&lt;/p&gt;

</description>
      <category>qwik</category>
      <category>webdev</category>
      <category>components</category>
    </item>
    <item>
      <title>First Impression with Qwik</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Sat, 15 Oct 2022 12:43:06 +0000</pubDate>
      <link>https://dev.to/gilfink/first-impression-with-qwik-495f</link>
      <guid>https://dev.to/gilfink/first-impression-with-qwik-495f</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fvq4b6yt76pcnkjje676n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fvq4b6yt76pcnkjje676n.png" width="800" height="382"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;TheAgency app&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A few days ago I published a small demo app called “&lt;a href="https://github.com/gilf/the-agency-qwik" rel="noopener noreferrer"&gt;TheAgency&lt;/a&gt;” which I fully developed with Qwik and QwikCity. In this post I’ll explain why I did it and how it might help you if you want to get familiar with &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; and QwikCity.&lt;/p&gt;

&lt;h4&gt;
  
  
  Qwik? QwikCity?
&lt;/h4&gt;

&lt;p&gt;There is a lot of buzz around &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; lately. &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; is a new front-end framework which is being developed by &lt;a href="https://www.builder.io/" rel="noopener noreferrer"&gt;builder.io&lt;/a&gt;. In the &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; framework team you can find known web framework developers/architects such as Miško Hevery (AngularJS/Angular), Adam Bradley (Ionic/Stencil) and Manu Mtz.-Almeida (Ionic/Stencil). &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; is trying to solve some major problems that we have in current modern web development frameworks. In a nutshell the main drive behind &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; is to make your website/web app faster by changing a few mental models (the need for hydration for exmaple) and introducing the concept of resumability.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This is not going to be an “hello world” post about Qwik. I think that&lt;/em&gt; &lt;a href="https://qwik.builder.io/docs/overview/" rel="noopener noreferrer"&gt;&lt;em&gt;Qwik documentation&lt;/em&gt;&lt;/a&gt; &lt;em&gt;is doing a good job for introducing the framework.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;QwikCity is a meta framework that is built on top of Qwik and introducing a whole website/web app solution that includes routing and backend as well. With QwikCity you are able to create not only the front-end but a whole site/app.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This is also not going to be an “hello world” post about QwikCity. I think that&lt;/em&gt; &lt;a href="https://qwik.builder.io/qwikcity/overview/" rel="noopener noreferrer"&gt;&lt;em&gt;QwikCity&lt;/em&gt;&lt;/a&gt; &lt;em&gt;documentation is doing a good job for introducing the meta framework.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  How did I heard about Qwik?
&lt;/h4&gt;

&lt;p&gt;I first learned about &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; in Twitter a few months ago (I’m following Miško Hevery), but I didn’t have the time to look at it or to implement something with it. Then, Miško Hevery visited Israel a couple of months ago and conducted a &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; workshop with Shai Reznik. I managed to attend the workshop and was really impressed with the ideas behind &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt;. I also had the opportunity to learn about it from one of it’s creators. I remember that when the workshop ended I was eager to build something with &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt;, but… Life…&lt;br&gt;&lt;br&gt;
I had no opportunity to do that because all my customers work with React and I had limited spare time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why to Build “TheAgency”?
&lt;/h4&gt;

&lt;p&gt;Three weeks ago one of my customers, a startup, had to close the company :( and I had some spare time to waste before I’ll have a new customer. So, I decided that I want to build something with Qwik and QwikCity and to have the feeling about how you can build a more realistic real world app and not some small demo app such as a todo list.&lt;/p&gt;

&lt;p&gt;This is where I had the idea to take the app I built when I wrote my “&lt;a href="https://www.amazon.com/Pro-Single-Page-Application-Development/dp/1430266732" rel="noopener noreferrer"&gt;Pro Single Page Application Development&lt;/a&gt;” book and migrate it entirely to &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; and QwikCity. The “TheAgency” app was created in 2014 with Backbone.js and ASP.NET.&lt;/p&gt;

&lt;p&gt;Migrating an app that was built in an old library such as Backbone.js wasn’t so easy. At first I created all the views with their HTML and CSS and then I wired everything inside QwikCity including routing. I had to learn how to use &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; and let it do it’s magic during the process. There were a few qwirks that I had to overcome. Mostly, things that aren’t documented or don’t work as expected (for example how to wire the Web API in QwikCity or serialization/deserialization of objects when you pass content to the server). All in all it took me a couple of hours but I managed to do the migration.&lt;/p&gt;

&lt;p&gt;One thing that I must emphasize — because I learned everything by implementation, I might not write an optimized app version in terms of how I implemented it. If you are using my example app as a reference, I’ll be happy to learn if you can do things better than I did.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;The main question you probably ask yourself is whether I’ll use &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; after I had the experience with it?&lt;br&gt;&lt;br&gt;
Of course. Even though there are things to improve in the framework I find it very interesting and revolutionary in it’s mental model. I also think that the framework is heading in a right direction.&lt;/p&gt;

&lt;p&gt;My hope is that the app I created will help others to understand how to create modern apps with &lt;a href="https://qwik.builder.io/" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; and QwikCity.&lt;/p&gt;

&lt;p&gt;Feedback is always welcome!&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>webappdevelopment</category>
      <category>webframework</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Quick Tip — Storybook Play Function</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Sun, 11 Sep 2022 09:14:16 +0000</pubDate>
      <link>https://dev.to/gilfink/quick-tip-storybook-play-function-4ik9</link>
      <guid>https://dev.to/gilfink/quick-tip-storybook-play-function-4ik9</guid>
      <description>&lt;h3&gt;
  
  
  Quick Tip — Storybook Play Function
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fr4nb6sp5ijsznnq3rv6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fr4nb6sp5ijsznnq3rv6e.png" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook&lt;/a&gt; is a go to tool that a lot of developers are using as a lab environment to the components they are creating. Storybook renders the components and then enable to interact with them, change their props and see the outcome of the changes.&lt;/p&gt;

&lt;p&gt;But sometime you might want to simulate user interactions or use some exposed component API after the component was rendered. How can you do that?&lt;/p&gt;

&lt;p&gt;In this short post you will get familiar with Storybook &lt;strong&gt;play&lt;/strong&gt; function, which enables you to hook operations after the component was rendered.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Play Function
&lt;/h4&gt;

&lt;p&gt;Storybook stories can help developers to test their components in a lab environment. When you want to simulate interaction with your component or use a function which was exposed from you component, you will want to hook the &lt;strong&gt;play&lt;/strong&gt; function to your template instance.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;play&lt;/strong&gt; function is a hook that enables you to interact with the component after it was rendered. Before you can use it, you need to make sure that Storybook’s &lt;strong&gt;addon-interactions&lt;/strong&gt; is installed. Another package that you might want to install is &lt;strong&gt;@storybook/testing-library&lt;/strong&gt; , which can help you to work with Storybook exposed DOM. If the packages aren’t installed, run the following command in your command line in the root folder of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install — save-dev @storybook/addon-interactions @storybook/testing-library
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the packages are installed, you should make sure that the &lt;strong&gt;addon-interactions&lt;/strong&gt; addon is added to the list of addons in the  &lt;strong&gt;.storybook/main.js&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  stories:[],
  addons:[
    '@storybook/addon-interactions'
  ]
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that everything is in place let’s see how you can use the &lt;strong&gt;play&lt;/strong&gt; function inside a stories file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Play Function in Action
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;play&lt;/strong&gt; function is added to the instance of a Storybook template like adding stories  &lt;strong&gt;args&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { screen } from '@storybook/testing-library';

... // some story definitions

export const Default = Template.bind({});
Default.play = async () =&amp;gt; {
  screen.getByTestId("someElementTestId").show('hello storybook');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to notice in this small example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Play can have asynchronous interactions and therefore I use the &lt;strong&gt;async&lt;/strong&gt; keyword. In this example there are no awaits but there could be (for example awaiting to simulated user interactions).&lt;/li&gt;
&lt;li&gt;I use the &lt;strong&gt;screen&lt;/strong&gt; object from the &lt;strong&gt;@storybook/testing-library&lt;/strong&gt; to grab an element by it’s test id. You should make sure the element indeed has a test id like the one that was used otherwise you will get an error.&lt;/li&gt;
&lt;li&gt;Once I have the element after it was queried from the DOM, I can interact with it. In this example I call an exposed API function called  &lt;strong&gt;show&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This example is very easy and you can definitely do some sophisticated things such as running user events (click, typing and etc.) using the testing library API, compose more than one story and more.&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;In the post you learned about the &lt;strong&gt;play&lt;/strong&gt; function in Storybook. The &lt;strong&gt;play&lt;/strong&gt; function is a very handy hook that enables you to “play” user interactions or component exposed API functions after the component was rendered in Storybook preview section.&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to write them in the comments section.&lt;/p&gt;

</description>
      <category>tips</category>
      <category>storybook</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Creating a Force Graph using React, D3 and PixiJS</title>
      <dc:creator>Gil Fink</dc:creator>
      <pubDate>Sun, 07 Mar 2021 08:42:28 +0000</pubDate>
      <link>https://dev.to/gilfink/creating-a-force-graph-using-react-d3-and-pixijs-182n</link>
      <guid>https://dev.to/gilfink/creating-a-force-graph-using-react-d3-and-pixijs-182n</guid>
      <description>&lt;p&gt;A few months ago I published a post about how to &lt;a href="https://dev.to/gilfink/creating-a-force-graph-using-react-and-d3-jpg-temp-slug-2341904"&gt;create a force graph using React and D3&lt;/a&gt;. But what if the force graph data source is enormous? Would you still use D3 or are there any other solutions out there?&lt;br&gt;&lt;br&gt;
In this post I’ll explain how you can combine both D3 and PixiJS to create almost the same force graph but in a different way which will enable you to support bigger data sources.&lt;/p&gt;

&lt;p&gt;In the app we created we faced a very painful performance problem. While D3 helped us to create the relevant force graph we needed to show on screen, the data source we were using became very large. When using D3, the graph representation underneath is created using SVG and that means that when the data source becomes larger the amount of SVG elements increase. The more SVG elements you have on screen the less performant the app becomes.&lt;/p&gt;

&lt;p&gt;So, how can we solve the problem? What if we could transfer D3 SVG representation into canvas representation. Would that help?&lt;br&gt;&lt;br&gt;
In our app it helped.&lt;/p&gt;
&lt;h4&gt;
  
  
  Enter PixiJS
&lt;/h4&gt;

&lt;p&gt;PixiJS is a flexible 2D WebGL renderer library which is working on top of HTML5 canvas element.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note - I won’t get into PixiJS fundamentals in this post and I encourage you to go to it’s&lt;/em&gt; &lt;a href="https://www.pixijs.com/" rel="noopener noreferrer"&gt;&lt;em&gt;website&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for further reading.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In a whole what I did was to use the D3 force graph simulation on one hand to keep the force graph simulation and I let PixiJS handle all the rendering on top of the canvas element.&lt;/p&gt;
&lt;h4&gt;
  
  
  Creating the Example App
&lt;/h4&gt;

&lt;p&gt;I’m going to refactor a little bit the app I created in the “&lt;a href="https://dev.to/gilfink/creating-a-force-graph-using-react-and-d3-jpg-temp-slug-2341904"&gt;Creating a Force Graph using React and D3&lt;/a&gt;” post. That means that if you haven’t read it go ahead and do that before you continue reading this post.&lt;/p&gt;

&lt;p&gt;First you will need to install PixiJS library. In command line run the following code to install both PixiJS and PixiJS Viewport, which will help us to support things like zoom in and out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i pixi.js pixi-viewport
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After the libraries are installed we are ready to proceed.&lt;/p&gt;

&lt;p&gt;I’ll use the same &lt;strong&gt;ForceGraph&lt;/strong&gt; component container I created in the previous post, but this time I’ll use the &lt;strong&gt;runForceGraphPixi&lt;/strong&gt; function instead of &lt;strong&gt;runForceGraph&lt;/strong&gt;. &lt;strong&gt;runForceGraphPixi&lt;/strong&gt; will be responsible to create and run the new force graph.&lt;/p&gt;
&lt;h4&gt;
  
  
  Building the Force Graph Generator
&lt;/h4&gt;

&lt;p&gt;The force graph generator will be a function that will be responsible to generate the graph. Here is the declaration of the function which gets the containing div, the data for links and nodes and a function to generate a node tooltip:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;You can see that I import both D3 and PixiJS and I use the same signature that I used in &lt;strong&gt;runForceGraph&lt;/strong&gt; from the previous post. Now let’s implement the function.&lt;/p&gt;

&lt;p&gt;The first lines of code will be to copy the data and to get the container’s &lt;strong&gt;width&lt;/strong&gt; and  &lt;strong&gt;height&lt;/strong&gt; :&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I also add a variable I’ll use later to control the nodes drag and drop and clean the container from it’s previously generated HTML content.&lt;/p&gt;

&lt;p&gt;Then, let’s add a few helper functions:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The helper functions will help us to add the tooltip, to support the coloring of the nodes and also to create the drag and drop functionality.&lt;/p&gt;

&lt;p&gt;Now we add the code that will create the nodes and their links and will simulate the force graph:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Pay attention that I add both a &lt;strong&gt;Pixi.Applicaiton&lt;/strong&gt; and also &lt;strong&gt;d3.forceSimulation&lt;/strong&gt;. The PixiJS application will be responsible for the graph rendering according to the force simulation that D3 exposes.&lt;/p&gt;

&lt;p&gt;When the graph is ready we will add a few event handlers to handle what is going to happen when the tick is happening :&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the tick event we clean all the links and then redraw them on the canvas again.&lt;/p&gt;

&lt;p&gt;Last but not least, we will return the destroy function that the graph container is going to use when it’s going to unmount the graph:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The whole function source code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now that everything is set in place you can run the app and look at your fancy force graph.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fq6up5kaiin8kc1k76sox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fq6up5kaiin8kc1k76sox.png" width="800" height="375"&gt;&lt;/a&gt;The Generated Force Graph&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In the post, I showed you how to create a force graph component using &lt;strong&gt;React, D3&lt;/strong&gt; and &lt;strong&gt;PixiJS&lt;/strong&gt; libraries. You can find the graph code &lt;a href="https://onedrive.live.com/?authkey=%21AL75phd8K0DQDgs&amp;amp;id=CC807E0FCC4169F4%2137455&amp;amp;cid=CC807E0FCC4169F4" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>pixijs</category>
      <category>webdev</category>
      <category>d3js</category>
      <category>react</category>
    </item>
  </channel>
</rss>
