<?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: Justin Ribeiro</title>
    <description>The latest articles on Forem by Justin Ribeiro (@justinribeiro).</description>
    <link>https://forem.com/justinribeiro</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%2F244761%2F8e905dd4-a16f-43bf-8a58-99a13d0d7839.jpeg</url>
      <title>Forem: Justin Ribeiro</title>
      <link>https://forem.com/justinribeiro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/justinribeiro"/>
    <language>en</language>
    <item>
      <title>Faster YouTube embeds with lite-youtube web component</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Mon, 18 Nov 2019 22:47:41 +0000</pubDate>
      <link>https://forem.com/justinribeiro/faster-youtube-embeds-with-lite-youtube-web-component-788</link>
      <guid>https://forem.com/justinribeiro/faster-youtube-embeds-with-lite-youtube-web-component-788</guid>
      <description>&lt;p&gt;I was puttering around Github at the end of last week and I stumbled upon Paul Irish’s &lt;a href="https://github.com/paulirish/lite-youtube-embed"&gt;lite-youtube-embed&lt;/a&gt;. I heart the things that Paul comes up with and in the run around with Chrome Dev Summit and what not last week, I had likely missed it (and as of this writing, it’s come a long way since I saw it on Friday in a single html file).&lt;/p&gt;

&lt;p&gt;What I really was intrigued about was the numbers: it was fast. Having been embedding YouTube videos in some of my posts recently, I wanted more speed as the YouTube embeds weren’t exactly blazing fast in my traces. So I decided I’d go a bit of a different direction than Paul and build a ShadowDOM version of the component (since Paul was going to only build the custom element version, I didn’t want to pester him with a shadowDOM argument in his issue tracker).&lt;/p&gt;

&lt;p&gt;My encapsulated and responsive version is now available on NPM at &lt;a href="https://www.npmjs.com/package/@justinribeiro/lite-youtube"&gt;@justinribeiro/lite-youtube&lt;/a&gt;, recently updated to version 0.3.1. Primary features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No dependencies; it’s just a vanilla web component.&lt;/li&gt;
&lt;li&gt;It’s fast yo.&lt;/li&gt;
&lt;li&gt;It’s Shadow Dom encapsulated!&lt;/li&gt;
&lt;li&gt;It’s responsive 16:9&lt;/li&gt;
&lt;li&gt;It’s accessible via keyboard and will set ARIA via the &lt;code&gt;videotitle&lt;/code&gt; attribute&lt;/li&gt;
&lt;li&gt;It’s locale ready; you can set the &lt;code&gt;videoplay&lt;/code&gt; to have a properly locale based label&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To use, you can install it via npm or yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @justinribeiro/lite-youtube # or yarn add @justinribeiro/lite-youtube
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or you can just include is directly with JSDelivr:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\&amp;lt;script type="module" src="https://cdn.jsdelivr.net/npm/@justinribeiro/lite-youtube@0.3.1/lite-youtube.js"\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;From there, just include it your page with the &lt;code&gt;videoid&lt;/code&gt; and &lt;code&gt;videotitle&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\&amp;lt;lite-youtube videoid="guJLfqTFfIw" videotitle="Sample output of devtools-to-video cli tool"\&amp;gt; \&amp;lt;/lite-youtube\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;p&gt;If you’d like to contribute or find an issue, the &lt;a href="https://github.com/justinribeiro/lite-youtube"&gt;project is available on Github&lt;/a&gt; or if you’re looking for the non-ShadowDOM version, do check out Paul’s &lt;a href="https://github.com/paulirish/lite-youtube-embed"&gt;repo&lt;/a&gt; and pending NPM package as well.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>youtube</category>
    </item>
    <item>
      <title>Fail a PR based on any audit score with v1.1.0 of Web Performance Audits with Lighthouse Github Action</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Wed, 06 Nov 2019 18:09:03 +0000</pubDate>
      <link>https://forem.com/justinribeiro/fail-a-pr-based-on-any-audit-score-with-v1-1-0-of-web-performance-audits-with-lighthouse-github-action-1bak</link>
      <guid>https://forem.com/justinribeiro/fail-a-pr-based-on-any-audit-score-with-v1-1-0-of-web-performance-audits-with-lighthouse-github-action-1bak</guid>
      <description>&lt;p&gt;While the budget.json support in my &lt;a href="https://github.com/marketplace/actions/web-performance-audits-with-lighthouse"&gt;Web Performance Audits with Lighthouse Github Action&lt;/a&gt; was a good start point for many folks already using budgets, there was just something missing from it. How can I check and fail a pull request based on a specific audit or an overall category score?&lt;/p&gt;

&lt;p&gt;I thought about this for some time and weighted the options. I could make Github Action input variables that allow setting, but that seemed rather convoluted and restrictive. I could come up with my own specific JSON file, but that too seemed ill conceived. What I settled on was the old adage dance with the one that brought; why not use the data model for Lighthouse?&lt;/p&gt;

&lt;p&gt;With that, v1.1.0 introduces a new input, &lt;code&gt;lighthouseScoringBudget&lt;/code&gt; that takes a file I call scores.js.&lt;/p&gt;

&lt;p&gt;scores.js is based on the Lighthouse JSON output data model and maps one-to-one with the existing keys and definitions within lighthouse. This allows an easy to use, vastly configurable file to test any audit score or raw numeric value that you find important.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = { audits: { 'service-worker': { score: 1, }, 'first-contentful-paint': { score: 1, numericValue: 100, }, 'first-meaningful-paint': { score: 1, numericValue: 100, }, }, categories: { performance: { score: 0.95, }, accessibility: { score: 0.95, }, },};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;No having to wait for me to add special parameters and easily comparable to the standard out from a JSON run of lighthouse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ lighthouse --output json --output-path=./sample.json --chrome-flags="--headless" https://YOUR\_URL\_HERE.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Just pop open that JSON file, determine what audits or categories are important to you, and start failing those pull requests at will.g sb&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ao-tPlf7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191106-github-action-scores-800.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ao-tPlf7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191106-github-action-scores-800.png" alt="scores.js in action as a PR comment"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;In the current iteration of this feature, we can test for either one or two specific keys:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;score&lt;/code&gt;: decimal ranging from 0 to 1. If you wanted to verify that your performance is above 95, you’d enter 0.95 like above.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;numericValue&lt;/code&gt;: decimal starting at zero. Commonly holds the value out of the trace in milliseconds, good for testing if you want those raw performance numbers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s all for now; stay tuned for more features. As always, &lt;a href="https://github.com/justinribeiro/lighthouse-action"&gt;PRs and issues are welcome&lt;/a&gt;. Now go trace a site and let’s make the web fast!&lt;/p&gt;

</description>
      <category>lighthouse</category>
      <category>webperf</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Web Performance Audits with Lighthouse for Github Actions Released</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Sat, 02 Nov 2019 23:37:27 +0000</pubDate>
      <link>https://forem.com/justinribeiro/web-performance-audits-with-lighthouse-for-github-actions-released-14h0</link>
      <guid>https://forem.com/justinribeiro/web-performance-audits-with-lighthouse-for-github-actions-released-14h0</guid>
      <description>&lt;p&gt;I’m just going to say it: I can pretty much integrate &lt;a href="https://github.com/GoogleChrome/lighthouse"&gt;Lighthouse&lt;/a&gt; anywhere. I’ve put in &lt;a href="https://github.com/justinribeiro/lighthouse-jest-example"&gt;tests&lt;/a&gt;, I’ve written it into &lt;a href="https://justinribeiro.com/chronicle/2018/06/26/running-lighthouse-audits-in-vs-code-via-tasks/"&gt;Visual Studio code tasks&lt;/a&gt;, I’ve wired it into &lt;a href="https://hub.docker.com/r/justinribeiro/lighthouse/"&gt;docker&lt;/a&gt;, I made it dance at &lt;a href="https://stickmanventures.com/blog/2016/11/21/demonstrating-web-performance-at-chrome-dev-summit-2016/"&gt;Chrome Dev Summit on giant screens as a game&lt;/a&gt;, I’ve even made a &lt;a href="https://github.com/GoogleChrome/lighthouse/pulls?q=is%3Apr+author%3Ajustinribeiro+is%3Aclosed"&gt;few commits here and there&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Which is to say, I &lt;em&gt;really&lt;/em&gt; like lighthouse. It’s a useful tool that I wish more developers would use. It’s one reason I keep writing integrations and examples, hoping that more buy-in for web performance is always just around the next corner.&lt;/p&gt;

&lt;p&gt;In today’s case, I’m releasing &lt;a href="https://github.com/marketplace/actions/web-performance-audits-with-lighthouse"&gt;Web Performance Audits with Lighthouse&lt;/a&gt;, a new Github Action that has a number of nifty features that I hope folks will enjoy.&lt;/p&gt;

&lt;p&gt;The biggest feature takes a page from the &lt;a href="https://github.com/GoogleChromeLabs/lighthousebot"&gt;lighthousebot style for Travis&lt;/a&gt; and injects a comment with the audit results right onto your pull request:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T0-DkzAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191102-github-action-lh-800.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T0-DkzAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191102-github-action-lh-800.png" alt="Lighthouse audit results right on your pull request!"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;If you’re looking at the screenshot and wondering “wait, budget.json fails?”, you’d be correct. You can use your existing &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/budgets"&gt;budget.json for Lighthouse&lt;/a&gt; (which you’re already using on the CLI right?) right into your configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Audit Web Performance on: [pull\_request] jobs: perf: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Generate Lighthouse Report uses: justinribeiro/lighthouse-action@v1.0.1 with: with: secret: ${{ secrets.GITHUB\_TOKEN }} url: https://justinribeiro.com/ wptConnectionSpeed: threegfast lighthouseBudget: .github/test/budget.json - name: Saving Lighthouse Audit Artifacts uses: actions/upload-artifact@master with: name: lighthouse-artifacts path: './results'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The full feature list includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;a href="https://github.com/GoogleChrome/puppeteer"&gt;Puppeteer&lt;/a&gt; to start up Chrome with &lt;a href="https://github.com/WPO-Foundation/webpagetest/blob/master/www/settings/connectivity.ini.sample"&gt;network emulation settings defined by WebPageTest&lt;/a&gt;. This is similar connection setup to my existing &lt;a href="https://github.com/justinribeiro/lighthouse-jest-example"&gt;lighthouse-jest-example&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Supports saving of artifacts to the Github Action run.&lt;/li&gt;
&lt;li&gt;Supports custom Lighthouse configuration via JavaScript file.&lt;/li&gt;
&lt;li&gt;Supports Lighthouse budget.json for failing PRs.&lt;/li&gt;
&lt;li&gt;Posts results of audit run as a comment on your PR.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see an example of this action in an actual Github workflow, you can see it in use in my &lt;a href="https://github.com/justinribeiro/blog-pwa/blob/master/.github/workflows/main.yml"&gt;blog-pwa repo&lt;/a&gt; where I’m using it to test site changes on deployments of PRs to Google App Engine.&lt;/p&gt;

&lt;p&gt;You can get started using the action today via the &lt;a href="https://github.com/marketplace/actions/web-performance-audits-with-lighthouse"&gt;marketplace&lt;/a&gt;. The &lt;a href="https://github.com/justinribeiro/lighthouse-action"&gt;repo is also available&lt;/a&gt; and happy to accept feature requests and pulls, so let me know what you’re thinking. I’ve written this as simply and straight forward as I could think of, so if you’re looking to understand a little how it all works, this example is a great way to dive in.&lt;/p&gt;

&lt;p&gt;If you happen to be at &lt;a href="https://developer.chrome.com/devsummit/"&gt;Chrome Dev Summit&lt;/a&gt; this month, find me and we’ll chat about all things Lighthouse, all things web performance.&lt;/p&gt;

&lt;p&gt;Now get out there and start testing even more of your deployments and let’s make the web fast!&lt;/p&gt;

</description>
      <category>lighthouse</category>
      <category>webperf</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Six Months Using Firebase Web Performance Monitoring</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Mon, 28 Oct 2019 14:46:28 +0000</pubDate>
      <link>https://forem.com/justinribeiro/six-months-using-firebase-web-performance-monitoring-pnl</link>
      <guid>https://forem.com/justinribeiro/six-months-using-firebase-web-performance-monitoring-pnl</guid>
      <description>&lt;p&gt;When &lt;a href="https://firebase.googleblog.com/2019/05/whats-new-Google-IO-2019.html" rel="noopener noreferrer"&gt;Firebase announced earlier this year&lt;/a&gt; that they were bringing real user monitoring of web performance into their stack of tools, I was ecstatic. Another tool to track what real users in the wild are experiencing with an easy setup? Yes, please.&lt;/p&gt;

&lt;p&gt;Initially, I heard similar shared excitement. Now six months on since it was announced I can find very little chatter about it, and I’ve not run into anyone who’s tried it.&lt;/p&gt;

&lt;p&gt;You’re in luck internet: I’ve been using Firebase web perf tracking since June on this very blog. Let’s take a look at the good, the bad, and the downright confusing portions of the Firebase web performance monitoring beta.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Good
&lt;/h2&gt;

&lt;p&gt;From the onset, Firebase web performance isn’t there to destroy your existing web performance. The library can be invoked with only the web performance tracking and not load anything related to the database or other Firebase-related products. This may seem like common sense, but then again, the third party web resource community is not exactly known for their &lt;a href="https://github.com/patrickhulce/third-party-web" rel="noopener noreferrer"&gt;light touch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While there are &lt;a href="https://firebase.google.com/docs/perf-mon/get-started-web" rel="noopener noreferrer"&gt;many setups&lt;/a&gt; outlined in the docs, I delay loading the library even further with no detrimental effect. I do load the &lt;a href="https://github.com/GoogleChromeLabs/first-input-delay" rel="noopener noreferrer"&gt;first input delay polyfill&lt;/a&gt; early on page load however (which is the same way I use it when tracking performance with tools like Google Analytics).&lt;/p&gt;

&lt;p&gt;From a collection of numbers standpoint, you literally have no code to write beyond the invoke. Install script, verify it’s sending data, wait for numbers to appear in the panel:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstorage.googleapis.com%2Fjdr-public-imgs%2Fblog%2F20191029-firebase-webperf-01-800.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstorage.googleapis.com%2Fjdr-public-imgs%2Fblog%2F20191029-firebase-webperf-01-800.png" alt="The Firebase Performance panel in the console for this blog."&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;In the screenshot above, we’re looking at three months worth of data from the entire domain. This paints a rather nice picture of performance for both the entire site and the specific blog-entry path, though we need to keep in mind we’re only looking at the median. All the action is in the tails when it comes to performance problems.&lt;/p&gt;

&lt;p&gt;If we dive into a particular route, we can get a larger picture of our web performance.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstorage.googleapis.com%2Fjdr-public-imgs%2Fblog%2F20191029-firebase-webperf-02-800.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstorage.googleapis.com%2Fjdr-public-imgs%2Fblog%2F20191029-firebase-webperf-02-800.png" alt="The Firebase Performance panel for on device metrics in the console for this blog."&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;These are the default performance numbers that Firebase Performance SDK will collect for the web. They’ll all probably look familiar if you’ve run a Lighthouse audit or looked a DevTools trace. Good numbers to have generally. Unfortunately, all is not great when it comes to those numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bad
&lt;/h2&gt;

&lt;p&gt;While it’s easy to collect numbers the further we dive into the numbers the more difficult it is to actually find actionable data. Actionable data is on the tail, where load times and potential bottlenecks within our web app code could be causing users on certain devices or networks problems. We want the bad cases so we can create fixes.&lt;/p&gt;

&lt;p&gt;Let’s take for instance the last three months of First Paints:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstorage.googleapis.com%2Fjdr-public-imgs%2Fblog%2F20191029-firebase-webperf-03-800.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstorage.googleapis.com%2Fjdr-public-imgs%2Fblog%2F20191029-firebase-webperf-03-800.png" alt="Looking at First Paint metrics in Firebase Performance panel."&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;We can move around to see the various percentiles by hovering over the graphs, but we really can’t dive into that tail to see the number of loads or other cross section of information when it comes to what’s going on with these users.&lt;/p&gt;

&lt;p&gt;If we filter down into a single country, in the case below India, we see similar tools and not much more information. Shifting the trend over time doesn’t really paint us a better picture, leaving us to guess as to why and how that segment of data might have come to be.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstorage.googleapis.com%2Fjdr-public-imgs%2Fblog%2F20191029-firebase-webperf-04-800.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstorage.googleapis.com%2Fjdr-public-imgs%2Fblog%2F20191029-firebase-webperf-04-800.png" alt="Looking at First Paint metrics for India in Firebase Performance panel."&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Just export the data and process it you say? I agree, we should do that. Should be the opportune word.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Downright Confusing
&lt;/h2&gt;

&lt;p&gt;While the data segmentation tools are not great, the more confusing part is the data itself. While the documentation makes note that you can &lt;a href="https://firebase.google.com/docs/perf-mon/bigquery-export" rel="noopener noreferrer"&gt;export the data into BigQuery&lt;/a&gt;, doing so doesn’t expose the collected data for web performance. The entire dataset is empty and without this working there’s no way to dig into or export the data into other tools.&lt;/p&gt;

&lt;p&gt;This is further compounded because you an only see up to the last three months of data within the web UI. My hope is that this is just a case of “it’s a beta, we haven’t enabled all this yet”.&lt;/p&gt;

&lt;p&gt;Then there is the question of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API" rel="noopener noreferrer"&gt;User Timing API&lt;/a&gt;. I love this API and use it a lot, as the marks and measures surface in my Lighthouse reports and many other custom tools I’ve written. Turns out the Firebase Performance SDK does support them, allowing you to use standard &lt;code&gt;performance.mark&lt;/code&gt; and &lt;code&gt;performance.measure&lt;/code&gt; to allow them to said data to appears as custom trace numbers in the panel. Note, this isn’t in the documentation but rather &lt;a href="https://codelabs.developers.google.com/codelabs/firebase-perf-mon-web/#8" rel="noopener noreferrer"&gt;briefly makes an appearance in their codelab&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What confuses me is why they felt the need to define their own &lt;code&gt;firebase.performance().trace&lt;/code&gt; method, which in combination with start and stop commands, allows custom trace logging. This is &lt;a href="https://firebase.google.com/docs/perf-mon/custom_traces-metrics?platform=web" rel="noopener noreferrer"&gt;documented&lt;/a&gt; and it frustrates me. Why not simply use the standard User Timing API? My hunch is this is because people may use this in node outside the browser context, but I would hope this would be clearly defined.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should You Use Firebase Web Perf SDK
&lt;/h2&gt;

&lt;p&gt;Like most questions of this nature, it depends.&lt;/p&gt;

&lt;p&gt;On the one hand, if you want to dabble and start to test the beta on things that aren’t mission critical, I’d say give it a spin. If you aren’t tracking data at all and you want to get a feel for just how your web site or PWA is working in the wild with users, then it’ll give you a pulse. Is it going to be actionable? My gut says no, but only you know how your app works.&lt;/p&gt;

&lt;p&gt;If you’re in production right now on a site and you’re thinking you want to track performance, the answer is no. The data reporting and export to BigQuery do no appear to work (and are not documented in relation to their Android/iOS brethren), the panels are not really actionable or allow custom alerts to be set. It’s just not ready for prime-time. There are significantly better tools out there for monitoring web perf RUM; I recommend &lt;a href="https://speedcurve.com/" rel="noopener noreferrer"&gt;Speedcurve&lt;/a&gt; if you’re doing anything at scale.&lt;/p&gt;

&lt;p&gt;Regardless of the gaps and initial issues with the beta, I applaud any company that’s will to take on web performance tracking and monitoring. It’s not easy to roll your own and often the alternatives are &lt;a href="https://justinribeiro.com/chronicle/2019/09/16/fighting-with-dynatrace-to-send-custom-user-timings-with-performance-observer/" rel="noopener noreferrer"&gt;terrible&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While Firebase Performance SDK for the web is clearly a work-in-progress, I’m hoping that it improves. The more awareness we have about web performance, the more I’m hoping we can make the web faster and better for more users around the world.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://justinribeiro.com/chronicle/2019/10/28/six-months-using-firebase-web-performance-monitoring/" rel="noopener noreferrer"&gt;justinribeiro.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webperf</category>
      <category>firebase</category>
    </item>
    <item>
      <title>Generating a Simple Font Report With a Devtools Snippet</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Fri, 18 Oct 2019 16:23:42 +0000</pubDate>
      <link>https://forem.com/justinribeiro/generating-a-simple-font-report-with-a-devtools-snippet-2be5</link>
      <guid>https://forem.com/justinribeiro/generating-a-simple-font-report-with-a-devtools-snippet-2be5</guid>
      <description>&lt;p&gt;As with most weekday mornings, links and articles are dropped into our random channel as either points of potential interest or swords drawn discussion. The topics have a lot of range, but the one that recently caught my eye was and article regarding finding &lt;a href="https://blog.lemi.travel/how-my-butt-helped-fix-font-problems-on-the-web/"&gt;improper font definitions in a page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The article had a useful premise, thought I wasn’t big on the code example or the page injection (which I found hard to read personally, but your mileage will vary). Instead, I decided I’d just write a variation of the snippet to output a unique report and use the DOM’s &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker"&gt;TreeWalker&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;TreeWalker has been in the &lt;a href="https://dom.spec.whatwg.org/#interface-treewalker"&gt;spec&lt;/a&gt; and in browsers for a long time and allows you to get a given document’s subtree and take a look at the nodes within. The nice thing about TreeWalker is that it’s fast and if you’ve ever used say &lt;a href="https://github.com/Polymer/lit-html/blob/a1b538f693abbc17d03ab84b96c497f63cd1535b/src/lib/template.ts#L53"&gt;lit-html&lt;/a&gt; or other such libraries, congratulations, you’ve used TreeWalker without even knowing it.&lt;/p&gt;

&lt;p&gt;With our API in mind, we can transverse and go about finding out what our &lt;code&gt;getComputedStyle()&lt;/code&gt; is for a given text node as in the DevTools snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function findTextNodesFor(element){ let node; const discoveredTextNodes = []; const walkTree = document.createTreeWalker(element, NodeFilter.SHOW\_TEXT, null, false); while(node = walkTree.nextNode()) { discoveredTextNodes.push(node); } return discoveredTextNodes; } weights = { 100: "Thin", 200: "Extra Light", 300: "Light", 400: "Regular", 500: "Medium", 600: "Semibold", 700: "Bold", 800: "Extra Bold", 900: "Black" }; fonts = new Set(); findTextNodesFor(document.querySelector('body')) .filter(node =\&amp;gt; !['SCRIPT', 'STYLE', 'NOSCRIPT'].includes(node.parentNode.nodeName)) .forEach(node =\&amp;gt; { const computedStyle = window.getComputedStyle(node.parentNode); const font = computedStyle.fontFamily || ""; const size = computedStyle.fontSize; const weight = computedStyle.fontWeight; const weights = { 100: "Thin", 200: "Extra Light", 300: "Light", 400: "Regular", 500: "Medium", 600: "Semibold", 700: "Bold", 800: "Extra Bold", 900: "Black" }; fonts.add(`${size} ${weights[weight]} ${font}`); }); console.table([...fonts].sort());
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will output a nifty little table of only the unique fonts we find (if you’ve not used &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set"&gt;Set&lt;/a&gt;, I highly recommend you take a look at the docs to see how if can make your life easier).&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aLWZiKxz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191018-devtools-font-report-800.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aLWZiKxz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191018-devtools-font-report-800.png" alt="devtools snippet font report"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Now, there are some gotcha’s to keep in mind here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;This won’t show you the browsers &lt;em&gt;computed&lt;/em&gt; display. Chrome DevTools for instance will show you the font(s) that system are actually being rendered as opposed to just the font definition that is being applied to the node.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This won’t transverse the custom element with shadowDOM (because that’s a whole other can of worms).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sans that, you get a nice little way to see exactly what’s being defined and if you may need to re-evaluate your font strategy.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Generating Video From a Chrome Devtools Trace With devtools-to-video</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Wed, 16 Oct 2019 14:55:51 +0000</pubDate>
      <link>https://forem.com/justinribeiro/generating-video-from-a-chrome-devtools-trace-with-devtools-to-video-4di6</link>
      <guid>https://forem.com/justinribeiro/generating-video-from-a-chrome-devtools-trace-with-devtools-to-video-4di6</guid>
      <description>&lt;p&gt;When it comes to diagnosing web performance problems, you do a lot of living in DevTools. Between the Performance Tab and the all powerful chrome://tracing, these are the sorts of things I work with on a daily basis.&lt;/p&gt;

&lt;p&gt;The problem with living in this paradise of useful information is that the information has a tendency to only make sense to a few folks. When you talk to upper management, traces tell a story that visually can be hard to decipher in bit sized meetings.&lt;/p&gt;

&lt;p&gt;Pictures of traces speak a thousand words. Video of what a user is experiencing get resources assigned to fix web performance problems.&lt;/p&gt;

&lt;p&gt;In a perfect world, I’d have WebPageTest just rolling runs at my behest with video output, but in a lot of on many projects WebPageTest isn’t running internally and testing externally is a non-starter. We need a method to generate some video with some feeling. Enter &lt;a href="https://github.com/justinribeiro/devtools-to-video"&gt;devtools-to-video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;devtool-to-video is a little cli tool written in node that utilizes ffmpeg to generate a video from a Chrome DevTools trace and put a timer on the bottom that shows the time progression.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Qe8ktciM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191016-devtools-to-video-800.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qe8ktciM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191016-devtools-to-video-800.png" alt="devtools-to-video cli in action"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;An &lt;a href="https://www.youtube.com/watch?v=guJLfqTFfIw"&gt;example of the video ouput&lt;/a&gt;:&lt;/p&gt;



&lt;p&gt;This is similar in concept to WebPageTest though their output video timer is way cooler. This simply utilizes the presentation time (pts) within the ffmpeg to give us a quick means to create the video without a lot overhead via drawtext.&lt;/p&gt;

&lt;p&gt;Using devtool-to-video is pretty simple. Install the cli tool via npm or yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @justinribeiro/devtools-to-video # or yarn global add @justinribeiro/devtools-to-video
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once installed, we have a few command line options to deal with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜ devtools-to-video -h DEVTOOLS-TO-VIDEO Output a video file from screenshot frames within a Chrome DevTools JSON trace file. Usage: `devtools-to-video [options ...]` Global Options -i, --input string File path to Chrome DevTools trace JSON file. -o, --output string Output file name for video file. -c, --hideClock If set, hides the time scale clock on the output video file. -l, --label string If set, adds the label above the time scale clock in the output video file. -f, --frames number Sets the frames per second of the output video. -h, --help Print out helpful usage information for this program. -v, --version Print out current program version number. Version 0.2.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In practice, we generate our trace with screenshots enabled from the performance tab in DevTools, export and download that file, and then run it through our tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜ devtools-to-video -i profile.json -o sample.mp4 -l '3G Slow @ Moto G4' STARTING UP Checking environment and setting up params. CONVERT Spawning FFMPEG worker with open pipe. CONVERT Begin piping screenshots from DevTools trace to FFMPEG. SCREENSHOTS Processed 21 screenshots into video file. CONVERT DevTools trace successfully converted to MP4. LABEL PASS Adding label and time scale to MP4. LABEL PASS Finished adding label and time scale to MP4. COMPLETE DevTools trace to video is now complete! Your file sample.mp4 is ready
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Take file, show stakeholders, make case that you need better web performance.&lt;/p&gt;

&lt;p&gt;Generating a video from a trace is also not a new concept; I used a much more convoluted approach a year or so ago that was just unreliable. Then I saw Kris Selden’s &lt;a href="https://gist.github.com/krisselden/bf98fb0c192fcb73ed32e79c0a7972d2"&gt;trace-to-mp4.js gist&lt;/a&gt;, and my faith in ffmpeg was restored. From there it was just a matter of double passing the video with a filter within ffmpeg (which is it’s own can of worms, but I love ya ffmpeg).&lt;/p&gt;

&lt;p&gt;So go out there and trace your sites and apps, and keep making the web faster.&lt;/p&gt;

</description>
      <category>devtools</category>
      <category>webperf</category>
      <category>npm</category>
    </item>
    <item>
      <title>Web Components Have Already Won Whether You Like It Or Not</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Mon, 14 Oct 2019 15:15:43 +0000</pubDate>
      <link>https://forem.com/justinribeiro/web-components-have-already-won-whether-you-like-it-or-not-32kc</link>
      <guid>https://forem.com/justinribeiro/web-components-have-already-won-whether-you-like-it-or-not-32kc</guid>
      <description>&lt;p&gt;With the announcement a last week that VMWare is taking their popular enterprise &lt;a href="https://medium.com/claritydesignsystem/claritys-future-user-focused-framework-independent-accessible-enterprise-ready-and-open-61a3f62eac93"&gt;Clarity design framework from Angular to web components&lt;/a&gt;, a few emails have trickled into my inbox asking for my opinion on certain anti-web components threads on Twitter (which I refuse to link to because it’s all blah). My opinion is not a popular one, but here it goes.&lt;/p&gt;

&lt;p&gt;Web components already won while you all were arguing about it on Twitter.&lt;/p&gt;

&lt;p&gt;A lot of folks are going to disagree. More pieces of “why I’m not using web components” will be written by folks who seemed either misinformed or simply want to protect their own knowledge space and viability. Many will point to technical reasons that show their lack of understanding of not just web components but the web platform as a whole. Some will point to performance and say web components are slow and have no trace to prove their point.&lt;/p&gt;

&lt;p&gt;No number of existing data that shows web component usage will matter, no number of large companies making announcements about their usage of web components will sway those opinions. I will probably be called names and my character attacked.&lt;/p&gt;

&lt;p&gt;All of that won’t change the fact that web components already won.&lt;/p&gt;

&lt;p&gt;Web components didn’t just win in the large public companies with splashy open source projects. They’ve won at private companies of all sizes, where line of business software keeps companies running. I’ve lost count of how many companies I’ve helped ship nearly a hundred pieces of LOBS that are built on top of web components. They won where integration was a challenge that frameworks could not (and frankly probably shouldn’t) deliver on. I’ve written a lot of components in all shapes and sizes for hundreds of companies at this point and I’m &lt;em&gt;losing&lt;/em&gt; compared to some of the work I see developers doing on web components in so many organizations.&lt;/p&gt;

&lt;p&gt;You know the place it wins that no one wants to talk about because it’s not cool? jQuery. Yeah that little library that it’s in use on in more places than anyone wants to admit. Turns out, web components are extremely pliable and companies with developers who still work on those system’s love them.&lt;/p&gt;

&lt;p&gt;“No one uses jQuery anymore, especially not with web components!”&lt;/p&gt;

&lt;p&gt;You live a sheltered development existence and I feel sorry for you. Not everyone is on the bleeding edge, not everyone can change their stack year after year. If you can’t have empathy for those developers, we can’t be friends.&lt;/p&gt;

&lt;p&gt;Why don’t you hear about these cases? The developers and companies in question are not in the bubble. They don’t care about your argument; they have work to do and are succeeding. Drag them into that argument and they’ll just walk away. They don’t have an axe to grind.&lt;/p&gt;

&lt;p&gt;When they do pop up from time to time, the brave step into a hostile online conversation, what happens? Drowned out by unwarranted judgement and pretty baseless gibberish. Then they shrug and go back to work on their web components.&lt;/p&gt;

&lt;p&gt;Inevitably someone will say I’m against frameworks (you clearly have not listened to the &lt;a href="https://thewebplatformpodcast.com/"&gt;podcast&lt;/a&gt;) and that I (and many others) who are helping companies build with web components (or even that raw web platform APIs) are doing these companies a disservice. I’ll let the CIO’s and CTO’s I’m meeting with this week know your concerned.&lt;/p&gt;

&lt;p&gt;The reality is you want to argue and quite frankly I’m done arguing. Stop trying to make it an adversarial game that someone has to lose. We’re all working towards a common goal of happy users.&lt;/p&gt;

&lt;p&gt;You don’t like the spec? &lt;a href="https://github.com/w3c/webcomponents"&gt;Contribute&lt;/a&gt;. Meetings continue to happen, get a word in and let’s talk it out. Features are good on the platform for everyone.&lt;/p&gt;

&lt;p&gt;You think it competes with your framework? &lt;a href="https://custom-elements-everywhere.com/"&gt;Probably less than you think&lt;/a&gt;. We can coexist people and I don’t have to tear anyone or any piece of technology down to do so.&lt;/p&gt;

&lt;p&gt;Use the right tools for the job, use others as warranted. Sometimes that’s going to be web components whether you like it or not.&lt;/p&gt;

&lt;p&gt;The battle was hard fought and took a lot longer than anyone expected, but specs and false starts and missteps aside, web components did the unthinkable: they won.&lt;/p&gt;

&lt;p&gt;You can keep arguing if you like. Me, I’m going to keep building things.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>webplatform</category>
    </item>
    <item>
      <title>Improving RSS Reader Support and Adding New Topic Feeds</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Wed, 09 Oct 2019 23:10:50 +0000</pubDate>
      <link>https://forem.com/justinribeiro/improving-rss-reader-support-and-adding-new-topic-feeds-3a9f</link>
      <guid>https://forem.com/justinribeiro/improving-rss-reader-support-and-adding-new-topic-feeds-3a9f</guid>
      <description>&lt;p&gt;With my recent foray into more widespread writing topics, I decided it was time to revisit the concept of topic specific RSS feeds and tag pages. Yeah, you’re not going to get the nitty gritty of some of my more personal posts, but hey, at least maybe you’ll keep on reading the content you find is relevant for you.&lt;/p&gt;

&lt;p&gt;Available now (and in the &lt;a href="https://github.com/justinribeiro/blog-pwa"&gt;blog-pwa&lt;/a&gt; codebase) are a new set of topic specific pages and feeds listed on the &lt;a href="https://justinribeiro.com/tags/"&gt;tags&lt;/a&gt; page and accessible from the home page or the &lt;a href="https://justinribeiro.com/chronicle/"&gt;archive&lt;/a&gt;. Topics currently include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;🕸️ &lt;a href="https://justinribeiro.com/tags/web/"&gt;Web Dev, Web Perf, and Web Platform Articles&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🥽 &lt;a href="https://justinribeiro.com/tags/iot/"&gt;Internet of Things (IoT) Articles&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📷 &lt;a href="https://justinribeiro.com/tags/photography/"&gt;Photography Articles and Prints&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;👔 &lt;a href="https://justinribeiro.com/tags/business/"&gt;Management and Business Articles&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;👨 &lt;a href="https://justinribeiro.com/tags/personal/"&gt;Personal Articles&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Under the hood, there was actually not a great deal of change required for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling tag generation in Hugo
&lt;/h2&gt;

&lt;p&gt;The tags are generated via Hugo in a similar fashion to how I generate all my JSON objects. The biggest difference you’ll find is that the taxonomy defines it’s own RSS template and handles some of the deployment paths via replace and we make our title more specific:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\&amp;lt;channel\&amp;gt; \&amp;lt;title\&amp;gt;{{ .Site.Title }} - {{ .Title }}\&amp;lt;/title\&amp;gt; \&amp;lt;description\&amp;gt;{{ .Description }}\&amp;lt;/description\&amp;gt; \&amp;lt;link href="{{ replace .Permalink "/tags" "/data/tags" }}index.xml" rel="self"/\&amp;gt; \&amp;lt;link href="{{.Permalink}}"/\&amp;gt; \&amp;lt;language\&amp;gt;en-us\&amp;lt;/language\&amp;gt; \&amp;lt;id\&amp;gt;https://justinribeiro.com/\&amp;lt;/id\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Along those lines, instead of just generating a big list of tags which would includes a number of old tagging conventions from my perl/jekyll/wordpress post conversions over the years, I override the &lt;code&gt;/tags/_index.md&lt;/code&gt; and simply made a nicely sectioned version for ease of use. I also decided to do this for each of the tag pages within the content folder, again to make things nicer.&lt;/p&gt;

&lt;p&gt;In terms of problems within this approach is that fact that every post needs at least one tag. Sure, I could have written some case logic within the hugo templates, but I figured I might as well backfill as much of the missing tags as needed. Turned out, not that many posts to update.&lt;/p&gt;

&lt;p&gt;There was also a more wide spread fix applied at this time as well; &lt;code&gt;code-block&lt;/code&gt; tags were replaced with &lt;code&gt;pre&lt;/code&gt;, allowing better code block rendering for CSS clients (which did not understand the web component obviously). Both tag and overall RSS feeds have this patch, allowing for a much nicer rendering remotely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling the tags in the PWA
&lt;/h2&gt;

&lt;p&gt;This part was actually rather easy because of the structure of existing views. The &lt;code&gt;blog-chronicle.js&lt;/code&gt; web component already had a &lt;code&gt;posts&lt;/code&gt; array parser, so with a little retrofitting of the data layer, it could now serve to display tags and tag specific pages as well.&lt;/p&gt;

&lt;p&gt;At that point, it only required a couple new routes within vaadin-router in the &lt;code&gt;blog-pwa.js&lt;/code&gt; web component, and everything worked without a hitch.&lt;/p&gt;

&lt;p&gt;No additional JavaScript weight or logic required. You gotta love it when a plan comes together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future planning
&lt;/h2&gt;

&lt;p&gt;I’m not sold on only those using those tags (and I really need to clean the old ones, which do properly function still within the Hugo generation and PWA). For now, this will at least give user a chance to pick the right feed for them.&lt;/p&gt;

&lt;p&gt;What are you waiting for? Subscribe to a feed or read a tag! You know you want to.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Four Cases of Progressive Rendering Fallbacks for Progressive Web Apps</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Tue, 08 Oct 2019 16:46:13 +0000</pubDate>
      <link>https://forem.com/justinribeiro/the-four-cases-of-progressive-rendering-fallbacks-for-progressive-web-apps-100k</link>
      <guid>https://forem.com/justinribeiro/the-four-cases-of-progressive-rendering-fallbacks-for-progressive-web-apps-100k</guid>
      <description>&lt;p&gt;I mentioned &lt;a href="https://justinribeiro.com/chronicle/2019/10/07/adding-webmention-support-to-a-progressive-web-app/"&gt;yesterday&lt;/a&gt; that &lt;a href="https://github.com/justinribeiro/blog-pwa"&gt;blog-pwa&lt;/a&gt; uses a static rendering layer for cases when the browser or whatever is fetching the page doesn’t support JavaScript. This was a slight simplification on my part. blog-pwa defines four primary cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Are you a known bot or tool that isn’t going to understand JavaScript or understand the noscript redirect? &lt;em&gt;STATIC&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Are you a browser that supports JavaScript? &lt;em&gt;PWA&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Are you a browser with JavaScript support turned off? &lt;em&gt;PWA + NOSCRIPT Redirect to STATIC&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Are you a browser with JavaScript support but no ES Modules support? &lt;em&gt;PWA + NOMODULE Redirect to STATIC.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These four primary cases are what I use for any content serving progressive web app I build today. Doesn’t matter the scale, if I’m building a PWA for someone, I consider these four cases the key to serving as many users and bots that I can (though in the case of #4 above, that might serve a different ES5 bundle based on what features I can patch).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: I said “content serving” because some PWA’s are offering more native app-like feature sets using things like WebUSB or WebBluetooth and the expectation that these should fallback the same way is not the same in my opinion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the case of blog-pwa, this takes place at both the server level (blog-pwa’s Google App Engine backend) and the client level (blog-pwa’s index.html shell). In most PWA buildouts in the last year or so, I always use server and client approaches.&lt;/p&gt;

&lt;p&gt;In the case of server side, I check two cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Are you a bot or tool in the known list?&lt;/li&gt;
&lt;li&gt;Are you a request with the url queryparam &lt;code&gt;static&lt;/code&gt; set to true?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second option works in conjunction with the blog-pwa’s index.html shell, which itself defines two cases to cause clients to redirect with static set to true based on enabled browser feature set:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the no JavaScript support enabled case, we use &lt;code&gt;noscript&lt;/code&gt; and a &lt;code&gt;meta&lt;/code&gt; redirect tag.&lt;/li&gt;
&lt;li&gt;In the no ES Module support case, we use &lt;code&gt;script nomodule&lt;/code&gt; and &lt;code&gt;location.href&lt;/code&gt; to handle the redirect.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To make this work, I cheat on first load by injecting a template variable server side into index.html that in modern browsers with JavaScript enabled won’t matter to handle the above two cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\&amp;lt;noscript\&amp;gt; \&amp;lt;p\&amp;gt;JavaScript appears to be turned off. No problem, this Progressive Web App is Progressive! Redirecting to static page...\&amp;lt;/p\&amp;gt; \&amp;lt;meta http-equiv="refresh" content="0;url={{ noscript }}"\&amp;gt; \&amp;lt;/noscript\&amp;gt; \&amp;lt;script nomodule\&amp;gt; // IE11 and anything that doesn't support ES Modules gets the no-JS // version of the site location.href = '{{ noscript }}'; \&amp;lt;/script\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This isn’t fancy or heavy engineering; this is just testing against features. No fancy user agent checking required.&lt;/p&gt;

&lt;p&gt;With these cases and the static side setup, I’m able to safely say that the site renders in things like browsers like Lynx quite beautifully.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cFmsfRpO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191008-progressive-web-for-the-win-lynx-edition.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cFmsfRpO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191008-progressive-web-for-the-win-lynx-edition.png" alt="this site running in lynx"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even more crazy is that you still get a reasonably readable render in something like Internet Explorer 8.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V1h5uCD0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191008-progressive-rendering-into-ie8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V1h5uCD0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/jdr-public-imgs/blog/20191008-progressive-rendering-into-ie8.png" alt="this site running in IE8"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Are there a lot of users viewing my site in these browsers? No. Does that mean I (or you) shouldn’t plan for this scenario? I’m of the opinion people should be able to read my content even on the most terrible of connections or browsers.&lt;/p&gt;

&lt;p&gt;Should it all looks the same in every browser ever designed? No. A lot of folks might disagree, but the engineering effort to make that happen is significantly high and you better be doing some cost-benefit analysis before you jump into those waters. I’ve seen projects crash and burn and take down jobs. Don’t be that team.&lt;/p&gt;

&lt;p&gt;Not every PWA might need these cases or offer more fine grained approaches. If you’re not thinking about these cases and you’re only relying on those JavaScript based analytics, do you really know how much syndication or user base you’re missing? Dig a little deeper and you might be surprised.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding Webmention support to a Progressive Web App</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Mon, 07 Oct 2019 21:18:51 +0000</pubDate>
      <link>https://forem.com/justinribeiro/adding-webmention-support-to-a-progressive-web-app-1m5d</link>
      <guid>https://forem.com/justinribeiro/adding-webmention-support-to-a-progressive-web-app-1m5d</guid>
      <description>&lt;p&gt;On my ongoing quest to independence from third party content silos, one of things that was inherently missing was engagement. Surely I would want some way to interact beyond &lt;a href="https://ribeiro.social/@justin"&gt;@justin@ribeiro.social&lt;/a&gt;; people should be able to write replies and what not on their own blogs, and I should be able to surface that on the site. Enter Webmention.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.w3.org/TR/2017/REC-webmention-20170112/"&gt;Webmention&lt;/a&gt; is a W3C recommendation specification that at the top level allows notifications that one URL links to another. You can think of this as a primitive that allows us to build federated services around the things people might write or comment about all around the web.&lt;/p&gt;

&lt;p&gt;A simple example is your write a response to one of my posts on your blog, linking to my original post. You then ping said url and express what exactly you did (maybe it was a comment, maybe it was a review), and then my endpoint accepts them and I can display them or reply back as I see fit.&lt;/p&gt;

&lt;p&gt;The spec is one of many concepts to come out of &lt;a href="https://indieweb.org/"&gt;IndieWeb&lt;/a&gt;, a community focused on people and the independent web. As you probably guessed I really like this concept. Problem was, how do I implement this when it comes to a progressive web app?&lt;/p&gt;

&lt;h2&gt;
  
  
  How our PWA is built
&lt;/h2&gt;

&lt;p&gt;As I’ve written about before, &lt;a href="https://github.com/justinribeiro/blog-pwa"&gt;blog-pwa&lt;/a&gt; is my little place I call home. I’ve worked on it for nearly three years and it’s powered my site for a long time with success. Built with web standards like web components and service worker, my custom progress web app blog setup is truly progressive, supporting no-javascript clients and bots via a nifty static generator. For a long time this was limited to linkbots for your social networks and what not, but over the years I’ve tweaked it to support a wide range of other services, including old IE (via no-module), lynx (just because) and Googlebot (static one-to-one representation of the PWA, which I technically don’t have to do anymore).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In IndieWeb parlance I’ve been told this is considered &lt;a href="https://indieweb.org/selfdogfood"&gt;selfdogfooding&lt;/a&gt;. I was not aware this was a thing to be honest, but I use what I build to be sure. Term at will.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having read a &lt;a href="https://indieweb.org/Webmention-developer"&gt;lot of documentation&lt;/a&gt; from the wiki, I set forth to handle what I hoped would be the easy bit: setting up the receiver.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receiving webmentions with webmentions.io
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://webmention.io/"&gt;webmention.io&lt;/a&gt; is an &lt;a href="https://github.com/aaronpk/webmention.io"&gt;open source&lt;/a&gt; and hosted service for receiving webmentions. I’ve initially opted for the hosted version to jump start things and on the surface this seemed pretty simple.&lt;/p&gt;

&lt;p&gt;After logging into webmention.io, we’re presented with a couple links to set in the head of our documents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\&amp;lt;link rel="webmention" href="https://webmention.io/justinribeiro.com/webmention" /\&amp;gt; \&amp;lt;link rel="pingback" href="https://webmention.io/justinribeiro.com/xmlrpc" /\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: you could also do this via &lt;a href="https://indieweb.org/webmention-implementation-guide"&gt;http headers&lt;/a&gt; if you so please.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the this now in the head of my document, I decided to just roll the dice and test to see what the various webmention tools out there would think about this. The end result will probably not shock you.&lt;/p&gt;

&lt;h2&gt;
  
  
  A receiver unseen
&lt;/h2&gt;

&lt;p&gt;With blog-pwa now rocking the proper setup, I went over to &lt;a href="https://brid.gy/"&gt;Bridgy&lt;/a&gt;, an open source connector that takes a look at your social media reactions and turns them into webmentions you can use on your site. After login and little timeline parsing, Bridgy had found some interactions, but was reporting that webmention support on my domain was not setup.&lt;/p&gt;

&lt;p&gt;A quick glance quickly revealed what I suspected: it was having trouble parsing the progressive web app output case. Bridgy wasn’t the only one; &lt;a href="https://telegraph.p3k.io/"&gt;Telegraph&lt;/a&gt;, &lt;a href="https://webmention.app/"&gt;Webmention.app&lt;/a&gt;, &lt;a href="https://indiewebify.me"&gt;IndieWebify.me&lt;/a&gt; all initially struggled to properly see the link references.&lt;/p&gt;

&lt;p&gt;I could have sat here and complained, but this stuff is open source so I got down to work. blog-pwa can render static output as needed; what I needed was User Agents to point them to the correct case.&lt;/p&gt;

&lt;p&gt;In the specification, the fetch GET case is not defined but senders should send “webmention” within their user agent. Since most of these were working with some type of GET to do the initial parsing and targeting of incoming mentions, I just needed to find these User Agents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# web mentions handlers webmention\_bot\_hunt = ['webmention', 'node-fetch', 'guzzle', 'bridgy', 'go-http-client', 'ruby', 'appengine-google', 'xray']
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You might be thinking that guzzle is a PHP HTTP client and node-fetch is a node client and you would be correct. What I found was that most of the GET processors used their respective library’s default User Agent, which means I had to stretch a bit to make them all work. In the case of &lt;a href="https://webmention.app/"&gt;Webmention.app&lt;/a&gt; its user agent was set to unknown (but &lt;a href="https://github.com/remy/wm/pull/11"&gt;I patched that last week&lt;/a&gt;, cheers &lt;a href="https://remysharp.com/"&gt;Remy&lt;/a&gt; for the merge!).&lt;/p&gt;

&lt;p&gt;The thing to keep in mind here is that these are fetch-and-parse operations; they’re not doing this via headless Chrome (my temptation to make a webmention parser with headless is running really deep at the moment), so we’re not going to get DOM parsing.&lt;/p&gt;

&lt;p&gt;This also extends to &lt;a href="http://microformats.org/wiki/h-card"&gt;h-card&lt;/a&gt; and &lt;a href="http://microformats.org/wiki/h-entry"&gt;h-entry&lt;/a&gt; microformats, which weren’t being read from my PWA body either. This too was needed within the static generation side, allowing for posts and replies to carry more context.&lt;/p&gt;

&lt;p&gt;With those fixes in place, all the webmention services I tested had no trouble reading or sending webmentions to my site.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: say what you will, but always have a static rendering plan when it comes to PWAs that are displaying content (ala, the word &lt;em&gt;progressive&lt;/em&gt;). There are lots of tools out there, including the fabulous &lt;a href="https://github.com/GoogleChrome/rendertron"&gt;Rendertron&lt;/a&gt; that can help with this if you’ve not engineering a specific solution and case for static generation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A little manual webmention action
&lt;/h2&gt;

&lt;p&gt;With data flowing, I wanted to continue tackling collection first. One thing I didn’t want to stop people from doing was just manually sending me a link letting me know “hey, I commented on this”.&lt;/p&gt;

&lt;p&gt;To handle this, I wrote a little form (they one at the very bottom of this post) that handles this. By no means is the lower form idea a new one; I had originally seen this concept on &lt;a href="https://adactio.com/"&gt;Jeremy Keith’s site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Writing such a form is actually pretty simple. Here, I just a use a standard form with a little click bind from my lit-element and a simple POST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\&amp;lt;form id="webMentionForm" action="https://webmention.io/justinribeiro.com/webmention" method="POST"\&amp;gt; \&amp;lt;input type="hidden" name="target" .value="${this.metadata.permalink}" /\&amp;gt; \&amp;lt;label for="source"\&amp;gt; Written a response or comment to this post? Fantastic! I support \&amp;lt;a href="https://indieweb.org/Webmention"\&amp;gt;WebMentions\&amp;lt;/a\&amp;gt;. Paste and send your URL here: \&amp;lt;/label\&amp;gt; \&amp;lt;input type="url" name="source" placeholder="https://your-amazing-response-url-here/" id="webMentionSource" /\&amp;gt; \&amp;lt;button @click="${e =\&amp;gt; this.\_\_submitWebMention(e)}"\&amp;gt; 🚚 Send Webmention \&amp;lt;/button\&amp;gt; \&amp;lt;/form\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;From a JavaScript perspective, the thing to keep in mind is that we could technically change our headers to request &lt;code&gt;Location&lt;/code&gt; header access to see allow the user to see the status of their webmention being processed, but I wasn’t really sold on that from a user experience perspective.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async \_\_submitWebMention(event) { event.preventDefault(); let message = 'Thank you for sharing! Your Webmention has been received and is currently be processed.'; const action = this.shadowRoot.querySelector('#webMentionForm').action; const target = this.metadata.permalink; const source = this.shadowRoot.querySelector('#webMentionSource').value; if (source !== '') { // technically, we could get the location header and show them the ticket, // but I'm not 100% sold on that as a user experience const response = await fetch(action, { method: 'POST', mode: 'cors', cache: 'no-cache', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `target=${target}&amp;amp;source=${source}`, }); if (!response.ok) { message = "Oh no, your Webmention didn't seem to make it through. Please try again."; } // show our snackbar popup to let the user know it's all good this.dispatchEvent( new CustomEvent('display-snackbar', { bubbles: true, composed: true, detail: { message, }, }), ); this.shadowRoot.querySelector('#webMentionSource').value = ''; } }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: if you’re using Content Security Policy, make sure to allow webmention.io in your form target settings otherwise this will not work!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Rendering those mentions (or not)
&lt;/h2&gt;

&lt;p&gt;With mentions now flowing, my final step was to actually render this at the footer of my blog entries. Most of the implementations I’ve reviewed of late handle this at build time (see examples for &lt;a href="https://mxb.dev/blog/using-webmentions-on-static-sites/"&gt;eleventy&lt;/a&gt;, &lt;a href="https://github.com/aarongustafson/jekyll-webmention_io"&gt;jekyll&lt;/a&gt;, and &lt;a href="https://paul.kinlan.me/using-web-mentions-in-a-static-sitehugo-/"&gt;hugo&lt;/a&gt;), but &lt;a href="https://github.com/aaronpk/webmention.io#api"&gt;webmention.io has an API&lt;/a&gt; and it’s easy enough to write a fetch function to get that data in a number of different forms.&lt;/p&gt;

&lt;p&gt;The problem became pretty clear to me: if I did this on a every render, I run the risk of pummeling that API for data in high traffic cases. I didn’t think that would be very cool. There is also the risk of large payloads based on interactions and I didn’t really dig that concept either for low bandwidth scenarios (of which I’d rather have content render rather than likes).&lt;/p&gt;

&lt;p&gt;What I settled on at the moment is to only render the interaction counts (which currently is a small payload and given that I haven’t parsed a lot of webmentions data yet, not heavy).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async \_\_getInteractionCounts() { const response = await fetch( `https://webmention.io/api/count?target=${this.metadata.permalink}`, { method: 'GET', mode: 'cors', }, ); if (response.ok) { const data = await response.json(); if (data.count \&amp;gt; 0) { this.interactions = `There are currently ${data.count} interactions with this piece on the open web.`; } else { this.interactions = `There are currently no interactions with this piece. Be the first!`; } } }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I suspect I’ll put a tiny cache in blog-pwa’s GAE layer to handle this in the future, so I get a level of control and I can shrink the payloads to a smaller, more succinct set of data I can render. I don’t want to hide those responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking ahead
&lt;/h2&gt;

&lt;p&gt;I have a few next steps that I’ll be tackling:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I have some PR’s I’m going to push to clean up a lot more user agents, that way if you have a PWA-style static render and are using bot string matching, that you’ll have an easier time.&lt;/li&gt;
&lt;li&gt;Along the lines of above, I need to open a ticket and see if that makes sense to put into the spec.&lt;/li&gt;
&lt;li&gt;I iced the web component I wrote for the interaction list, but that’s going to get published on NPM.&lt;/li&gt;
&lt;li&gt;I’m probably going to implement Remy’s webmention.app CLI tool into my make deployment script. Testing it locally over the weekend, his tool (and site) work great.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the meantime, if you have a mention you can ping me below in the form&lt;/p&gt;

&lt;p&gt;¡Viva la web abierta!&lt;/p&gt;

</description>
      <category>webmentions</category>
      <category>pwa</category>
    </item>
    <item>
      <title>Workaround for Karma and Chrome headless on Windows Subsystem for Linux, ala WSL</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Wed, 02 Oct 2019 22:26:00 +0000</pubDate>
      <link>https://forem.com/justinribeiro/workaround-for-karma-and-chrome-headless-on-windows-subsystem-for-linux-ala-wsl-1g6</link>
      <guid>https://forem.com/justinribeiro/workaround-for-karma-and-chrome-headless-on-windows-subsystem-for-linux-ala-wsl-1g6</guid>
      <description>&lt;p&gt;Windows Subsystem for Linux (WSL) is a vastly useful thing. When I do work on Windows for those certain projects, WSL has made my life significantly easier.&lt;/p&gt;

&lt;p&gt;One the gaps however is that running Chrome headless within WSL is difficult. I’m not blaming WSL for this (it’s basically a namespace problem which I’d expect). There are workarounds to be sure, usually involving single process and disabling the GPU, but in a recent demo I was running showcasing &lt;a href="https://open-wc.org/"&gt;open-wc&lt;/a&gt; and &lt;a href="http://karma-runner.github.io/latest/index.html"&gt;karma&lt;/a&gt;, I was in a bind for a workaround on short notice. The fix is it’s faster and easier to point to the pre-installed Chrome binary on Windows.&lt;/p&gt;

&lt;p&gt;Doing this requires setting the &lt;code&gt;CHROME_BIN&lt;/code&gt; env variable, which will allow chrome headless to work without issue when using karma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/src/jdr-wc-template master\* ➜ export CHROME\_BIN=/mnt/c/Program\ Files\ \(x86\)/Google/Chrome/Application/chrome.exe ~/src/jdr-wc-template master\* ➜ yarn test yarn run v1.19.0 $ karma start --coverage START: \&amp;lt;your-component\&amp;gt; ✔ has a default property hello ✔ allows property hello to be overwritten Finished in 0.055 secs / 0.038 secs @ 15:23:16 GMT-0700 (Pacific Daylight Time) SUMMARY: ✔ 2 tests completed TOTAL: 2 SUCCESS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is actually one of the cooler things about WSL; you can integrate executables between environments.&lt;/p&gt;

&lt;p&gt;Will this fix all your headless chrome problems in the WSL? Probably not; some of my basic headless examples don’t run in this configuration. But if you need to run some tests real quick like, this fix just might be for you.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Three Reasons You Betrayed Your Modern Web Tooling</title>
      <dc:creator>Justin Ribeiro</dc:creator>
      <pubDate>Tue, 01 Oct 2019 16:46:54 +0000</pubDate>
      <link>https://forem.com/justinribeiro/three-reasons-you-betrayed-your-modern-web-tooling-2kjn</link>
      <guid>https://forem.com/justinribeiro/three-reasons-you-betrayed-your-modern-web-tooling-2kjn</guid>
      <description>&lt;p&gt;No one wants to believe the DevTools trace. I have many theories as to why, some proven others less so. One prevailing theory I have is that people don’t understand how to read said trace, so I do the only reasonable thing and teach them. Surely that’ll work I always think, knowledge is power.&lt;/p&gt;

&lt;p&gt;Apparently it’s not enough power, as they still won’t believe it.&lt;/p&gt;

&lt;p&gt;Finger pointing will ensue. Passive aggressive comments will be made. Somehow it will become not only my fault, but my problem. Which is funny because if it’s really my problem I’ll fix it. I will propose a plan, people will immediately push back and protect their tiny kingdoms.&lt;/p&gt;

&lt;p&gt;Among the ensuing fray of competing kingdoms waging their various troops forward shouting the battle cries of yore, “Ops, chaaarrrge”, “UX through the flank”, and “AGGGILEE!!!” it’s clear no one has a clue what’s going on.&lt;/p&gt;

&lt;p&gt;Mind you the villagers do. Yeah, they’re your users suffering at the hands of your petty turf war.&lt;/p&gt;

&lt;p&gt;A comment from the lead developer leaves their quiver and flies through the air destined for my heart, to end the ensuing threat of more of my trace analysis.&lt;/p&gt;

&lt;p&gt;“We’re using modern web tooling and we followed so-and-so’s guide and they’re an expert.”&lt;/p&gt;

&lt;p&gt;The arrow strikes true, resulting in a hushed silence upon the battlefield. A smirk comes across my face.&lt;/p&gt;

&lt;p&gt;“A craftsperson never blames their tools.” The arrow falls lifeless to the floor, my armour in tact.&lt;/p&gt;

&lt;p&gt;You see I hear this argument more often than not these days. Pick a fancy web tool and I’ve probably got a terrible story of poor engineering around it. The three rather generic reasons I’ve seen time and again for this poppycock:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Time investment for learning&lt;/em&gt;. Not all tools are intuitive; some are harder to learn than others and that requires time and invest to use correctly in a project to get the performance you may want. I sometimes call this the “WebPack conundrum”.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Single information source&lt;/em&gt;. Too many folks send cited sources and articles that gloss over or misstate the impact of said tool usage, yet these often single point information source then becomes the gospel truth in a given team.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Hope-based Development&lt;/em&gt;. People don’t put in the work to verify anything, resulting in “write once, it works on my machine, it built so it’s not my problem” thinking. I call it hope-based because I’m being optimistic that people actually are hopeful their code works better, but experience tells me they too often don’t care.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ultimately these things conspire against the very best web tooling because just because a tool is good doesn’t mean it can’t be misused. A lot of work has been done on many such tools to push warnings and messages to developers in an attempt to prevent such harsh and poor performing development modes from slipping into production, but if you’ve got a team that’s done any or all of the above three points, a warning isn’t going to stop them.&lt;/p&gt;

&lt;p&gt;What can you do to prevent such malfeasance? For starters, I’d never take any article or tutorial on the web as a single source of truth. There are rare exceptions, but even in those cases it comes back to doing your due diligence, not just from a single developer but rather a team effort.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Managers&lt;/em&gt;: Give your developers time to actually study what they’re working on. Tight deadlines are all fine and dandy until you ship a steaming pile of code that only functions on a set 12 core processors. You want cutting edge? Give them time.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Developers&lt;/em&gt;: Know your tools and and which ones are right for the job at hand. What every you choose out of your toolbox, you have to trace. Trace on your desktop, trace on device. Run tests. Find the edges of the performance and tooling. Study reasons why, test your hypothesis.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Designers&lt;/em&gt;: Get to know the web. Understand that for all our progress, we have constraints that differ on devices and network connections. Dig in, learn what works and what might not get you to 60 fps.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Quality Assurance&lt;/em&gt;: You’re the last line of defence. Get some Lighthouse tests in your mix and verify that web app is going to work for users in a wide range of places and device types. Look beyond upper management’s high speed Wifi and iPhone X existence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ultimately it’s not the tools that betrayed you, but rather your approach to them and the code you write. Tools won’t save you from poor engineering; you have to put in not just the work to write the lines of code, but also understand what those lines of code actually going to do. The tools will only get you so far, and then it comes down to actually verifying how that deliverable is going to perform.&lt;/p&gt;

&lt;p&gt;When in doubt, run a trace and work through it. If everyone started doing these things, just maybe I’ll get less arrows shot at me at my next meeting.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
