<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Dennis Bruijn's blog</title>
    <link>https://www.0x1ad2.dev/blog</link>
    <description>Writing about React, Node.js, testing, performance and the craft of building software that lasts.</description>
    <language>en</language>
    <atom:link href="https://www.0x1ad2.dev/feed.xml" rel="self" type="application/rss+xml" />
    <lastBuildDate>Sat, 10 Oct 2026 00:00:00 GMT</lastBuildDate>
    <item>
      <title>🏗️ How I build my website</title>
      <link>https://www.0x1ad2.dev/blog/how-i-build-my-website</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/how-i-build-my-website</guid>
      <pubDate>Sat, 10 Oct 2026 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>The stack, the guardrails and the blog features behind 0x1ad2.dev, with live three.js demos you can pause, restart and read.</description>
      <category>react</category>
      <category>vite</category>
      <category>threejs</category>
      <category>typescript</category>
      <category>blogging</category>
      <content:encoded><![CDATA[<p>This site is a small React application that I treat like a client project. It has a component library, a content pipeline, tests in two runners and a CI gate. It also has more animation than any client would sign off on. This post walks through how it fits together, from the stack to the blog features, ending with three.js demos that run right inside the article.</p>
<p>Everything below describes the code in the repository today. When something is a trade-off rather than a win, I say so.</p>
<h2>The stack at a glance</h2>
<table><thead><tr><th>Layer</th><th>Choice</th></tr></thead><tbody><tr><td>UI</td><td>React 19 and TypeScript</td></tr><tr><td>Build</td><td>Vite, with Tailwind CSS v4 through its Vite plugin</td></tr><tr><td>Routing</td><td>React Router with lazy route modules</td></tr><tr><td>Components</td><td>shadcn/ui primitives on Radix, plus effects from Magic UI and React Bits</td></tr><tr><td>Motion</td><td><code>motion</code> for springs and layout animation, CSS for the rest</td></tr><tr><td>WebGL</td><td>three.js for the hero backgrounds and the demos in this post, plus ogl for one alternative background</td></tr><tr><td>Quality</td><td>Oxlint, Vitest with Testing Library, Playwright, GitHub Actions</td></tr></tbody></table>
<p>The components live in the repository rather than in a package. shadcn/ui and the React Bits registry both work that way: <code>npx shadcn add</code> copies the source into <code>src/components/ui</code>, and from then on it&#x27;s my code to read, trim and test. The effects sidebar&#x27;s Jelly Radio came from the React Bits registry the same way.</p>
<p>There is no server. <code>npm run build</code> produces static files, and the host only needs to rewrite deep links such as <code>/blog/how-i-build-my-website</code> to <code>index.html</code>.</p>
<h2>Pages, routes and lazy loading</h2>
<p>The home page ships in the main bundle so the first visit paints quickly. Every other page is a lazy route, so its code downloads only when someone navigates there:</p>
<pre><code class="language-tsx">{
  path: &quot;blog/:slug&quot;,
  lazy: async () =&gt; ({ Component: (await import(&quot;@/pages/BlogPostPage&quot;)).BlogPostPage }),
},
</code></pre>
<p>Each route group also has an <code>errorElement</code>. If a chunk fails to load (a flaky connection or a deploy mid-visit), the header and footer stay on screen and the reader gets a way back instead of a blank page. A Playwright test blocks the About page chunk on purpose to prove that.</p>
<h2>The hero background and its guardrails</h2>
<p>The home page hero runs React Bits&#x27; <a href="https://reactbits.dev/backgrounds/crt-warp">CRT Warp</a> by default: blocky plasma on a curved CRT screen with scanlines, bloom and a slight RGB split, all in one three.js fragment shader. Moving your cursor bends the screen. I dimmed it from its defaults so the name and copy stay readable on top. Two earlier heroes are still available from the effects sidebar described below: React Bits&#x27; <a href="https://reactbits.dev/backgrounds/pattern-waves">Pattern Waves</a>, a halftone surface of dots rendered with the small <a href="https://github.com/oframe/ogl">ogl</a> library, and <a href="https://reactbits.dev/backgrounds/light-pillar">Light Pillar</a>, a raymarched column of light. Both take their colours from the page&#x27;s primary hue, which changes on every visit (more on that below). The backgrounds are the heaviest things on the site, so they come with three guardrails:</p>
<ol>
<li><strong>It&#x27;s optional.</strong> The component is lazy-loaded and only rendered when <code>supportsWebGL()</code> can create a WebGL2 context.</li>
<li><strong>It can&#x27;t take the page down.</strong> It sits inside a <code>BackgroundBoundary</code>, an error boundary that renders nothing if the canvas throws.</li>
<li><strong>It stops when nobody can see it.</strong> A small hook pauses the frame loop off-screen and in background tabs.</li>
</ol>
<pre><code class="language-ts">// Keep mounted GPU resources, but stop requesting frames outside the viewport.
export function useAnimationActive(ref: RefObject&lt;HTMLElement | null&gt;) {
  const [active, setActive] = useState(true)

  useEffect(() =&gt; {
    let inView = true
    const update = () =&gt; setActive(inView &amp;&amp; document.visibilityState !== &quot;hidden&quot;)
    const observer = typeof IntersectionObserver === &quot;undefined&quot; ? undefined : new IntersectionObserver(
      ([entry]) =&gt; {
        inView = entry.isIntersecting
        update()
      }
    )
    if (ref.current) observer?.observe(ref.current)
    document.addEventListener(&quot;visibilitychange&quot;, update)
    update()
    return () =&gt; {
      observer?.disconnect()
      document.removeEventListener(&quot;visibilitychange&quot;, update)
    }
  }, [ref])

  return active
}
</code></pre>
<p>That same hook drives the neon progress bar and every three.js demo further down this page. With reduced motion turned on, either hero background renders one still frame and never starts its loop.</p>
<h2>A new primary colour on every visit</h2>
<p>Reload the page and the accent changes. Buttons, links, focus rings, the reading-progress bar, the hero background, the demo colours below and even the favicon all follow it. Everything themed derives from one CSS variable, <code>--accent-hue</code>, an OKLCH hue angle:</p>
<pre><code class="language-css">:root {
  --accent-hue: 295;
  --primary: oklch(0.65 0.2 var(--accent-hue));
  --highlight: oklch(0.78 0.14 calc(var(--accent-hue) + 40));
  --ring: oklch(0.65 0.2 var(--accent-hue));
}
</code></pre>
<p>A tiny inline script in <code>index.html</code> picks a hue from a curated list before the first paint, so there&#x27;s no flash of purple. It also avoids repeating the previous visit&#x27;s hue. OKLCH keeps lightness perceptually even, so a blue primary looks as bright as an orange one and text contrast barely moves between hues.</p>
<p>CSS can&#x27;t feed a three.js material or <code>canvas-confetti</code>, so <code>src/lib/accent.ts</code> reads the variable back and converts OKLCH to hex in about fifteen lines. That&#x27;s how the hero backgrounds, the demos and the confetti get their colours.</p>
<h2>A glowing status dot</h2>
<p>The availability pill in the hero is deliberately plain: a soft border, small text and a green dot with a CSS ping. The only flourish is on the dot itself, which glows like a tiny LED. That&#x27;s three stacked shadows on one element, a tight bright core and two wider, fainter halos:</p>
<pre><code class="language-tsx">&lt;span className=&quot;relative flex size-2&quot;&gt;
  &lt;span className=&quot;absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-75 motion-reduce:animate-none&quot; /&gt;
  &lt;span className=&quot;relative inline-flex size-2 rounded-full bg-emerald-300 shadow-[0_0_4px_#6ee7b7,0_0_10px_#10b981,0_0_18px_#10b98199]&quot; /&gt;
&lt;/span&gt;
</code></pre>
<p>The glow is static, so it costs nothing per frame. With reduced motion turned on, the ping stops and the dot keeps glowing.</p>
<p>Try the same trick here. Change the shadow sizes or colours and press <strong>Run</strong>:</p>
<pre><code class="language-html-live">&lt;style&gt;
  body { background: #07060b; display: grid; place-items: center; min-height: 10rem; }
  .pill {
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .25rem .75rem .25rem .5rem;
    border: 1px solid rgb(255 255 255 / .15); border-radius: 999px;
    background: rgb(255 255 255 / .05);
    color: rgb(255 255 255 / .8); font: 500 .75rem system-ui, sans-serif;
  }
  .dot {
    width: .5rem; height: .5rem; border-radius: 50%;
    background: #6ee7b7;
    box-shadow: 0 0 4px #6ee7b7, 0 0 10px #10b981, 0 0 18px #10b98199;
  }
&lt;/style&gt;
&lt;span class=&quot;pill&quot;&gt;&lt;span class=&quot;dot&quot;&gt;&lt;/span&gt;Available for select consulting engagements&lt;/span&gt;
</code></pre>
<h2>A neon reading-progress bar</h2>
<p>The thin bar at the very top of the window fills as you scroll and reaches the right edge at the bottom of the page. It&#x27;s a neon tube: when you start scrolling from the top, it strikes with a flicker, then hums gently while it&#x27;s lit. The behaviour and prop names follow React Bits Pro&#x27;s <a href="https://pro.reactbits.dev/docs/components/neon-reveal">Neon Reveal</a>. My version in <code>src/components/ui/neon-reveal.tsx</code> uses the Web Animations API rather than a canvas.</p>
<p>The tube itself doesn&#x27;t know about scrolling. A wrapper sets its width from <code>motion</code>&#x27;s scroll progress and asks it to strike again each time the page leaves the top:</p>
<pre><code class="language-tsx">const { scrollYProgress } = useScroll()
const width = useTransform(scrollYProgress, (value) =&gt; `${value * 100}%`)

useMotionValueEvent(scrollYProgress, &quot;change&quot;, (value) =&gt; {
  if (value &gt; 0 &amp;&amp; !lit.current) {
    lit.current = true
    neon.current?.replay()
  } else if (value === 0) {
    lit.current = false
  }
})
</code></pre>
<p>Animating <code>width</code> instead of <code>scaleX</code> keeps the glow&#x27;s rounded ends from being squashed while the bar is short. Every ignition animation uses a backwards fill, so nothing lingers on the element once it finishes. With reduced motion on, the bar still tracks your position but never flickers.</p>
<h2>An effects sidebar at the edge of the screen</h2>
<p>Move your mouse to the right edge of the window and a panel slides in. It lets you pick the pointer effect for the whole site: <strong>Sparks</strong> on click (the default), a neon <strong>Trail</strong> behind the cursor, a small burst of <strong>Confetti</strong>, or <strong>Off</strong>. It also has a hidden extra: a second choice that switches the home page hero between <strong>CRT</strong>, <strong>Waves</strong> and <strong>Light pillar</strong>. Both choices are React Bits Jelly Radios. The pointer effect is saved in <code>localStorage</code>, so it survives future visits. The hero choice lasts only for the tab&#x27;s session, so every new visit starts with the CRT.</p>
<p>The edge detection is a single passive <code>pointermove</code> listener. The pointer has to stay in the last 12 pixels for 120 ms before the panel opens, so a quick trip to the scrollbar doesn&#x27;t trigger it. Moving well to the left closes it again:</p>
<pre><code class="language-ts">const onPointerMove = (event: PointerEvent) =&gt; {
  if (event.pointerType === &quot;touch&quot;) return
  if (modeRef.current === null) {
    const nearEdge = event.clientX &gt;= document.documentElement.clientWidth - EDGE_ZONE
    if (nearEdge &amp;&amp; event.buttons === 0) dwell ??= setTimeout(() =&gt; setMode(&quot;hover&quot;), EDGE_DWELL)
    else clearDwell()
  } else if (modeRef.current === &quot;hover&quot; &amp;&amp; panelRef.current) {
    if (event.clientX &lt; panelRef.current.getBoundingClientRect().left - LEAVE_DISTANCE) setMode(null)
  }
}
</code></pre>
<p>Hover-only features exclude touch and keyboard users, so a slim handle on the edge opens the same panel with a tap or Enter, and focus moves to the selected option. While closed, the panel is <code>inert</code>, so it never traps Tab. Each effect only runs a frame loop while something is moving. With reduced motion on, the choices are disabled and the panel explains why.</p>
<h2>Posts are Markdown files</h2>
<p>There&#x27;s no CMS. A post is a Markdown file in <code>src/content/blog</code>, reviewed in a pull request like any other change. The filename becomes the slug:</p>
<pre><code class="language-md">---
title: &quot;🏗️ How I build my website&quot;
description: A concrete promise to the reader.
date: 2026-10-10
tags: [react, threejs]
draft: true
---

## Start with the problem
</code></pre>
<p>The frontmatter parser in <code>src/lib/blog-content.ts</code> supports a deliberate subset: one-line strings, inline lists and booleans. Drafts appear in development and are left out of production builds. Vite&#x27;s glob import turns every file into a string at build time:</p>
<pre><code class="language-ts">export const posts = collectPosts(
  import.meta.glob&lt;string&gt;(&quot;/src/content/blog/*.md&quot;, {
    query: &quot;?raw&quot;,
    import: &quot;default&quot;,
    eager: true,
  }),
  { includeDrafts: import.meta.env.DEV }
)
</code></pre>
<p>A small Vite plugin parses every post again, drafts included, during <code>npm run build</code>. A missing title, an impossible date such as <code>2026-02-30</code>, or an embedded demo that doesn&#x27;t exist fails the build rather than shipping a broken page.</p>
<p>The trade-off is honest: posts are bundled into client code, so drafts aren&#x27;t secret, and the initial HTML doesn&#x27;t contain the article. For a personal blog, a reviewed diff per post is worth it.</p>
<h2>From Markdown to a reading page</h2>
<p><code>react-markdown</code> with <code>remark-gfm</code> renders the body, and the post page adds the reading furniture:</p>
<ul>
<li><strong>Reading time</strong> counts prose only. Code blocks are stripped first, so a long snippet doesn&#x27;t inflate the estimate.</li>
<li><strong>Table of contents.</strong> Every <code>##</code> heading gets a slug id and a hover anchor. The sidebar list is React Bits&#x27; <a href="https://reactbits.dev/components/line-sidebar">Line Sidebar</a>: items near your cursor lean out and take the accent colour, and an <code>IntersectionObserver</code> lights up the section you&#x27;re reading. I changed its items from click handlers to real links, so Tab, Enter and the URL hash all work, and keyboard focus lights an item the same way hover does.</li>
<li><strong>Search and tags</strong> on the blog index live in URL parameters, so a filtered view is a shareable link.</li>
<li><strong>Share</strong> copies the post URL and confirms with a toast, or explains when the clipboard is blocked.</li>
<li><strong>Reduced-motion notice.</strong> If your system asks for less motion, the post says which animations are paused and that the examples still work.</li>
</ul>
<h2>Code blocks you can copy and run</h2>
<p>Each fenced block goes through one <code>Pre</code> component, which reads the fence&#x27;s language and picks a renderer:</p>
<pre><code class="language-tsx">function Pre({ children }: { children?: ReactNode }) {
  const code = textOf(children).replace(/\n$/, &quot;&quot;)
  const language = languageOf(children)

  if (language === &quot;html-live&quot;) return &lt;CodePlayground source={code} /&gt;
  if (language === THREE_DEMO_LANGUAGE) {
    return (
      &lt;BackgroundBoundary fallback={&lt;DemoMessage&gt;This demo couldn&#x27;t load. Reload the page to try again.&lt;/DemoMessage&gt;}&gt;
        &lt;Suspense fallback={&lt;DemoMessage&gt;Loading demo…&lt;/DemoMessage&gt;}&gt;
          &lt;ThreeDemo name={code.trim()} /&gt;
        &lt;/Suspense&gt;
      &lt;/BackgroundBoundary&gt;
    )
  }
  return &lt;CodeBlock code={code} language={language} /&gt;
}
</code></pre>
<p>Plain blocks get line numbers, a deliberately tiny regex tokenizer for colour, and a copy button. It&#x27;s not a real parser, but it covers the TypeScript, TSX and HTML I write about without shipping a highlighting engine.</p>
<p><code>html-live</code> blocks, like the glowing dot example above, become an editor next to a preview. The preview is an <code>iframe</code> with <code>sandbox=&quot;allow-scripts&quot;</code> and a Content Security Policy of <code>default-src &#x27;none&#x27;</code>. Scripts run, but they can&#x27;t touch this page, its storage or the network.</p>
<h2>Three.js demos inside a post</h2>
<p>That sandbox is exactly why three.js demos need their own path. The <code>iframe</code> can&#x27;t load modules, so a <code>three-demo</code> fence names a TypeScript file in <code>src/components/blog/three-demos/</code> instead:</p>
<pre><code class="language-md">Here is the spinning cube:

~~~three-demo
spinning-cube
~~~
</code></pre>
<p>Every demo exports a <code>mount(canvas, { accent })</code> function with the same small contract. <code>accent</code> is this visit&#x27;s primary colour as hex. The demo owns its renderer and scene. The host owns everything around it:</p>
<pre><code class="language-ts">export type Demo = {
  frame: (seconds: number) =&gt; void
  resize: (width: number, height: number) =&gt; void
  dispose: () =&gt; void
}

export type DemoOptions = { accent: string }
</code></pre>
<p>The host component loads the module and its raw source with two lazy <code>import.meta.glob</code> calls. The code under each demo is therefore the file that&#x27;s running, not a copy that can drift. three.js itself only downloads when a post contains a demo. The host also:</p>
<ul>
<li>drives one <code>requestAnimationFrame</code> loop that stops off-screen, in hidden tabs and when you press <strong>Pause</strong></li>
<li>re-renders a still frame when the canvas resizes while paused</li>
<li>calls <code>dispose()</code> on unmount so geometries, materials and the renderer are released</li>
<li>starts paused for reduced-motion readers, who can opt in with <strong>Play</strong></li>
<li>shows the source with an explanation when WebGL isn&#x27;t available</li>
</ul>
<h3>A first scene</h3>
<p>The smallest useful scene is a renderer, a camera and one lit mesh. Rotation comes from elapsed seconds rather than a per-frame increment, so pausing, restarting and frame drops all behave predictably:</p>
<pre><code class="language-three-demo">spinning-cube
</code></pre>
<h3>Rewriting geometry every frame</h3>
<p>Here, 3,136 points share one <code>BufferAttribute</code>. Each frame rewrites their heights in place and sets <code>needsUpdate</code>, which uploads the buffer once without allocating anything. Move your pointer over the canvas to move the ripple. The listener is removed in <code>dispose</code>, like every other resource:</p>
<pre><code class="language-three-demo">pointer-ripples
</code></pre>
<h3>Ordered dithering in a shader</h3>
<p>The site&#x27;s previous hero used an ordered-dither pass. This demo is the same idea in under 20 lines of GLSL. A moving gradient is quantised to four shades, and a 4×4 Bayer matrix decides which pixels round up, so it reads as a smooth ramp from a distance:</p>
<pre><code class="language-three-demo">ordered-dither
</code></pre>
<p>To add a demo, drop a file that exports <code>mount</code> into the folder and reference it from a fence. The build checks that the name exists.</p>
<h2>Testing and shipping</h2>
<p>Vitest runs unit and integration tests in jsdom: the frontmatter parser, date validation, routes and the playground. jsdom has no WebGL, so those tests check the fallbacks. Playwright runs the production build in Chromium, WebKit and a mobile viewport. It checks that every post renders its code blocks and anchors, that the hero canvas pauses off-screen, that a failed chunk keeps navigation alive, and that the effects sidebar opens from the edge and remembers its choice.</p>
<p><code>npm run check</code> runs lint, tests and the build locally. CI runs the same steps plus the browser suite on every pull request and every push to <code>main</code>. Dependabot proposes weekly updates, and the workflow actions are pinned to commits.</p>
<p>That&#x27;s the whole machine: a static React app, Markdown in the repository, and enough guardrails that the fun parts (neon tubes, shaders, confetti) can&#x27;t make the reading worse.</p>]]></content:encoded>
    </item>
    <item>
      <title>Part 1: Create your first Next.js application</title>
      <link>https://www.0x1ad2.dev/blog/create-your-first-nextjs-application</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/create-your-first-nextjs-application</guid>
      <pubDate>Tue, 28 Apr 2020 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>A step-by-step guide to scaffolding a Next.js app with Yarn, styled-components and dotenv, and rendering your first page.</description>
      <category>nextjs</category>
      <category>react</category>
      <category>nodejs</category>
      <category>tutorial</category>
      <content:encoded><![CDATA[<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/create-your-first-nextjs-application/01.webp" alt="Orange DevJam Next.js mini-series banner"/></p>
<h2>What is Next.js</h2>
<p>Next.js is a minimalistic framework for server-rendered (SSR), and production-ready React applications. Here are some other cool features Next.js brings to the table:</p>
<ul>
<li>An intuitive page-based routing system (with support for dynamic routes)</li>
<li>Automatically statically optimizes page(s) when possible</li>
<li>Server-side renders page(s) with blocking data requirements</li>
<li>Automatic code splitting for faster page loads</li>
<li>Client-side routing with optimized page prefetching</li>
<li>Built-in CSS support, and support for any CSS-in-JS library</li>
<li>Webpack-based dev environment which supports <a href="https://webpack.js.org/concepts/hot-module-replacement/">Hot Module Replacement</a> (HMR)</li>
<li>API routes to build your API with serverless functions, with the same simple router used for pages</li>
<li>Customizable with community plugins and with your own Babel and Webpack configurations</li>
</ul>
<h2>What we are going to create</h2>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/create-your-first-nextjs-application/02.webp" alt="Browser at localhost:3000/placeholder showing the DevJam logo and “Woo-hoo you&#x27;ve created your first Next.js app”"/></p>
<h2>Prerequisites</h2>
<p>Before creating our first Next.js project, there are some essential dependencies that you need to install in order to at least run our app and install our application-specific dependencies:</p>
<ul>
<li><a href="https://nodejs.org/en/">NodeJS</a>: NodeJS is a cross-platform JavaScript run-time that executes JavaScript code outside of the browser. NodeJS lets developers use JavaScript to write command-line tools and server-side applications.</li>
<li><a href="https://yarnpkg.com/">Yarn</a>: Yarn is a package manager for your code. It allows you to use and share (e.g., JavaScript) code with other developers from around the world. Yarn does this quickly, securely, and reliably so you don’t ever have to worry.</li>
<li><a href="https://code.visualstudio.com/">Visual Studio Code</a>: Visual Studio Code is a lightweight but powerful source code editor that runs on your desktop and is available for Windows, macOS, and Linux. It comes with built-in support for JavaScript, TypeScript, and Node.js and has a rich ecosystem of extensions for other languages (e.g., C++, C#, Java, Python, PHP, Go) and runtimes (e.g., .NET and Unity).</li>
</ul>
<blockquote>
<p>I’m in favor of Yarn but you could also use NPM instead if you want to! Both are good tools for managing your packages.</p>
</blockquote>
<h2>Setup your project</h2>
<p>With those essential dependencies installed, we are now able to scaffold our first project using the yarn interactive setup form.</p>
<blockquote>
<p>If you don’t know what mkdir, cd and other CLI commands mean <a href="https://openclassrooms.com/en/courses/4614926-learn-the-command-line-in-terminal">click here</a></p>
</blockquote>
<p>Create a new folder on your system where your project lives. I call our new folder “devjam-dasboard”.</p>
<pre><code class="language-sh">$ mkdir devjam-dashboard
</code></pre>
<p>Traverse into that directory</p>
<pre><code class="language-sh">$ cd devjam-dashboard
</code></pre>
<p>Initialize a new Yarn project</p>
<pre><code class="language-sh">$ yarn init
</code></pre>
<p>This command walks you through an interactive session to create a package.json file, after that we can start adding our application-specific dependencies.</p>
<h3>Install dependencies</h3>
<p>We’re going to add a whole lot of packages to the application, most of them are a must-have (some of them aren’t used in this part of the series yet).</p>
<pre><code class="language-sh">$ yarn add body-parser dotenv dotenv-webpack express isomorphic-fetch next react react-dom styled-components bootstrap react-bootstrap
</code></pre>
<p>If everything did go well our <strong>package.json</strong> should look like this</p>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;devjam-dashboard&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;A small administrative dashboard for DevJam.&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;author&quot;: &quot;Dennis Bruijn&quot;,
  &quot;license&quot;: &quot;MIT&quot;,
  &quot;dependencies&quot;: {
    &quot;body-parser&quot;: &quot;^1.19.0&quot;,
    &quot;bootstrap&quot;: &quot;^4.4.1&quot;,
    &quot;dotenv&quot;: &quot;^8.2.0&quot;,
    &quot;dotenv-webpack&quot;: &quot;^1.7.0&quot;,
    &quot;express&quot;: &quot;^4.17.1&quot;,
    &quot;isomorphic-fetch&quot;: &quot;^2.2.1&quot;,
    &quot;next&quot;: &quot;^9.3.5&quot;,
    &quot;react&quot;: &quot;^16.13.1&quot;,
    &quot;react-bootstrap&quot;: &quot;^1.0.0&quot;,
    &quot;react-dom&quot;: &quot;^16.13.1&quot;,
    &quot;styled-components&quot;: &quot;^5.1.0&quot;
  }
}
</code></pre>
<ul>
<li><a href="https://github.com/expressjs/body-parser">body-parser</a>: This package lets your NodeJS application parse different types of request bodies (e.g., application/JSON).</li>
<li><a href="https://github.com/motdotla/dotenv">dotenv</a>: Loads environment variables from .env for NodeJS projects.</li>
<li><a href="https://github.com/mrsteele/dotenv-webpack">dotenv-webpack</a>: A secure webpack plugin that supports dotenv and other environment variables and only exposes what you choose and use.</li>
<li><a href="https://github.com/expressjs/express">Express</a>: Fast, unopinionated, minimalist web framework for NodeJS</li>
<li><a href="https://github.com/matthew-andrews/isomorphic-fetch">isomorphic-fetch</a>: This package adds an <em>isomorphic</em> fetch function that you can use both on the front-end and the back-end.</li>
<li><a href="https://github.com/vercel/next.js">Next.js</a>, <a href="https://github.com/facebook/react">react</a>, and <a href="https://auth0.com/blog/next-js-authentication-tutorial/">react-dom</a>: Together, these packages let you build React apps with Next on top.</li>
<li><a href="https://github.com/twbs/bootstrap">bootstrap</a> and <a href="https://github.com/react-bootstrap/react-bootstrap">react-bootstrap</a>: These packages allow you to use Bootstrap components without having to use jQuery.</li>
<li><a href="https://styled-components.com/">styled-components</a>: Utilising tagged template literals (a recent addition to JavaScript) and the power of CSS, styled-components allows you to write actual CSS code to style your components.</li>
</ul>
<h3>Launching from the command line</h3>
<p>Launching Visual Studio Code from the terminal looks cool and is a productive way to edit (if you split your screen with the terminal on one side and Code on the other).</p>
<p>To enable this, press <strong>cmd + shift + P</strong>, type in <strong>shell command,</strong> and select <strong>Install code command in path</strong></p>
<h3>Configure babel</h3>
<p>Create a file called .babelrc inside the project root</p>
<pre><code class="language-sh">$ touch .babelrc
</code></pre>
<p>Open the file</p>
<pre><code class="language-sh">$ code .babelrc
</code></pre>
<p>Paste the following into the file and hit save.</p>
<pre><code class="language-json">{
  &quot;presets&quot;: [&quot;next/babel&quot;],
  &quot;plugins&quot;: [[&quot;styled-components&quot;, { &quot;ssr&quot;: true }]]
}
</code></pre>
<p>This will make styled-components work with Next.js and let Babel know that you are developing with this package. Configuring Babel with <a href="https://nextjs.org/blog/next-7#babel-7">the next/babel preset is needed</a> to make this package compile your code correctly.</p>
<h3>Configure dotenv</h3>
<p>Create a file called .env inside the project root</p>
<pre><code class="language-sh">$ touch .env
</code></pre>
<p>Open the file</p>
<pre><code class="language-sh">$ code .env
</code></pre>
<p>Paste the following into the file and hit save.</p>
<pre><code class="language-ini">PORT=3000
</code></pre>
<p>An env file is a simple configuration text file that is used to define some variables you want to pass into your application’s environment. This file needs something like a parser to make it work. The parser reads the variable definitions one-by-one and parses them to the environment. In our case, the parser is webpack in combination with dotenv.</p>
<h3>Configure Next.js</h3>
<p>Create a file called .next.config.js inside the project root</p>
<pre><code class="language-sh">$ touch next.config.js
</code></pre>
<p>Open the file</p>
<pre><code class="language-sh">$ code next.config.js
</code></pre>
<p>Paste the following into the file and hit save.</p>
<pre><code class="language-js">require(&quot;dotenv&quot;).config();

const path = require(&quot;path&quot;);
const Dotenv = require(&quot;dotenv-webpack&quot;);

module.exports = {
  webpack: config =&gt; {
    config.plugins = config.plugins || [];

    config.plugins = [
      ...config.plugins,

      new Dotenv({
        path: path.join(__dirname, &quot;.env&quot;),
        systemvars: true
      })
    ];

    return config;
  }
};
</code></pre>
<p>A Next.js config file is a regular NodeJS module, not a JSON file. It is used by the Next.js server and build phases, and it’s not included in the browser build.</p>
<h2>Let’s build!</h2>
<h3>Create a pages directory</h3>
<p>In Next.js, a <strong>page</strong> is a <a href="https://legacy.reactjs.org/docs/components-and-props.html">React Component</a> exported from a .js, jsx, .ts, or .tsx file in the pages directory.</p>
<pre><code class="language-sh">$ mkdir -p src/pages
^ the -p flag makes sure src is created first
</code></pre>
<h3>Add a new page</h3>
<p>Create a file called placeholder.js inside the src/pages directory</p>
<pre><code class="language-sh">$ touch src/pages/placeholder.js
</code></pre>
<p>Open the file</p>
<pre><code class="language-sh">$ code src/pages/placeholder.js
</code></pre>
<p>Paste the following into the file and hit save.</p>
<pre><code class="language-jsx">import styled from &quot;styled-components&quot;;

const Placeholder = styled.div`
  margin-top: 25vh;
  text-align: center;
  font-family: Arial, Helvetica, sans-serif;
  img {
    width: 100px;
  }
  h1 {
    color: #4a566e;
  }
`;

function Index() {
  return (
    &lt;Placeholder&gt;
      &lt;img src=&quot;https://cdn-images-1.medium.com/max/222/1*CAL6MRkz-KF6U2oZY4JWJg@2x.png&quot; /&gt;
      &lt;h1&gt;Woo-hoo you&#x27;ve created&lt;/h1&gt;
      &lt;h1&gt; your first Next.js app 🎉&lt;/h1&gt;
    &lt;/Placeholder&gt;
  );
}

export default Index;
</code></pre>
<p>Each page is associated with a route based on its file name. e.g., if you create <strong>pages/placeholder.js</strong> that exports a React component like below, it will be accessible at <strong>domain.io/placeholder</strong></p>
<h3>Run it</h3>
<p>To wrap things in this section, open the package.json file add a script property to the main object.</p>
<p>Open the file package.json</p>
<pre><code class="language-sh">$ code package.json
</code></pre>
<p>Paste the following into the file and hit save.</p>
<pre><code class="language-json">&quot;scripts&quot;: { &quot;dev&quot;: &quot;next&quot; },
</code></pre>
<p>After defining the dev script, you can execute</p>
<pre><code class="language-sh">$ yarn dev
</code></pre>
<p>to run the first version of your Next.js app.</p>
<p>If everything works as expected, in a few seconds, you will be able to open <a href="http://localhost:3000/placeholder">http://localhost:3000/placeholder</a> in a web browser.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/create-your-first-nextjs-application/03.webp" alt="You did it!"/>
<em>You did it!</em></p>
<h2>Github repository</h2>
<p>If you want to check out the code without following the guide or just check if you did everything right <a href="https://github.com/0x1ad2/devjam-next-part-1">DevJam Part 1 — Repository</a></p>]]></content:encoded>
    </item>
    <item>
      <title>⏩ React Live: the interactive conference</title>
      <link>https://www.0x1ad2.dev/blog/react-live-the-interactive-conference</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/react-live-the-interactive-conference</guid>
      <pubDate>Mon, 30 Sep 2019 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>Key learnings from React Live in Amsterdam: Theme UI, SVGR, Framer Motion, Ignite, MobX State Tree and Next.js 9.</description>
      <category>react</category>
      <category>conference</category>
      <category>react-native</category>
      <content:encoded><![CDATA[<p>Two weeks ago I attended the React Live conference; it’s one of the biggest React conferences in the Netherlands. Besides being a conference, Passionate People (the event organizers) tried to spice it up by adding live coding to their sessions.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-live-the-interactive-conference/01.webp" alt="The conference was hosted at Theater Amsterdam, a tier-A location."/>
<em>The conference was hosted at Theater Amsterdam, a tier-A location.</em></p>
<blockquote>
<p>“Most impressive Conference Venue I have ever been too” — Evan You</p>
</blockquote>
<h2>🔑 Key learnings</h2>
<p>I usually write my conference blogs talk by talk, but since everyone is doing that, it’s quite annoying to read. I collected my key learnings below.</p>
<p><strong>Theme UI</strong><br/>
Build consistent; theme-able React apps based on constraint-based design principles.</p>
<p>This way of working allows you, your product team, and the UI/UX team to be consistent when making changes. You can define a theming object based on the rules that the UI/UX team gives you.</p>
<pre><code class="language-js">export default {
  fonts: {
    body: &#x27;system-ui, sans-serif&#x27;,
    heading: &#x27;&quot;Avenir Next&quot;, sans-serif&#x27;,
    monospace: &#x27;Menlo, monospace&#x27;,
  },
  colors: {
    text: &#x27;#000&#x27;,
    background: &#x27;#fff&#x27;,
    primary: &#x27;#33e&#x27;,
  },
}
</code></pre>
<p>You can later use emotion (a CSS-in-JS library) in your components to read the object that you’ve defined.</p>
<blockquote>
<p>You can also tokenize the above values, so they have a single source of truth.</p>
</blockquote>
<p><a href="https://github.com/system-ui/theme-ui">GitHub - system-ui/theme-ui: Build consistent, themeable React apps based on constraint-based design principles</a></p>
<p><strong>Transform SVGs into React components</strong><br/>
SVGR is an SVG to React transformer. The transformed SVG will be a simple React component that becomes highly configurable. SVGR is available as a module, webpack plugin or via CLI.</p>
<p><a href="https://react-svgr.com/">SVGR - SVGR</a></p>
<p><strong>Framer motion</strong><br/>
As an addition to the SVG part, you can use Framer X’s motion library to power your transformed SVG with fluid cross-device animations.</p>
<p><a href="https://motion.dev/">Motion - JavaScript &amp; React animation library</a></p>
<p><strong>Infinite Red Ignite</strong><br/>
Infinite Red has released a new version of their React Native boilerplate tooling called Ignite. Check it out, it’s incredible!</p>
<p><a href="https://github.com/infinitered/ignite">GitHub - infinitered/ignite</a></p>
<p>Besides Ignite, Infinite Red also offers a tool called ReactorTron: a desktop app for inspecting your React and React Native projects on macOS, Linux, and Windows.</p>
<p><a href="https://github.com/infinitered/reactotron">GitHub - infinitered/reactotron: A desktop app for inspecting your React JS and React Native projects. macOS, Linux, and Windows.</a></p>
<p><strong>Mobx state tree</strong><br/>
An Opinionated, transactional, MobX powered state container. That is combining the best features of the immutable and mutable world for an optimal DX.</p>
<p><a href="https://github.com/mobxjs/mobx-state-tree">mobxjs/mobx-state-tree</a></p>
<p>Besides MobX, Overmind was also mentioned as a proper state container <a href="https://overmindjs.org/?view=react">https://overmindjs.org/</a></p>
<blockquote>
<p>I don’t use MobX, but it was refreshing to see what’s possible</p>
</blockquote>
<p><strong>Next level NextJS 9</strong><br/>
<a href="https://x.com/timneutkens">Tim</a> did a live coding session with Zeit’s product NextJS. It was interesting to see what new features have been added since the time I first tried it (over a year ago). It now has zero-config TypeScript support, file-based dynamic routing, automatic static optimization, and many more features.</p>
<p><a href="https://nextjs.org/blog/next-9">Next.js 9</a></p>
<p><a href="https://www.youtube.com/watch?v=B5bKxxaEsUs"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-live-the-interactive-conference/02.webp" alt="Video thumbnail: React Live Conference 2019 - Aftermovie"/></a>
<em>▶ Watch “React Live Conference 2019 - Aftermovie” on YouTube</em></p>
<p><strong>Fun fact:</strong> During the talks, we had WiFi problems, and as you can imagine, that’s not ideal for a live coding conference. 😅 Luckily they managed to fix it rather quickly by providing a UTP cable for the speakers. Shout out to the team!</p>]]></content:encoded>
    </item>
    <item>
      <title>⚡️ Build your own CLI power tool using NodeJS</title>
      <link>https://www.0x1ad2.dev/blog/build-your-own-cli-power-tool-using-nodejs</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/build-your-own-cli-power-tool-using-nodejs</guid>
      <pubDate>Sun, 28 Jul 2019 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>Automate setting up a new machine with a small Node.js CLI that uses Enquirer and Homebrew to install the apps you always need.</description>
      <category>nodejs</category>
      <category>cli</category>
      <category>tutorial</category>
      <content:encoded><![CDATA[<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/build-your-own-cli-power-tool-using-nodejs/01.webp" alt="Banner with a cartoon robot and the title Build your own CLI power tool using NodeJS, with Node.js and Sytac logos"/></p>
<p>Hopefully, some of you can relate to the following problem. You buy yourself a new machine or get a new device from a client to work with. You go to the process of installing, updating, and configuring the device. Even worse when you’re done store your work in a safe place, sign off across the system and format your SSD.</p>
<h2>What are we using</h2>
<p><strong>NodeJS</strong><br/>
NodeJS is a cross-platform JavaScript run-time that executes JavaScript code outside of the browser. NodeJS lets developers use JavaScript to write command-line tools and server-side applications.</p>
<p><strong>Enquirer</strong><br/>
Enquirer is fast, easy to use, and lightweight system to build stylish, intuitive, and user-friendly prompts.<br/>
<a href="https://github.com/enquirer/enquirer">https://github.com/enquirer/enquirer</a></p>
<h2>What are we building</h2>
<p>For this use case, we can make ourselves a powerful command-line interface to automate some of these tasks. Since NodeJS allows us to write and execute code that primarily interacts with the system disk and network, tasks like downloading and installing binaries will become a breeze.</p>
<h2>Setup a new project</h2>
<p>Make sure you’ve got a terminal of choice set up (I use Zsh with oh-my-zsh). Also, get homebrew for Mac so we can fetch binaries and install them via CLI commands.</p>
<p><strong>1.) Create a new directory called “node-power-cli”</strong></p>
<pre><code class="language-sh">$ mkdir ~/Projects/node-power-cli
</code></pre>
<p><strong>2.) Traverse into that directory</strong></p>
<pre><code class="language-sh">$ cd ~/Projects/node-power-cli
</code></pre>
<p><strong>3.) Grab the MIT license and add it to the project</strong></p>
<pre><code class="language-sh">$ npx license mit &gt; LICENSE
</code></pre>
<p><strong>4.) Add a .gitignore file to the project</strong></p>
<pre><code class="language-sh">$ npx gitignore node
</code></pre>
<p><strong>5.) Generate a new package.json file</strong></p>
<pre><code class="language-sh">$ npm init -y
</code></pre>
<p><strong>6.) Create a new file</strong></p>
<pre><code class="language-sh">$ touch power-cli.js
</code></pre>
<p><strong>7.) Allow the file to be executed</strong></p>
<pre><code class="language-sh">$ chmod u+x power-cli.js
</code></pre>
<p><strong>8.) Edit the new file</strong></p>
<pre><code class="language-sh">$ code power-cli.js
</code></pre>
<pre><code class="language-js">#! /usr/bin/env node
// will tell shell enviroment which program it needs execute this, in our case it&#x27;s node
// always run your code in strict mode
&quot;use strict&quot;;

console.log(`My first Node CLI app 🎉`);
</code></pre>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/build-your-own-cli-power-tool-using-nodejs/02.webp" alt="To execute your NodeJS script, you can use the following command $ ./power-cli.js"/>
<em>To execute your NodeJS script, you can use the following command $ ./power-cli.js</em></p>
<blockquote>
<p><em>If you’ve not seen npx before, it searches locally to see if there is a command to run and executes it. If there is no local command, it will try to download, install the command from npm, and run it. This is useful when generating new projects and saves you from globally installing a lot of stuff.</em></p>
</blockquote>
<h2>Add and use Enquirer</h2>
<p><strong>1.) Install Enquirer</strong></p>
<pre><code class="language-sh">$ npm install enquirer --save
</code></pre>
<p><strong>2.) Define your list of frequently used binaries</strong></p>
<pre><code class="language-js">// make a list of frequently used binaries
const frequentlyUsedBinaries = [
  &quot;iterm2&quot;,
  &quot;visual-studio-code&quot;,
  &quot;google-chrome&quot;,
  &quot;zsh&quot;,
  &quot;whatsapp&quot;,
  &quot;spectacle&quot;,
  &quot;spotify&quot;,
  &quot;slack&quot;,
  &quot;github&quot;,
  &quot;node&quot;,
  &quot;grammarly&quot;,
  &quot;figma&quot;
];
</code></pre>
<p><strong>3.) Add multi-select prompt</strong></p>
<pre><code class="language-js">// require the enquirer module
const { MultiSelect } = require(&quot;enquirer&quot;);

// create a new multi select prompt
const multiSelectPrompt = new MultiSelect({
  name: &quot;value&quot;,
  message: &quot;Select all the binaries that you want to install&quot;,
  choices: frequentlyUsedBinaries
});

// run the prompt and handle the answer
multiSelectPrompt
  .run()
  .then(binaries =&gt; {
    console.log(&quot;Selected binaries:&quot;, binaries);
  })
  .catch(console.error);
</code></pre>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/build-your-own-cli-power-tool-using-nodejs/03.webp" alt="To execute your NodeJS script, you can use the following command $ ./power-cli.js"/>
<em>To execute your NodeJS script, you can use the following command $ ./power-cli.js</em></p>
<h2>Execute CLI commands</h2>
<p>Now we get an answer from the multi-select prompt, and we can parse that to a function to generate a command-line string. After that use brew to install all the selected binaries.</p>
<pre><code class="language-js">// require utility tools and child_process exec to execute CLI commands
const util = require(&quot;util&quot;);
const exec = util.promisify(require(&quot;child_process&quot;).exec);

// define a async function execute commands
async function executeCommands(CommandLineString) {
  const { stdout, stderr } = await exec(CommandLineString);
  console.log(&quot;Standard output:&quot;, stdout);
  console.log(&quot;Standard error:&quot;, stderr);
}

// create command line string
function getCommandLIneString(binaries) {
  return binaries
    .map(binary =&gt; {
      return `brew cask install ${binary} &amp;&amp;`;
    })
    .join()
    .replace(/,/g, &quot; &quot;)
    .slice(0, -3);
}

// run the prompt and handle the answer
multiSelectPrompt
  .run()
  .then(binaries =&gt; {
    console.log(&quot;Selected binaries:&quot;, binaries);
    console.log(&quot;Installing them all&quot;);
    executeCommands(getCommandLIneString(binaries));
  })
  .catch(console.error);
</code></pre>
<h2>Run it!</h2>
<p>Now we’re done and we can run the program and see if it works the way we expected.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/build-your-own-cli-power-tool-using-nodejs/04.webp" alt="Select the binaries that you want and hit ENTER"/>
<em>Select the binaries that you want and hit ENTER</em></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/build-your-own-cli-power-tool-using-nodejs/05.webp" alt="Terminal output of power-cli.js installing Grammarly and Firefox through Homebrew casks"/></p>
<p>That’s it. There’s your first “friendly &amp; powerful” command-line tool that you can extend with all the possibilities you’ve got in mind — E.G., a feature that sets your <a href="https://pawelgrzybek.com/change-macos-user-preferences-via-command-line/">default user preferences for macOS</a>.</p>
<p>If you have any questions? Either comment on this story or tweet me at @0x1ad2 If you want to check out the project yourself here’s the <a href="https://github.com/0x1ad2/nodejs-power-tool">Github repository</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>🇫🇷 React Europe 2018</title>
      <link>https://www.0x1ad2.dev/blog/react-europe-2018</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/react-europe-2018</guid>
      <pubDate>Sun, 20 May 2018 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>Highlights from React Europe 2018: the Context API, new lifecycle methods, Suspense, Apollo, Replicated Redux, CodeSandbox and Lona.</description>
      <category>react</category>
      <category>conference</category>
      <category>graphql</category>
      <content:encoded><![CDATA[<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/01.webp" alt="ReactEurope 2018 banner over photos of the conference audience and the Eiffel Tower"/></p>
<p>I visited React Europe with my colleague Peter. The conference hold in France just like the previous years. It allowed us to learn a lot of new things about React, GraphQL, React Native, and Reason. Also, a lot of excellent product releases 💕</p>
<p>Here’s a break down with the things I loved the most</p>
<h2>React</h2>
<p><strong>Keynote</strong></p>
<p>It all started with an all-American 🇺🇸 keynote from <a href="https://medium.com/u/e50c25098d37">Ken Wheeler</a> he told us about The state of React, probably a reference to the American State of the Union, I would vote for Ken as President of the React Community (spreading some love here 💙).</p>
<p><strong>Context API</strong><br/>
Context provides a way to pass data through the component tree without having to pass props down manually at every level. So basically teleporting data between components.</p>
<p>There are two main steps to set up the Context API into your application<br/>
1. add a context provider &amp; define the data you want to store<br/>
2. use a context consumer where ever you need the data from the store</p>
<p>Want a code example? Head over to <a href="https://legacy.reactjs.org/docs/context.html">https://legacy.reactjs.org/docs/context.html</a></p>
<p><strong>New lifecycle methods</strong><br/>
We all know the current component lifecycles (componentWillMount, componentWillReceiveProps, and componentWillUpdate). These also happen to be the lifecycles that cause the most confusion within the React community. For these reasons, Facebook is going to deprecate those methods in favor of better alternatives. Those alternatives would be the following.</p>
<p>1. getDerivedStateFromProps is being added as a safer alternative to the legacy componentWillReceiveProps.</p>
<p>2. getSnapshotBeforeUpdate is being added to support safely reading properties from e.g. the DOM before updates are made.</p>
<p>All the legacy lifecycle methods will be available until react 17 comes around the corner, for then the lifecycle methods will be prefixed by “UNSAFE_” to indicate that they might cause issues.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/02.webp" alt="React lifecycle diagram with render, pre-commit and commit phases, including getDerivedStateFromProps and getSnapshotBeforeUpdate"/></p>
<p><strong>Suspense</strong><br/>
And there was React Suspense, it was everywhere, everyone was talking about it Suspense jokes everywhere, even the React Europe cup we got some Suspense stuff on it.</p>
<p>In short: the new feature allows you to defer rendering part of your application tree until some condition is met e.g. loading data from an endpoint or when a resource is loaded.</p>
<p>The mechanism basically works like this as explained by <a href="https://x.com/acdlite">@acdlite</a><br/>
- in the render method, read a value from the cache.<br/>
- if the value is already cached, the render continues like normal<br/>
- if the value is not already cached, the cache *throws a promise*<br/>
- when the promise resolves, React retries where it left off</p>
<p>A good example of suspense would be async placeholders, here’s a code example</p>
<pre><code class="language-jsx">import React, { Fragment } from &quot;react&quot;;

function Placeholder({ delayMs, fallbackUI, children }) {
  return (
    &lt;React.Timeout ms={delayMs}&gt;
      {didTimeout =&gt; {
        return (
          &lt;Fragment&gt;
            &lt;span hidden={didTimeout}&gt;{children}&lt;/span&gt;
            {didTimeout ? fallbackUI : null}
          &lt;/Fragment&gt;
        );
      }}
    &lt;/React.Timeout&gt;
  );
}

export default Placeholder;
</code></pre>
<p>thanks to <a href="https://medium.com/u/c827782c6410">Peggy Rayzis</a>!</p>
<p><a href="https://gist.github.com/peggyrayzis/4c4778e88d9eb71b71b8974836fea044">Placeholder.js on GitHub Gist</a></p>
<p><a href="https://www.youtube.com/watch?v=QFk6YwMz8nc"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/03.webp" alt="Video thumbnail: Keynote - @Ken_Wheeler at @ReactEurope 2018"/></a>
<em>▶ Watch “Keynote - @Ken_Wheeler at @ReactEurope 2018” on YouTube</em></p>
<p><strong>The Case for Whimsy</strong><br/>
<a href="https://medium.com/u/a11edf57e20a">Joshua Comeau</a> give an awesome talk about The Case for Whimsy, we usually tend to just craft new features and fix bugs but besides that, we could also build fun things e.g. at Khan Academy, they fill the user’s screen with confetti rain when they get 100% correct on an exercise. That’s pure joy, go make something fun!</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/04.webp" alt="Animated illustration of confetti, party hats and champagne bottles"/></p>
<p><a href="https://www.youtube.com/watch?v=Z2d9rw9RwyE"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/05.webp" alt="Video thumbnail: The Case for Whimsy - Joshua Comeau aka @joshwcomeau at @ReactEurope 2018"/></a>
<em>▶ Watch “The Case for Whimsy - Joshua Comeau aka @joshwcomeau at @ReactEurope 2018” on YouTube</em></p>
<p><strong>On Apollo</strong><br/>
<a href="https://medium.com/u/c827782c6410">Peggy Rayzis</a> is an Open Source Engineer <a href="https://x.com/apollographql">**@**apollographql</a> the talk was created around the future of Apollo, what’s available right now and what’s the next big thing in the near future.</p>
<p>The new 2.1 version of Appolo now supports Render Props 🎉 a component with a render prop takes a function that returns a React element and calls it instead of implementing its own render logic.</p>
<p>And of course, coming in 2018, Suspense support!</p>
<p><a href="https://www.youtube.com/watch?v=fCXYA3lZTbo"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/06.webp" alt="Video thumbnail: A Journey Through React Apollo - Peggy Rayzis aka @peggyrayzis at @ReactEurope 2018"/></a>
<em>▶ Watch “A Journey Through React Apollo - Peggy Rayzis aka @peggyrayzis at @ReactEurope 2018” on YouTube</em></p>
<p><strong>Replicated Redux</strong><br/>
<a href="https://medium.com/u/8e6c73de31a2">Jim Purbrick</a> is doing awesome things in ReactVR on the Oculus team at Facebook. He showed us the potential of Redux for building networked ReactVR applications.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/07.webp" alt="Avatars gathered around a colourful board game table in a networked React VR room"/></p>
<p>Redux’s reified events, serializable actions and state, middleware, side effect free functional reducers and time travel superpowers make it well suited for building simple, networked, testable decoupled simulations.</p>
<p><a href="https://www.youtube.com/watch?v=Fr3vp0C22H0"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/08.webp" alt="Video thumbnail: Replicated Redux - Jim Purbrick aka @JimPurbrick at @ReactEurope 2018"/></a>
<em>▶ Watch “Replicated Redux - Jim Purbrick aka @JimPurbrick at @ReactEurope 2018” on YouTube</em></p>
<p><strong>A year of CodeSandbox</strong><br/>
<a href="https://medium.com/u/ee6691f0bd65">Ives van Hoorne</a> is the owner of one of the most awesome products currently around, it’s called CodeSandBox, CodeSandbox is an online editor that helps you create web applications, from prototype to deployment.</p>
<p>CodeSandbox recently turned one year old and gave him some valuable insights he’s shared that in his talk ⬇️</p>
<p><a href="https://www.youtube.com/watch?v=qURPenhndYA"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/09.webp" alt="Video thumbnail: A year of CodeSandbox - Ives van Hoorne aka @CompuIves at @ReactEurope 2018"/></a>
<em>▶ Watch “A year of CodeSandbox - Ives van Hoorne aka @CompuIves at @ReactEurope 2018” on YouTube</em></p>
<p><strong>Beyond React</strong></p>
<p><a href="https://medium.com/u/cb21631de456">Devin Abbott</a> is a software engineer working at <a href="https://medium.com/u/ebe93072cafd">AirbnbEng</a> he’s currently working on Lona, a perfect fit for a gap that a lot of companies have, a bridge between design and development. Lona is a design tool that allows you to design flexible, compassable component systems and transpile these components into any language on any platform, such as Swift components on iOS, or Kotlin components on Android.</p>
<p><a href="https://www.youtube.com/watch?v=HVwLOcllTfI"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/10.webp" alt="Video thumbnail: Beyond React - Devin Abbott aka @dvnabbott at @ReactEurope 2018"/></a>
<em>▶ Watch “Beyond React - Devin Abbott aka @dvnabbott at @ReactEurope 2018” on YouTube</em></p>
<p>Check out the Github repo <a href="https://github.com/Lona/Lona">https://github.com/Lona/Lona</a> this tool is 🔥</p>
<p><strong>And last but not least Bridging React Native Back to its Roots</strong></p>
<p>An epic talk by <a href="https://x.com/vincentriemer">@vincentrimer</a> he’s a software engineer at Symantec he released React Native DOM an experimental, comprehensive port of React Native to the web. It’s multithreaded by default, build with the same bundler and it has the same layout behaviour as React Native on mobile.</p>
<p><a href="https://www.youtube.com/watch?v=aOWIJ4Mgb2k"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/react-europe-2018/11.webp" alt="Video thumbnail: Bridging React Native Back to its Roots - Vincent Riemer  (@vincentriemer) at @ReactEurope 2018"/></a>
<em>▶ Watch “Bridging React Native Back to its Roots - Vincent Riemer  (@vincentriemer) at @ReactEurope 2018” on YouTube</em></p>
<p>Check out the Github repo <a href="https://github.com/vincentriemer/react-native-dom">https://github.com/vincentriemer/react-native-dom</a></p>]]></content:encoded>
    </item>
    <item>
      <title>👨🏻‍💻 GDG DevFest 2017</title>
      <link>https://www.0x1ad2.dev/blog/gdg-devfest-2017</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/gdg-devfest-2017</guid>
      <pubDate>Wed, 22 Nov 2017 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>Notes from GDG DevFest 2017 in Amsterdam: Google's machine learning APIs, an early look at Flutter and real-time data lessons from BUX.</description>
      <category>conference</category>
      <category>google</category>
      <category>flutter</category>
      <content:encoded><![CDATA[<p>Last weekend I visited <a href="https://devfest.nl/">GDG DevFest 2017</a> at the University of Amsterdam. This conference is the biggest Google related event in The Netherlands, carefully crafted by the GDG community!</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/gdg-devfest-2017/01.webp" alt="Credits to @elizacamber"/>
<em>Credits to @elizacamber</em></p>
<p>Usually, the conference is visited by approximately 500 attendees and speakers all over the world, several of these attendees are GDE’s (Google Developer Experts) so there’s a lot to learn 🧠</p>
<p>Every year there are three parallel lecture tracks dedicated to Mobile, Web &amp; Cloud technologies.</p>
<h2>Machine Learning APIs and how to get the most of it</h2>
<p>In this session, we dived into what the different Google Cloud Machine Learning APIs can do. We combined various solutions to get an interesting results and they even released a new feature called <a href="https://cloud.google.com/speech/docs/basics#time-offsets">Google speech API timestamps</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/gdg-devfest-2017/02.webp" alt="Collage of a Google Cloud machine learning talk, a slide on two ways to benefit from ML and the GDG DevFest Netherlands banner"/></p>
<h2>Creating your first flutter app</h2>
<p><a href="https://flutter.dev/">Flutter</a> is a new cross-platform SDK from Google to create Android and iOS apps with a single-codebase written in Dart.</p>
<p>It allows fast development through a feature we already knew from React Native called hot reload. Hot reload helps you quickly and easily experiment, build UIs, add features, and fix bug faster.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/gdg-devfest-2017/03.webp" alt="Collage of the “Creating your first flutter app” talk, a code slide and the audience"/></p>
<p>Flutter has built-in beautiful Material Design and Cupertino (iOS-flavor) widgets, rich motion APIs, smooth natural scrolling, and platform awareness to delivery the best experience to the client.</p>
<p>It also allows access to native features and SDKs</p>
<blockquote>
<p>⚠ ️<strong>Be aware of the fact that flutter is still in ALPHA</strong></p>
</blockquote>
<h2>Designing a real-time data application: a case study on the stock market</h2>
<p>Applications that require data from real-time events impose their own challenges. How to store data? Can you cache data at all? How to make sure data that is constantly changing is consistent throughout the app?</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/gdg-devfest-2017/04.webp" alt="Collage of the BUX talk “Designing a real-time data application: a case study on the stock market” and its slide on how trades are matched"/></p>
<p>The guys at BUX have quite a lot experience with this and where happy to share their best practices. I think the main lesson for me was:</p>
<blockquote>
<p>If a technology works (has proven itself) stick with it but do not be afraid to experiment with upcoming technologies.</p>
</blockquote>
<p>They just completed a <a href="https://press.getbux.com/160170-next-generation-trading-app-bux-completes-10-6-million-funding-round/">€10.6 million funding round</a> so I think you’ll see them around.</p>
<p>Altogether I had an amazing day! Attended serval cool talks, met new and old friends and was able to write some code in between. See you next year!</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/gdg-devfest-2017/05.webp" alt="Collage of a laptop with code open, a sandwich lunch and the GDG DevFest Netherlands banner"/></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/gdg-devfest-2017/06.webp" alt="Douglas Adams quote “I may not have gone where I intended to go, but I think I have ended up where I needed to be” above DevFest swag: a fidget spinner, a notebook and an Android sticker"/></p>]]></content:encoded>
    </item>
    <item>
      <title>🔥 Firebase Dev Summit 2017</title>
      <link>https://www.0x1ad2.dev/blog/firebase-dev-summit-2017</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/firebase-dev-summit-2017</guid>
      <pubDate>Tue, 31 Oct 2017 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>What Google showed at the Firebase Dev Summit 2017 in Amsterdam, from Crashlytics and Predictions to Cloud Firestore.</description>
      <category>conference</category>
      <category>firebase</category>
      <category>google</category>
      <content:encoded><![CDATA[<p>Today I visited the Firebase Dev Summit in Amsterdam 🇳🇱 This summit showcased the latest product releases and features. We learned how Firebase helps to solve key infrastructure &amp; growth challenges that the industry faces.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/firebase-dev-summit-2017/01.webp" alt="The Muziekgebouw aan &#x27;t IJ and Bimhuis venue on the Amsterdam waterfront"/></p>
<h2>Huh, Firebase Dev Summit?</h2>
<p>The Firebase Dev Summit is an annual event held by Google. Every year a country is selected to host the summit and the event is mostly based around Firebase.</p>
<p>Since Firebase isn’t just a <a href="https://techcrunch.com/2014/10/21/google-acquires-firebase-to-help-developers-build-better-realtime-apps/">real-time database</a> anymore but a platform that helps developers build, analyze and grow there is a lot of awesome knowledge that could be shared.</p>
<h2>What’s new in Firebase?</h2>
<p>Basically, Google integrated <a href="https://firebase.google.com/docs/crashlytics/">Crashlytics</a> into Firebase, enabled <a href="https://firebase.google.com/docs/ab-testing/abtest-with-console">first-class A/B support</a> and take their first step in bringing the power of Machine Learning 🤖 into Firebase with a new product called <a href="https://firebase.google.com/products/predictions/">Predictions</a>.</p>
<blockquote>
<p>Predictions automatically create dynamic user groups based on predicted behaviour from your analytics, you can use these predictions i.e. to send users who are about to churn in the next 7 days a customised notification</p>
</blockquote>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/firebase-dev-summit-2017/02.webp" alt="Firebase Predictions illustration: players grouped by predicted behaviour, with those about to churn offered three extra lives"/></p>
<p>They are also working hard to prepare for the General Data Protection Regulation (<a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation">GDPR</a>) across Firebase and they are committed to helping us (developers) succeed under it.</p>
<h2>Talks, talks, talks!</h2>
<p>I’ve tried to attend the talks that were most aligned with my day to day job as a front-end web developer. And to sum it up, the most exciting feature for me is…<a href="https://firebase.google.com/docs/firestore/">Cloud Firestore</a>! 🎉</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/firebase-dev-summit-2017/03.webp" alt="Cloud Firestore diagram of phones, tablets and laptops syncing a shared list through the cloud"/></p>
<p>A fully-managed NoSQL document database for mobile and web app development. It operates using documents and collections as a data model.</p>
<p>It allows for expressive queries. Queries scale with the size of your result set, not the size of your data set.</p>
<p>So you’ll get the same performance fetching 1 result from a set of 100, or 100,000,000</p>
<p>Firestore syncs data between devices, enables offline data access through an on-device database and they provide SDK’s for Node, Python, Go, and Java.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/firebase-dev-summit-2017/04.webp" alt="Firebase Dev Summit 2017 attendee badge next to a cup of coffee"/></p>
<p>I had an amazing day!</p>
<p>Did meet some new people, a couple I already knew, and some I used to work with in the past.</p>
<blockquote>
<p>The food was delicious, the venue was perfect and it had all the features I think a conference needs to be able to offer their attendees.</p>
</blockquote>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/firebase-dev-summit-2017/05.webp" alt="Collage of the keynote stage at Firebase Dev Summit 2017 and slides about building and growing apps"/></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/firebase-dev-summit-2017/06.webp" alt="Collage of speakers on stage, a code slide and the audience at Firebase Dev Summit"/></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/firebase-dev-summit-2017/07.webp" alt="Collage of a talk building an app with Cloud Storage, Authentication and Cloud Firestore, including live coding"/></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/firebase-dev-summit-2017/08.webp" alt="Collage of a fastlane talk asking “How would you like 2 extra hours every week?” next to a list of release-day excuses"/></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/firebase-dev-summit-2017/09.webp" alt="Collage of a serverless talk showing an app with client SDKs talking directly to Cloud Firestore"/></p>]]></content:encoded>
    </item>
    <item>
      <title>🦑 Simplify testing your local environment on physical devices by using Squid</title>
      <link>https://www.0x1ad2.dev/blog/test-local-environments-on-physical-devices-with-squid</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/test-local-environments-on-physical-devices-with-squid</guid>
      <pubDate>Wed, 20 Sep 2017 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>Route a phone's traffic through SquidMan on your Mac so cookies, headers and hosts-file entries keep working when you test on real devices.</description>
      <category>testing</category>
      <category>mobile</category>
      <category>devtools</category>
      <content:encoded><![CDATA[<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/test-local-environments-on-physical-devices-with-squid/01.webp" alt="Banner with a pink octopus: Simplify testing your local environment on physical devices by using Squid"/></p>
<p>Big companies use a lot of <a href="https://en.wikipedia.org/wiki/HTTP_cookie">HTTP cookie</a>s 🍪 to store all the information you need to interact with the application in a proper way. Besides using cookies there are other things to take care of like setting HTTP request headers or tweak your application to fix HTTP access control issues.</p>
<p>If you are working on your local machine and have setup all these things everything works well but when you need to test it outside of this machine i.e. on a physical Android or iOS device it’s a hard to get it all working.</p>
<p>Here’s where squid comes in</p>
<p><a href="http://www.squid-cache.org/Intro/">squid : Optimising Web Delivery</a></p>
<p>Basically, squid allows you to forward all your device requests through your machine so everything you’ve set stays set.</p>
<blockquote>
<p>Squid is a fully-featured HTTP/1.0 proxy which is almost (but not quite — we’re getting there!) a fully-featured HTTP/1.1 proxy. Squid offers a rich access control, authorization and logging environment to develop web proxy and content serving applications.</p>
</blockquote>
<h2>How to install it?</h2>
<p>I would recommend using SquidMan for configuring and running, SquidMan is a graphical installer and manager for the Squid proxy cache.</p>
<p>You can install SquidMan trough a brew <a href="https://github.com/Homebrew/homebrew-cask/blob/main/Casks/s/squidman.rb">cask</a></p>
<pre><code class="language-sh">$ brew cask install squidman
</code></pre>
<h2>Configure squid to use your OS host file</h2>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/test-local-environments-on-physical-devices-with-squid/02.webp" alt="SquidMan 3.8 window showing “Squid is not running” and a Start Squid button"/></p>
<p>When you launch SquidMan you would see the following window, go to <strong>SquidMan</strong> &gt; <strong>Preferences</strong> to configure it.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/test-local-environments-on-physical-devices-with-squid/03.webp" alt="SquidMan General preferences with the HTTP port set to 7777"/></p>
<p>Once there go to <strong>General</strong> and change the port a less used one i.e. <strong>7777</strong>.<br/>
After that go to template and add the following, if not already set.</p>
<pre><code class="language-sh">#host file
hosts_file /etc/hosts
</code></pre>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/test-local-environments-on-physical-devices-with-squid/04.webp" alt="SquidMan Template preferences with hosts_file /etc/hosts added at the end of the Squid configuration"/></p>
<p>This means that SquidMan would use your local machine it’s <strong>hosts(file)</strong> to route the traffic trough.</p>
<p>Now press the <strong>save</strong> button and <strong>start</strong> SquidMan to use it.</p>
<h2>Configure squid on your iPhone to forward traffic</h2>
<p>Unlock your phone, go to Wifi networks (make sure you are on the same network as your machine) and press the <strong>( i )</strong> icon next to the network. This will open up network settings.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/test-local-environments-on-physical-devices-with-squid/05.webp" alt="iPhone Wi-Fi network details with the HTTP proxy currently set to Off"/></p>
<p>Click on configure proxy <strong>Manual</strong> and configure based upon your SquidMan settings.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/test-local-environments-on-physical-devices-with-squid/06.webp" alt="iPhone Configure Proxy screen set to Manual with server 10.0.30.189 and port 7777"/></p>
<h2>Configure squid on your Android phone to forward traffic</h2>
<p>Unlock your phone, go to <strong>Connections</strong> (make sure you are on the same network as your machine) and long-press the SSID (network name).</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/test-local-environments-on-physical-devices-with-squid/07.webp" alt="Android Connections settings with Wi-Fi turned on"/></p>
<p>This will open up a pop-up, click on <strong>Manage network settings</strong>.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/test-local-environments-on-physical-devices-with-squid/08.webp" alt="Android Wi-Fi list with a long-press menu offering Forget network, Manage network settings and Write to NFC tag"/></p>
<p>Another screen pops-up.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/test-local-environments-on-physical-devices-with-squid/09.webp" alt="Android network dialog with advanced options shown, proxy set to Manual, host 10.0.30.189 and port 7777"/></p>
<p>Click on <strong>show advanced options</strong>, proxy <strong>Manual</strong> and configure based upon your SquidMan settings.</p>
<p>Press save and you’re done you can now visit your <a href="http://local-development-url.host">http://local-development-url.host</a> on your mobile device through a proxy on your local machine. 🙌🏼 🚀</p>]]></content:encoded>
    </item>
    <item>
      <title>💎 Visual Studio Code treasures</title>
      <link>https://www.0x1ad2.dev/blog/visual-studio-code-treasures</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/visual-studio-code-treasures</guid>
      <pubDate>Mon, 17 Jul 2017 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>A list of Visual Studio Code extensions I can't live without, from Prettier and Quokka to GitLens and Import Cost.</description>
      <category>vscode</category>
      <category>devtools</category>
      <content:encoded><![CDATA[<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/01.webp" alt="Visual Studio Code Treasures title card with a treasure chest full of gems"/></p>
<p>It has almost been a year since I published my story about <a href="https://www.freecodecamp.org/news/atom-treasures-82a64ac391c">Atom the hackable text editor</a> from our friends at <a href="https://medium.com/u/8df3bf3c40ae">GitHub</a> here’s my take on VS Code 👇🏼</p>
<blockquote>
<p><a href="https://x.com/Microsoft">@Microsoft</a> did an exceptional job by creating a super performant and flexible editor. There’s a big community behind it and it’s constantly improving. Besides flexibility and performance, it also offers IntelliSense, interactive debugging and build-in GIT commands.</p>
</blockquote>
<p>If you haven’t switched yet, give it a try and let me know what you think about it.</p>
<p><a href="https://code.visualstudio.com/">Visual Studio Code</a></p>
<h2>How to install extensions?</h2>
<p>Installing extensions in Visual Studio Code is a breeze! Launch Visual Studio Code Quick Open with Ctrl+P (⌘P) and paste the extension installation command in there: <code>ext install prettier-vscode</code></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/02.webp" alt="Another thing you can do is open the extensions marketplace by clicking on the extension icon in Visual Studio Code"/>
<em>Another thing you can do is open the extensions marketplace by clicking on the extension icon in Visual Studio Code</em></p>
<h2>The list</h2>
<h3>Prettier</h3>
<p>This extension enables you to use Prettier in your projects.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">Prettier - Code formatter - Visual Studio Marketplace</a></p>
<p>Prettier is an opinionated code formatter with support for: JavaScript, (including ES2017) JSX, Flow, TypeScript, CSS, LESS, SCSS, JSON and GraphQL</p>
<p>You can learn more about prettier by watching this React Conf video.</p>
<p><a href="https://www.youtube.com/watch?v=hkfBvpEfWdA"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/03.webp" alt="Video thumbnail: ⚡️ - James Long - A Prettier Printer (plus bonus clip!) - React Conf 2017"/></a>
<em>▶ Watch “⚡️ - James Long - A Prettier Printer (plus bonus clip!) - React Conf 2017” on YouTube</em></p>
<h3>Quokka</h3>
<p>This extension enables you to use Quokka.js in your projects.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=WallabyJs.quokka-vscode">Quokka.js - Visual Studio Marketplace</a></p>
<p><a href="https://quokkajs.com">Quokka.js</a> is a rapid prototyping playground for JavaScript and TypeScript. It runs your code immediately as you type and displays various execution results in your code editor.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/04.gif" alt="Quokka.js showing the value of a JavaScript object inline as it is typed"/></p>
<p>Use command Start on current file from the quokka.js command list or press Ctrl+K(⌘K)</p>
<h3>Import Cost</h3>
<p>This extension enables you to display import/require package size inside the file you are working in.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost">Import Cost - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/05.webp" alt="Import Cost showing the size of each imported package next to its import line"/></p>
<h3>ESLint</h3>
<p>This extension enables you to use ESLint. ESLint is an open source JavaScript linting utility originally created by Nicholas C. Zakas in June 2013. Code <a href="https://en.wikipedia.org/wiki/Lint_(software)">linting</a> is a type of static analysis that is frequently used to find problematic patterns or code that doesn’t adhere to certain style guidelines. There are code linters for most programming languages, and compilers sometimes incorporate linting into the compilation process.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint">ESLint - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/06.webp" alt="ESLint problems panel in VS Code listing lint errors for the open files"/></p>
<h3>Markdown all in one</h3>
<p>This extension enables you to have keyboard shortcuts (toggle bold, italic, code span and heading), a table of contents generator, automatically show preview, list editing and much more.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one">Markdown All in One - Visual Studio Marketplace</a></p>
<blockquote>
<p>Because we all ❤ Markdown, don’t we?</p>
</blockquote>
<h3>Project manager</h3>
<p>This extension allows you to manage multiple projects inside visual studio code, the projects are listed in a projects.json that gives you full control over names and paths</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=alefragnani.project-manager">Project Manager - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/07.webp" alt="Command palette filtered to Project Manager commands to edit, list, refresh and save projects"/></p>
<h3>Regex previewer</h3>
<p>This extension enables you to validate your regular expressions in real-time.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=chrmarti.regex">Regex Previewer - Visual Studio Marketplace</a></p>
<p>Shows the current regular expression matches in a side-by-side document. This can be turned on/off with Ctrl+Alt+M (⌥⌘M).</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/08.gif" alt="Regex Previewer highlighting matches of an email regular expression in a side-by-side sample file"/></p>
<h3>Settings sync</h3>
<p>This extension enables you to synchronize: settings, snippets, themes, file icons, key bindings, workspaces and extensions across multiple machines using <a href="https://gist.github.com/">GitHub gist</a>.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync">Settings Sync - Visual Studio Marketplace</a></p>
<p>It basically does the same as <a href="https://atom.io/packages/sync-settings">sync-settings</a> did in Atom</p>
<h3>Auto close tag</h3>
<p>This extension allows you to automatically add HTML/XML close tag, same as Visual Studio IDE or Sublime Text does.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag">Auto Close Tag - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/09.webp" alt="Auto Close Tag adding the closing HTML tag while typing in test.html"/></p>
<h3>Path intellisense</h3>
<p>This extension enables auto completion of file paths in your HTML tags.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense">Path Intellisense - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/10.gif" alt="Path Intellisense suggesting file paths while editing an HTML file in a small project"/></p>
<h3>Auto rename tag</h3>
<p>This extension allows you to automatically rename paired HTML/XML tag.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag">Auto Rename Tag - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/11.gif" alt="Auto Rename Tag renaming the matching closing tag as an opening HTML tag is edited"/></p>
<h3>Change case</h3>
<p>This extension enables you to quickly change the case of the current selection or current word, you can change the cases to camelCase, CONSTANT_CASE, snake_case, kebab-case, etc.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=wmaurer.change-case">change-case - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/12.webp" alt="Change Case converting selected identifiers in a TypeScript file between casings"/></p>
<h3>Stylelint</h3>
<p>This extension enables you to use Stylelint in your project, Styelint is a modern CSS linter and fixer that helps you avoid errors and enforce consistent conventions in your stylesheets.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint">stylelint - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/13.webp" alt="Stylelint warnings for a CSS rule with a universal selector, an unspaced calc operator and trailing zeros"/></p>
<blockquote>
<p>Don’t forget to add a .stylelintrc config file to your project root. <a href="https://stylelint.io/user-guide/configure/">https://stylelint.io/user-guide/configure/</a></p>
</blockquote>
<h3>Git Lens</h3>
<p>This extension <strong>supercharges</strong> the built-in Visual Studio Code Git capabilities. It helps you to <strong>visualize code authorship</strong> at a glance via Git blame annotations and code lens, <strong>seamlessly navigate and explore</strong> the history of a file or branch, <strong>gain valuable insights</strong> via powerful comparison commands, and so much more.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">GitLens - Git supercharged - Visual Studio Marketplace</a></p>
<h3>TODO Highlight</h3>
<p>This extension allows you to highlight TODOs, FIXMEs, and any keywords, annotations.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight">TODO Highlight - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/14.webp" alt="TODO Highlight colouring TODO and FIXME comments in a JavaScript file"/></p>
<h3>SVG Viewer</h3>
<p>This extension enables you to view SVG’s on the fly, just right click the file and view.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=cssho.vscode-svgviewer">SVG Viewer - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/15.gif" alt="SVG Viewer previewing an SVG file opened from the VS Code explorer"/></p>
<h2>Extra</h2>
<h3>Color Info</h3>
<p>This extension enables you to view color information specifics on a color entry in CSS.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=bierner.color-info">Color Info - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/16.webp" alt="Color Info hover showing a colour swatch with its RGB, HSL, CMYK, hex and alpha values"/></p>
<h3>VScode icons</h3>
<p>This extension enables you to have specific file icons for almost every extension. By default Visual Studio Code now uses seti as icon pack, this is why I didn’t list VScode icons in the main list.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=vscode-icons-team.vscode-icons">vscode-icons - Visual Studio Marketplace</a></p>
<p>You can see it in action here</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/17.gif" alt="vscode-icons giving each file type its own icon in the VS Code explorer"/></p>
<h3>VS Code Spotify</h3>
<p>This extensions allows you to use Spotify inside Visual Studio Code.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=shyykoserhiy.vscode-spotify">vscode-spotify - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/18.webp" alt="VS Code status bar with vscode-spotify playback controls and the current track"/></p>
<h3>Calculate</h3>
<p>This extension allows you to do evaluate your math.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=acarreiro.calculate">Calculate - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/19.gif" alt="Calculate evaluating sums like 1+1 and 5^5 in an untitled file"/></p>
<h3>Insert Numbers</h3>
<p>This extension allows you to insert incrementing/decrementing numbers with a custom starting point.</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=Asuka.insertnumbers">Insert Numbers - Visual Studio Marketplace</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/visual-studio-code-treasures/20.webp" alt="Insert Numbers adding incrementing numbers at several cursors in a C struct"/></p>
<h2>Did I miss something powerful? ⚡</h2>
<p>If there’s a good extension available that’s not listed, please let me know in the comments. I tried to create a list of extensions that fit well into the generic workflow of a web developer. I might do a write up on specifics if requested, there are pretty powerful extensions out there if you are an Angular or React developer.</p>]]></content:encoded>
    </item>
    <item>
      <title>🔦 How to create a PWA with a 90+ score in Google Lighthouse using Ionic 2</title>
      <link>https://www.0x1ad2.dev/blog/pwa-with-a-90-lighthouse-score-using-ionic-2</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/pwa-with-a-90-lighthouse-score-using-ionic-2</guid>
      <pubDate>Wed, 22 Mar 2017 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>How I built an Ionic 2 Progressive Web App that scores 99 in Google Lighthouse, from enabling the service worker to Firebase Hosting.</description>
      <category>pwa</category>
      <category>ionic</category>
      <category>performance</category>
      <category>firebase</category>
      <content:encoded><![CDATA[<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/01.webp" alt="Lighthouse on a rocky coastline under a blue sky"/></p>
<p>I just created a <a href="https://web.dev/explore/progressive-web-apps">Progressive Web App</a> that scores 99 out of 100 in the <a href="https://developer.chrome.com/docs/lighthouse/overview/">Lighthouse</a> auditing report. I used <a href="https://ionicframework.com/">Ionic 2</a> (<a href="https://angular.dev/">Angular</a>) to get the results I wanted, here’s how I did it:</p>
<h2>Install Ionic globally</h2>
<p>To use the Ionic CLI we fist need to install Ionic globally.</p>
<pre><code class="language-sh">$ sudo npm install -g ionic cordova
</code></pre>
<h2>Create a new blank Ionic 2 project</h2>
<p>After that we can make a new Ionic 2 project by executing the following command using the Ionic CLI.</p>
<pre><code class="language-sh">$ ionic start MyPWA blank — v2
</code></pre>
<h2>Serve the application</h2>
<p>Execute the ionic serve command to serve the application in your browser. Serving the application in the browser automatically creates a web based build of your Ionic project.</p>
<pre><code class="language-sh">$ ionic serve
</code></pre>
<h2>Install Lighthouse for Google Chrome</h2>
<p><a href="https://chromewebstore.google.com/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk">Click here</a> and install Lighthouse. After installation and icon will appear.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/02.webp" alt="Google Lighthouse logo: a striped lighthouse under a starry night sky"/></p>
<h2>Run Lighthouse to generate a report</h2>
<p>If you click on the Lighthouse icon it will do some tests and generate a report.</p>
<blockquote>
<p>You need to close Chrome Developer tools to be able to run the test.</p>
</blockquote>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/03.webp" alt="First Lighthouse report scoring the Ionic app 60 out of 100, failing offline support, load performance and progressive enhancement"/></p>
<h2>Optimize 📈</h2>
<h3>1. App can load on offline/flaky connections</h3>
<p>Ensuring your web app can respond when the network connection is unavailable or flaky is critical to providing your users a good experience. This is achieved through the use of a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Worker</a>.</p>
<p>You can enable the Service Worker in Ionic by un-commenting the Service Worker part in the <strong>index.html</strong></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/04.webp" alt="Commented-out service worker registration script in Ionic&#x27;s index.html"/></p>
<p>After enabling you automatically resolve the Service Worker fail under <strong>User can be prompted to Add to Homescreen</strong></p>
<h3>2. Site is progressively enhanced</h3>
<p>Progressive enhancement means that everyone can access the basic content and functionality of a page in any browser, and those without certain browser features may receive a reduced but still functional experience.</p>
<p>We’re going to add some code to our <strong>index.html</strong> file to let the user know that they need to enable JavaScript to get the full experience. Ionic wouldn’t be able to provide a functional experience without using JavaScript.</p>
<pre><code class="language-html">&lt;noscript&gt;
  &lt;h1&gt;You don’t have javascript enabled.&lt;/h1&gt;
  &lt;p&gt;Please enable it to get the full experience.&lt;/p&gt;
&lt;/noscript&gt;
</code></pre>
<h3>4. Page load performance is fast</h3>
<p>Users notice if sites and apps don’t perform well and that will give them a bad experience. To pass this point in the report let’s make a production build using Ionic CLI’s build command and the — prod flag.</p>
<pre><code class="language-sh">$ ionic build — prod
</code></pre>
<h2>Create a secure hosting environment using Firebase 🔥</h2>
<p>Head to <a href="https://firebase.google.com">Firebase</a> and create an account. Once your account has been created go to the <a href="https://console.firebase.google.com/">Firebase console</a> to create a new project.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/05.webp" alt="Firebase console Create a project dialog with the project name MyPWA and region Netherlands"/></p>
<p>That’s it you’ve created your first Firebase project 🎉</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/06.webp" alt="Firebase console overview of the new MyPWA project with options to add Firebase to iOS, Android and web apps"/></p>
<p>As you’ve might have noticed Firebase includes a lot of features from analytics, to cloud messaging to hosting. We are going to use the last one to host our PWA in a secure environment.</p>
<h2>Deploy 📦</h2>
<p>We can deploy to Firebase by using the Firebase CLI login, init &amp; deploy commands. First, you need to login into your Firebase account (a web browser will pop-up).</p>
<pre><code class="language-sh">$ firebase login
</code></pre>
<p>After that traverse to the right directory and execute Firebase init, select hosting and select the project we’ve created above.</p>
<pre><code class="language-sh">$ firebase init
</code></pre>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/07.webp" alt="Terminal running firebase init and asking which Firebase features to set up"/></p>
<p>Set the <strong>www</strong> folder as default</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/08.webp" alt="firebase init Hosting setup asking for the public directory, answered with www"/></p>
<p>After initializing the project we can simply deploy the application to Firebase by executing.</p>
<pre><code class="language-sh">$ firebase deploy
</code></pre>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/09.webp" alt="Terminal output of firebase deploy uploading 33 files from www and printing the hosting URL"/></p>
<p>That’s it we’ve deployed our package 👍🏻</p>
<h2>Run Lighthouse (again) to generate a report</h2>
<p>Click on the lighthouse icon when in your Firebase environment, again it will do some tests and generate a report. This time, and most of the times it will generate a 90+ score.</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/10.webp" alt="Lighthouse report scoring the deployed PWA 99 out of 100 with every progressive web app audit passing"/></p>
<h2>100 out of 100?</h2>
<p>If you want to get a perfect score you should need to optimize more. Due to the way Ionic was build the <a href="https://developer.chrome.com/docs/lighthouse/performance/first-meaningful-paint">first meaningful paint</a>, <a href="https://developer.chrome.com/docs/lighthouse/performance/speed-index">perceptual speed index</a>, <a href="https://developer.chrome.com/docs/lighthouse/performance/interactive">time to interactive</a> are higher than recommended. In my opinion, this wouldn’t be an issue but there’s always room for improvement.</p>
<p>We can measure our application by applying the <a href="https://web.dev/articles/rail">RAIL method</a>. RAIL is a user-centric performance model. Every web app has these four distinct aspects to its life cycle, and performance fits into them in different ways:</p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/11.webp" alt="The RAIL performance model: Response, Animation, Idle and Load"/></p>
<p>There a couple of ways to improve the performance, the two main parts would be <a href="https://web.dev/articles/performance-optimizing-content-efficiency">Optimizing Content Efficiency</a> &amp; adjusting the <a href="https://web.dev/articles/critical-rendering-path">Critical Rendering Path</a></p>
<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/pwa-with-a-90-lighthouse-score-using-ionic-2/12.webp" alt="Diagram comparing optimized progressive rendering, which shows content from 0.3 seconds, with unoptimized rendering that stays blank until 1.5 seconds"/></p>]]></content:encoded>
    </item>
    <item>
      <title>Fingerprint end-to-end encryption</title>
      <link>https://www.0x1ad2.dev/blog/fingerprint-end-to-end-encryption</link>
      <guid isPermaLink="true">https://www.0x1ad2.dev/blog/fingerprint-end-to-end-encryption</guid>
      <pubDate>Fri, 19 Aug 2016 00:00:00 GMT</pubDate>
      <dc:creator>Dennis Bruijn</dc:creator>
      <description>Improved endpoint security using FE2EE: an idea for requiring a fingerprint scan before you can read end-to-end encrypted messages.</description>
      <category>security</category>
      <category>encryption</category>
      <content:encoded><![CDATA[<p><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/fingerprint-end-to-end-encryption/01.webp" alt="Green title card with a fingerprint: Fingerprint end-to-end encryption, improved endpoint security using FE2EE"/></p>
<h2>🔑 What is E2EE?</h2>
<p>According to Wikipedia End-to-end encryption (E2EE) is a system of communication where only the communicating users can read the messages. In principle, it prevents potential eavesdroppers — including telecom providers, Internet providers, and even the provider of the communication service — from being able to access the cryptographic keys needed to decrypt the conversation.</p>
<p><a href="https://www.wired.com/2016/05/allo-duo-google-finally-encrypts-conversations-end-end/"><img loading="lazy" decoding="async" src="https://www.0x1ad2.dev/images/blog/fingerprint-end-to-end-encryption/02.webp" alt="https://www.wired.com/2016/05/allo-duo-google-finally-encrypts-conversations-end-end/"/></a>
<em><a href="https://www.wired.com/2016/05/allo-duo-google-finally-encrypts-conversations-end-end/">https://www.wired.com/2016/05/allo-duo-google-finally-encrypts-conversations-end-end/</a></em></p>
<h2>💡 What is FE2EE?</h2>
<p>FE2EE stands for <strong>Fingerprint end-to-end encryption</strong> It’s just a made up term based on my idea on how we could improve end-to-end encryption or at least the authentication around end-to-end encryption.</p>
<p><strong>In a nutshell:</strong> applications should allow users to switch on FE2EE. After that, a fingerprint scan is required to authenticate that the receiver is the owner of the device and thus is authorized to read the contents of that message.</p>
<h2>🛠 A good way to implement FE2EE?</h2>
<p>Existing applications should be able to keep their current E2EE techniques/features the fingerprint only adds a level of authentication. And must be enabled throughout the settings panel of the application (so you can opt-in if you want).</p>
<p>After the authenticity of the user is validated. The user should have the possibility to edit the level of (re)authentication. I can imagine a user would just want to receive an authentication request on app start or maybe before each message.</p>
<p><em><strong>Note:</strong></em> <em>This is just an idea on how to implement it if you think there’s a better/safer/easier way, please share it.</em></p>
<h2>📱 How could FE2EE be used on my phone?</h2>
<p>Some iOS and Android devices can do fingerprint scans (a biometric scanner module on your device is required). It allows the devices to perform the most secure security check to date.</p>
<p><em><strong>Note:</strong></em> <em>Although fingerprint scanning has already be hacked a couple of times by the</em> <a href="https://www.ccc.de/en/updates/2014/ursel"><em>Chaos Computer Club</em></a> <em>it’s still much safer than a passcode or pattern.</em></p>
<h2>✏️ Share you toughts</h2>
<p>Please share your toughs below, tweet me or send me an email. Also if you have some constructive feedback on my writings please, reach out to me.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
