<?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>Forem: Bernardo Pacheco</title>
    <description>The latest articles on Forem by Bernardo Pacheco (@bernardop).</description>
    <link>https://forem.com/bernardop</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%2F21939%2Fa7a30389-2a65-4cbe-8b15-c711f3575953.jpg</url>
      <title>Forem: Bernardo Pacheco</title>
      <link>https://forem.com/bernardop</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bernardop"/>
    <language>en</language>
    <item>
      <title>Introducing VS Code Working Sets 💼</title>
      <dc:creator>Bernardo Pacheco</dc:creator>
      <pubDate>Tue, 21 Apr 2020 20:05:43 +0000</pubDate>
      <link>https://forem.com/bernardop/introducing-vs-code-working-sets-3a61</link>
      <guid>https://forem.com/bernardop/introducing-vs-code-working-sets-3a61</guid>
      <description>&lt;p&gt;Picture this, you're happily coding an awesome feature for your product and you have a few VS Code tabs open specific to that feature. Suddenly, you receive a message, there is a bug in a totally unrelated part of the site and you need to investigate. You start opening new files as you debug the issue, next thing you know you have 37 tabs open. You fixed the bug (nice job!), but now you want to go back to your awesome feature and there's a lot of clutter, you start closing one-by-one the unrelated tabs until your editor is back to the state it was before the bug.&lt;/p&gt;

&lt;p&gt;Does that sound familiar? Have you ever been in that situation before? Wouldn't it be nice if you could "save" the files related to your awesome feature, work on your bug, and then come back to your saved files with just a few clicks?&lt;/p&gt;

&lt;p&gt;Well, I wrote a VS Code extension that allows you to do just that. I call it &lt;a href="https://marketplace.visualstudio.com/items?itemName=bernardop.working-sets" rel="noopener noreferrer"&gt;Working Sets&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Working Sets?
&lt;/h2&gt;

&lt;p&gt;The idea is simple--a way to manage and organize groups of resources--but is not new. Other editors like &lt;a href="https://help.eclipse.org/2019-12/index.jsp?topic=%2Forg.eclipse.platform.doc.user%2Fconcepts%2Fcworkset.htm" rel="noopener noreferrer"&gt;Eclipse&lt;/a&gt; and &lt;a href="https://nuclide.io/docs/features/working-sets/" rel="noopener noreferrer"&gt;Facebook's Nuclide&lt;/a&gt; offer versions of this concept. The VS Code team has &lt;a href="https://github.com/microsoft/vscode/issues/9498" rel="noopener noreferrer"&gt;discussed&lt;/a&gt; &lt;a href="https://github.com/microsoft/vscode/issues/13951" rel="noopener noreferrer"&gt;this&lt;/a&gt; &lt;a href="https://github.com/microsoft/vscode/pull/87666" rel="noopener noreferrer"&gt;before&lt;/a&gt; too. And although they may offer a baked-in solution in the near future, I still wanted to share my take on it. I've wanted to contribute to open source for a while and I thought this was the perfect opportunity.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&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%2Fi%2F9d26gnjbhpde6tnbqhxp.gif" 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%2Fi%2F9d26gnjbhpde6tnbqhxp.gif" alt="VS Code Working Sets demo" width="1174" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a nutshell, it shows a new sidebar view where you'll have access to all your saved working sets. From there you can create, restore and delete them as well as add/remove files from them. You can find more details on the extension &lt;a href="https://marketplace.visualstudio.com/items?itemName=bernardop.working-sets" rel="noopener noreferrer"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I would love for you to take it for a spin and let me know what you think.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=bernardop.working-sets" rel="noopener noreferrer"&gt;VS Code Working Sets&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/photos/bqzLehtF8XE" rel="noopener noreferrer"&gt;Russ Ward&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>vscode</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
    <item>
      <title>Exploring the Broadcast Channel API</title>
      <dc:creator>Bernardo Pacheco</dc:creator>
      <pubDate>Thu, 20 Feb 2020 19:59:05 +0000</pubDate>
      <link>https://forem.com/bernardop/exploring-the-broadcast-channel-api-i57</link>
      <guid>https://forem.com/bernardop/exploring-the-broadcast-channel-api-i57</guid>
      <description>&lt;p&gt;You know those digital menu boards that you see at quick service restaurants? Well, last year I got to work on one of those.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ok, but what does that have to do with the Broadcast Channel API?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A little bit of background
&lt;/h2&gt;

&lt;p&gt;In our particular case, the menu board is a React web app running in a Chromebox at the restaurant. It supports two displays and we control which page of the menu it shows based on the URL route.&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%2Fi%2F5kqsbigjs5wu3h5lvlit.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%2Fi%2F5kqsbigjs5wu3h5lvlit.png" alt="Two Browser windows showing different menu pages" width="644" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the requirements was that we needed to animate certain elements in the menu, but there was a catch. The animations &lt;em&gt;had&lt;/em&gt; to be synchronized across the displays. We couldn't just fire up the animation loop whenever we wanted. We needed a way for the two pages to communicate with each other to start their timers at the same time. &lt;/p&gt;

&lt;p&gt;Enter the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API" rel="noopener noreferrer"&gt;Broadcast Channel API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Broadcast Channel API?
&lt;/h2&gt;

&lt;p&gt;It is a Web API that allows basic communication between browsing contexts (i.e. windows, tabs, iframes, webviews) on the same origin.&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%2Fi%2Fw1c7a961fq57lxoflzk4.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%2Fi%2Fw1c7a961fq57lxoflzk4.png" alt="Two browser windows communicating through a broadcast channel" width="672" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You start by creating a &lt;code&gt;BroadcastChannel&lt;/code&gt; object and giving it a name. If a channel with the same name already exists, it will join the channel instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BroadcastChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;channel_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To send a message you call the &lt;code&gt;postMessage()&lt;/code&gt; method on the created object, which takes any object as an argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is this thing on?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will dispatch a &lt;code&gt;message&lt;/code&gt; event to each of the contexts that have joined the channel. We can then run a function for this event with the &lt;code&gt;onmessage&lt;/code&gt; event handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// is this thing on?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To disconnect from the channel you call the &lt;code&gt;close()&lt;/code&gt; method on the object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Back to our app
&lt;/h2&gt;

&lt;p&gt;We were able to leverage this API to communicate back and forth between the two displays and make sure they start their animation loop exactly at the same time. Keep in mind that each display "boots up" independently at slightly different times, so we need some negotiation up front to know when both of them are ready.&lt;/p&gt;

&lt;p&gt;The basic logic looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * In this example I will refer to the first display to finish 
 * booting up as "display 1". The second one to be ready will
 * be "display 2".
 */&lt;/span&gt;

&lt;span class="c1"&gt;// display 1 creates the channel; display 2 joins it&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BroadcastChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;animation-sync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;syncChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// display 1 receives the "READY" message from display 2&lt;/span&gt;
    &lt;span class="c1"&gt;// and posts a message to start setting things up&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;READY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;syncChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;START&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// display 2 receives the "START" message&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;START&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// record the current time (just to be safe we pad it 5s&lt;/span&gt;
      &lt;span class="c1"&gt;// to allow display 1 to receive the next message)&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;

      &lt;span class="c1"&gt;// outside function that schedules the animations&lt;/span&gt;
      &lt;span class="nf"&gt;scheduleAnimations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;// send "SYNC" message to display 1 with the syncTime      &lt;/span&gt;
      &lt;span class="nx"&gt;syncChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SYNC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;syncTime&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// display 1 receives the "SYNC" message with the syncTime&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SYNC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;scheduleAnimations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;syncTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// display 2 sends the "READY" message to display 1&lt;/span&gt;
&lt;span class="nx"&gt;animationSyncChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;READY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Play with it
&lt;/h2&gt;

&lt;p&gt;I made &lt;a href="https://codesandbox.io/s/react-broadcast-channel-api-84en5?fontsize=14&amp;amp;theme=dark" rel="noopener noreferrer"&gt;a simplified demo of this&lt;/a&gt; in Codesandbox. And here's a short preview of it:&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%2Fi%2Fdrmkrizbr0x2nnamt4v1.gif" 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%2Fi%2Fdrmkrizbr0x2nnamt4v1.gif" alt="Animated gif of two browser windows showing a synchronized timer" width="613" height="726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty cool, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveat
&lt;/h2&gt;

&lt;p&gt;Not every browser supports this natively. Fortunately, there's a npm package called &lt;a href="https://www.npmjs.com/package/broadcast-channel" rel="noopener noreferrer"&gt;broadcast-channel&lt;/a&gt; that has the same API and uses the native implementation in browsers that support it. Plus, it allows you to use it in Node too!&lt;/p&gt;




&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/photos/LeZItQhwFks" rel="noopener noreferrer"&gt;Prince Abid&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
