<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Aymeric Beaumet | Posts, Talks & Projects]]></title><description><![CDATA[Aymeric is a Senior Software Engineer with 7 years of experience in deploying resilient, scalable, and highly available back-end systems.]]></description><link>https://aymericbeaumet.com</link><generator>GatsbyJS</generator><lastBuildDate>Sat, 03 Jan 2026 21:49:35 GMT</lastBuildDate><item><title><![CDATA[Developers, please nurture your coding experience]]></title><description><![CDATA[I see writing code as an art. An art we would each approach from a different
perspective, playing with the tools we are being offered. We…]]></description><link>https://aymericbeaumet.com/developers-please-nurture-your-coding-experience</link><guid isPermaLink="false">https://aymericbeaumet.com/developers-please-nurture-your-coding-experience</guid><pubDate>Fri, 19 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I see writing code as an art. An art we would each approach from a different
perspective, playing with the tools we are being offered. We all evolve at a
different level of the stack. And yet, we all conceptually work very similarly:
editing some code in a form or another to make the machines behave as we expect.&lt;/p&gt;
&lt;p&gt;What is the only interface between you and the code you write? Your machine.
Your workstation. Your work environment. Your workflow. There are different ways
to name it, but ultimately that’s what enabling you to write code.&lt;/p&gt;
&lt;p&gt;I believe taking complete ownership of one’s environment is a key attribute of
becoming a better engineer. Some people would argue it brings a productivity
boost. While that might be true, I think the main reason to get to know your
environment is to move potential obstacles out of the way. To let your thoughts
flow efficiently from your brain to code. The productivity boost is a
&lt;em&gt;consequence&lt;/em&gt;, not a mean in itself.&lt;/p&gt;
&lt;p&gt;We should all get to know our environments. Caring about it is not only
beneficial for you. It is also beneficial for your coworkers and any person you
work with. Not only that, but it will give you a better intuition of what
represents a good or bad environment, and that always comes handy.&lt;/p&gt;
&lt;p&gt;The good news is: your journey has already begun. You already have a work
environment. You already took inspiration from your peers. You are already using
tools developed by people that happen to be improving their environment in a way
that suits your needs. So where should you go next?&lt;/p&gt;
&lt;h2 id=&quot;pursue-your-journey&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#pursue-your-journey&quot; aria-label=&quot;pursue your journey permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Pursue your journey&lt;/h2&gt;
&lt;p&gt;I usually start by introspecting my workflow to identify pain points. It is
often harder said than done, especially because our brain is excellent at
&lt;em&gt;accepting&lt;/em&gt; a current situation as long as we’ve been exposed to it long enough.
And that’s still the case even if there are significant improvements waiting for
us down the road.&lt;/p&gt;
&lt;p&gt;Introspection could happen in the form of self-assessing questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;what are my most frequent tasks?&lt;/li&gt;
&lt;li&gt;where am I wasting my time?&lt;/li&gt;
&lt;li&gt;what are the most tedious tasks I have to do on a regular basis?&lt;/li&gt;
&lt;li&gt;which inconsistencies can I find in my workflow?&lt;/li&gt;
&lt;li&gt;what is slowing me down?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these questions will help you find potential directions for improvements.&lt;/p&gt;
&lt;p&gt;While working on this article, I was wondering about what would be the
fundamental concepts if I were to distillate my mindset into key points. I found
5 of them:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep your stack simple.&lt;/strong&gt; When you can,
&lt;a href=&quot;https://www.youtube.com/watch?v=SxdOUGdseq4&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;choose simplicity over complexity&lt;/a&gt;.
Find the smallest set of tools required to do the job and consolidate your
workflow around them. Remove the tools you don’t need.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don’t let your stack get obsolete.&lt;/strong&gt; Challenge your existing stack on a
regular basis. Make sure you keep your tools up-to-date. Do not miss out on
the latest opportunities brought by modern tooling.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Integrate your tools together.&lt;/strong&gt; Having a small set of tools that you
master and make them talk to each other is immensely useful. The
&lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_philosophy&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Unix philosophy&lt;/a&gt; applies
here. By design, it is easier to follow this principle when working in a
terminal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Practice is essential.&lt;/strong&gt; Getting to know your tooling is all down to
practice. Learn the shortcuts. Learn how they behave. You need to deeply
understand these tools, so they become an extension of yourself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stability is key.&lt;/strong&gt; This is a never ending journey, and you should always
keep digging for ways to improve. But also know when to pause. Your habits
and muscular memory will be impacted if you change your stack too often.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Applying these concepts has been my rock over all these years. Sticking to this
will slowly but steadily bring you to a better place.&lt;/p&gt;
&lt;h2 id=&quot;concrete-examples&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#concrete-examples&quot; aria-label=&quot;concrete examples permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Concrete examples&lt;/h2&gt;
&lt;p&gt;I’ve started to code back in 2005. I was using Windows XP, Firefox, and
&lt;a href=&quot;https://notepad-plus-plus.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Notepad++&lt;/a&gt; at the time. At that time the
concept of productivity didn’t even cross my mind. Over the years, I’ve gathered
experiences in various environments (mainly Linux and macOS). I want to talk
about a few situations which I’ve identified as problematic and improved in my
workflow.&lt;/p&gt;
&lt;p&gt;The first one I want to mention is about my keyboard. &lt;em&gt;What is slowing me down?&lt;/em&gt;
Well, I found myself doing a lot of typos when typing. I had to stop my flow,
correct the error, and start typing again. So I looked it up and tried to find
solutions. The first thing that comes up on the topic is to learn how to touch
type (I couldn’t recommend &lt;a href=&quot;https://www.keybr.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;keybr.com&lt;/a&gt; enough). But then
my brain was tickled: if I’m ready to spend time to improve my typing skills, is
there more I could do? It turns out I could, and long story short, I ultimately
settled on learning to touch type with the &lt;a href=&quot;https://colemak.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Colemak&lt;/a&gt;
layout. It’s been so since 2015, and I couldn’t be happier.&lt;/p&gt;
&lt;p&gt;The second one is about the feedback loop when working on Go and Rust projects.
&lt;em&gt;Where am I wasting my time?&lt;/em&gt; I was used to working with the Node.js ecosystem
(&lt;a href=&quot;https://jestjs.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;jest&lt;/a&gt;, &lt;a href=&quot;https://github.com/remy/nodemon&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;nodemon&lt;/a&gt;,
&lt;a href=&quot;https://webpack.js.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;webpack&lt;/a&gt;, etc) that natively integrates many ways to
optimize the feedback loop (watching, reloading, hot-reloading, etc). I was
manually restarting my programs and tests when working on Go and Rust projects,
so I tried to find a way to replicate this. I have currently settled on using
&lt;a href=&quot;https://github.com/watchexec/watchexec&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;watchexec&lt;/a&gt; that is a general purpose
watcher. And I’ve
&lt;a href=&quot;https://github.com/aymericbeaumet/dotfiles/blob/0d8dc7488ceae7262934ba17a5bf31b77a7264ff/.zshrc#L81&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;aliased it to &lt;code class=&quot;language-text&quot;&gt;w&lt;/code&gt;&lt;/a&gt;
to make it convenient to use.&lt;/p&gt;
&lt;p&gt;The third one is my shell. &lt;em&gt;What are my most frequent tasks?&lt;/em&gt; Well that is a
software I’m using all day long, so I have high performance expectation. I want
it to be &lt;em&gt;blazingly&lt;/em&gt; fast, and it was not the case. Startup time as well as
printing the prompt was slow. A basic shell is actually fast by default. Just
try for yourself: start zsh
&lt;a href=&quot;https://unix.stackexchange.com/a/585012/38682&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;without loading the configuration files&lt;/a&gt;
to see how fast it is. I didn’t want to compromise on a rich prompt, but on the
other hand, my shell was slow. So what to do? I began with an empty
configuration file and only added the bits I needed. My
&lt;a href=&quot;https://github.com/aymericbeaumet/dotfiles/blob/master/.zshrc&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt;&lt;/a&gt; is
200 lines of code and loading 4 plugins. I have also made the switch to
&lt;a href=&quot;https://github.com/romkatv/powerlevel10k&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;powerlevel10k&lt;/a&gt;. And I’m now satisfied
with my shell user experience.&lt;/p&gt;
&lt;p&gt;The last one is a story happening at my current job. I’m working for
&lt;a href=&quot;https://rekki.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;REKKI&lt;/a&gt; as a Lead Platform Engineer, and part of my team’s
mission is to design and improve the Developer Experience. In doing so, I’m
letting the vision shared in this blog post infuse in my every day work. &lt;em&gt;What
are the most tedious tasks I have to do on a regular basis?&lt;/em&gt; Well, setting up
the stack for all the engineers working at REKKI was getting more and more
painful. So we’ve released an &lt;a href=&quot;https://cli.rekki.team/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;internal CLI&lt;/a&gt; that does
this for us, installed by default on all the engineers machines.&lt;/p&gt;
&lt;p&gt;Each of those examples could be a blog post in itself. And I could continue over
and over on other topics: learning how to debug and instrument my code, learning
how not to use the mouse, learning how to master my editor
(&lt;a href=&quot;https://github.com/aymericbeaumet/dotfiles/blob/master/.config/nvim/init.lua&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;nvim/init.lua&lt;/a&gt;),
learning how to use snippets, learning how to take notes efficiently, learning
how to create impactful slides, etc. But it’s not the point.&lt;/p&gt;
&lt;p&gt;The point here is to show you the mindset: identify issues, find which one would
have the biggest impact if fixed, and address them.&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final words&lt;/h2&gt;
&lt;p&gt;We’ve seen why spending time on your work environment is important, along with
some practical advices to help you shape it according to your own needs. We’ve
also looked at some examples of how I applied these advices to improve my
workflow over the past few years.&lt;/p&gt;
&lt;p&gt;This is in the end a very personal experience, and is all about getting to know
yourself. Introspection is key here: what works for you might not work for
someone else, and vice versa. This is &lt;em&gt;your&lt;/em&gt; journey, and I hope this post
inspired you to revisit your work environment. I’d love to hear how you improved
your workflow.&lt;/p&gt;
&lt;p&gt;Give it time, and you will be rewarded.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Faster git clones with sparse checkouts]]></title><description><![CDATA[We at REKKI are working on a monorepo that contains all the
backend Go code for most of our services and jobs. As time goes by and the size…]]></description><link>https://aymericbeaumet.com/faster-git-clones-with-sparse-checkouts</link><guid isPermaLink="false">https://aymericbeaumet.com/faster-git-clones-with-sparse-checkouts</guid><pubDate>Sat, 23 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We at &lt;a href=&quot;https://rekki.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;REKKI&lt;/a&gt; are working on a monorepo that contains all the
backend Go code for most of our services and jobs. As time goes by and the size
of this repository grows, the time it takes for an initial clone becomes
noticeable. While this is not really a problem on the engineers’ workstations as
they operate statefully, it impacts stateless systems that have to download the
codebase regularly: like CIs, CDs, or even our in-house
&lt;a href=&quot;https://cli.rekki.team/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;CLI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Our CLI sometimes needs to pull a fresh version of a specific commit from the Go
codebase to perform beta updates when our engineers request it (e.g.: to test
new features that are not yet released in the stable version). Cloning the Go
monorepo every time they want to install a beta update is not an option, as it
takes more than a minute on a good connection.&lt;/p&gt;
&lt;h2 id=&quot;shallow-clones&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#shallow-clones&quot; aria-label=&quot;shallow clones permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Shallow clones&lt;/h2&gt;
&lt;p&gt;The first approach you often take in a situation like this is to shallow clone.
While a default clone will fetch all the commits and all the
&lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Git-Objects&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;blob objects&lt;/a&gt; for the
branch you track (by default &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt;), a shallow clone will only fetch
the blob objects for a subset of these commits, thus resulting in faster clone
times.&lt;/p&gt;
&lt;p&gt;That is very common in the world of CIs. For example, both
&lt;a href=&quot;https://github.com/actions/checkout&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GitHub Actions&lt;/a&gt; and
&lt;a href=&quot;https://docs.travis-ci.com/user/customizing-the-build/#git-clone-depth&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Travis CI&lt;/a&gt;
do it by default.&lt;/p&gt;
&lt;p&gt;One way you’d do a shallow clone is by specifying the &lt;code class=&quot;language-text&quot;&gt;--depth=&amp;lt;n&gt;&lt;/code&gt; flag to the
&lt;code class=&quot;language-text&quot;&gt;git clone&lt;/code&gt; command, hence limiting the number of commits to pull starting from
the HEAD:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# fetch the latest commit&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone --depth&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; git@github.com:rekki/go.git&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another way to shallow clone it is to specify a &lt;em&gt;start date&lt;/em&gt; instead of a number
of commits. This is possible via the &lt;code class=&quot;language-text&quot;&gt;--shallow-since=&amp;lt;date&gt;&lt;/code&gt; flag with either
an absolute or a relative date:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# fetch the last day of commits&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone --shallow-since&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;1 day&apos;&lt;/span&gt; git@github.com:rekki/go.git&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While shallow clones work well in some contexts, they fall short by downloading
all the blob objects in the working tree for the given commits. So even
specifying a depth of 1 results in non-negligible clone times for some
repositories (in the case of our Go monorepo, this still takes 30 seconds).&lt;/p&gt;
&lt;h2 id=&quot;sparse-checkouts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sparse-checkouts&quot; aria-label=&quot;sparse checkouts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sparse checkouts&lt;/h2&gt;
&lt;p&gt;Another way to reduce the amount of downloaded data is to use sparse checkouts.
Sparse checkouts solve that problem by allowing to partially checkout a working
tree. While shallow clones give you control over the &lt;em&gt;commits&lt;/em&gt; you want to
fetch, sparse checkouts will enable you to specify the &lt;em&gt;blob objects&lt;/em&gt; you wish
to fetch.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While sparse checkouts exist since git
&lt;a href=&quot;https://github.com/git/git/blob/master/Documentation/RelNotes/2.25.0.txt&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.25.0&lt;/a&gt;,
they are still considered experimental. It is unlikely that the feature will
be removed in the future, but breaking changes might happen in both its
implementation and its usage.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can either specify a list of directories (in what’s called &lt;em&gt;cone mode&lt;/em&gt;) or a
list of patterns (ala &lt;em&gt;.gitignore&lt;/em&gt;). The
&lt;a href=&quot;https://git-scm.com/docs/git-sparse-checkout&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;manual&lt;/a&gt; recommends using the cone
mode for performance reasons.&lt;/p&gt;
&lt;p&gt;Leveraging sparse checkouts allows you only to fetch the blob objects you need
for the task you want to perform. In our case, we wanted only to clone the files
required to build our CLI. This is how we did it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone --filter&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;blob:none --no-checkout git@github.com:rekki/go.git
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; go
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; sparse-checkout &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; --cone go.mod go.sum cmd/rekki-cli pkg/rekki/errors
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout master&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s explain step by step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;git clone&lt;/code&gt;: like a typical clone, but with 2 additional flags:
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;--filter=blob:none&lt;/code&gt;: instructs not to fetch any blob object&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;--no-checkout&lt;/code&gt;: instructs not to automatically checkout &lt;em&gt;HEAD&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;git sparse-checkout set&lt;/code&gt;: enables the sparse checkout settings and specifies
which files should be checked out. Change this line to whatever works for
you.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;git checkout master&lt;/code&gt;: checkouts the actual branch or commit (in this case,
the &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt; branch) and fetches the objects matching the sparse patterns.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can easily adapt these commands to your use cases.&lt;/p&gt;
&lt;p&gt;This approach allowed us to reduce the end-to-end time to clone to less than 5
seconds. We are satisfied with that number, and we know that time will only grow
proportionally to the size of the code required to build the CLI (and nothing
else). So it should stay fast for the foreseeable future.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Using sparse checkouts is a bit more involved in the commands you have to
execute, but it allows for more control over the files you download on your
local filesystem. You don’t always need the entirety of a git repository, and
sparse checkouts allow you to pick what you need granularly.&lt;/p&gt;
&lt;p&gt;Give it a try the next time you find yourself in a situation where a git clone
takes too long. What use case do you have in mind? Leave a comment with your
ideas below.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Prevent chromedp Chromium zombie processes from stacking]]></title><description><![CDATA[I have recently been playing with
chromedp. Chromedp is a Go library that
enables you to control a Chromium browser programmatically. This…]]></description><link>https://aymericbeaumet.com/prevent-chromedp-chromium-zombie-processes-from-stacking</link><guid isPermaLink="false">https://aymericbeaumet.com/prevent-chromedp-chromium-zombie-processes-from-stacking</guid><pubDate>Sat, 13 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have recently been playing with
&lt;a href=&quot;https://github.com/chromedp/chromedp&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;chromedp&lt;/a&gt;. Chromedp is a Go library that
enables you to control a Chromium browser programmatically. This can be used for
different tasks: from testing to scraping. I have some memories of implementing
a similar program in Node.js, and I was pleased to leverage a strongly typed
language for the job.&lt;/p&gt;
&lt;p&gt;I was able to quickly start experimenting by following the
&lt;a href=&quot;https://github.com/chromedp/examples&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;examples&lt;/a&gt; and browsing the
&lt;a href=&quot;https://pkg.go.dev/github.com/chromedp/chromedp&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;documentation&lt;/a&gt;. For the
record, this is what the chromedp hello world looks like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cancel &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; chromedp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NewContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cancel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; chromedp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
		ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		chromedp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Navigate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://github.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-problem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-problem&quot; aria-label=&quot;the problem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The problem&lt;/h2&gt;
&lt;p&gt;Not so long after I started getting results, I suddenly heard my MacBook Pro
fans running crazy. Similar to what’s happening when a &lt;code class=&quot;language-text&quot;&gt;brew install&lt;/code&gt; is not
going as expected, and you feel like you are recompiling gcc from scratch. This
was accompanied by a weirdly unpleasant gentle warmth on my hands and an
increasing slowness on the macOS UI.&lt;/p&gt;
&lt;p&gt;A quick look at the &lt;a href=&quot;/resources/chromium_zombies.png&quot;&gt;activity monitor&lt;/a&gt; revealed
that the Chromium processes were not terminated as expected. They were also
using a lot of RAM, and forced my computer to swap (hence the perceived
slowness).&lt;/p&gt;
&lt;p&gt;Running &lt;code class=&quot;language-text&quot;&gt;pkill Chromium&lt;/code&gt; got me out of trouble. But now remains the question:
how to prevent this from happening in the future? A quick search on Google led
me to the chromedp issue tracker, were several
&lt;a href=&quot;https://github.com/chromedp/chromedp/issues/81&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;resolved&lt;/a&gt;
&lt;a href=&quot;https://github.com/chromedp/chromedp/issues/289&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;issues&lt;/a&gt; are reporting this
very problem. They were all closed, and I didn’t have the same symptoms, so I
opened a &lt;a href=&quot;https://github.com/chromedp/chromedp/issues/752&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;new one&lt;/a&gt; to keep
track of what I was facing.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;TLDR: if you are looking for the solution, jump to the
&lt;a href=&quot;#the-solution&quot;&gt;end of this post&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-quick-fix&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-quick-fix&quot; aria-label=&quot;the quick fix permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The quick fix&lt;/h2&gt;
&lt;p&gt;This problem will at some point be fixed upstream, but in the meantime I was
looking for a temporary solution that would prevent the zombie processes from
stacking (and eating my RAM). As it happens, the Chromium processes are spawned
with the same user as the Go process. That means it should theoratically be
possible (permission wise) to kill them from within the Go process right before
it dies. I quickly tried to confirm this theory with the following code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cancel &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; chromedp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NewContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;cancel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; exec&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pkill&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Chromium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[warn] Failed to kill Chromium processes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It is not as accurate as I would like it to be. All the Chromium processes on my
machine (whose my user has rights on) would die, but this works. That being
said, I’m not using Chromium as my primary browser, so I’m not really impacted.
But then came the time to write this blog post, and I was sure at some point
someone would face this issue &lt;em&gt;and&lt;/em&gt; would also be using Chromium as its primary
browser. So I started digging.&lt;/p&gt;
&lt;h2 id=&quot;going-down-the-rabbit-hole&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#going-down-the-rabbit-hole&quot; aria-label=&quot;going down the rabbit hole permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Going down the rabbit hole&lt;/h2&gt;
&lt;p&gt;As it turns out, &lt;code class=&quot;language-text&quot;&gt;man pkill&lt;/code&gt; gives us some interesting leads to explore. &lt;code class=&quot;language-text&quot;&gt;pkill&lt;/code&gt;
(and &lt;code class=&quot;language-text&quot;&gt;pgrep&lt;/code&gt; for that matters, as they share most of their options) does support
a flag allowing to restrict the processes receiving the signal to only the
descendants of a specific PID (or said otherwise: all the processes whose parent
is PID). This is achieved by providing the &lt;code class=&quot;language-text&quot;&gt;-P &amp;lt;PID&gt;&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;Once the code is adjusted to leverage the
&lt;a href=&quot;https://golang.org/pkg/os/#Getpid&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;os.Getpid()&lt;/code&gt;&lt;/a&gt; function, only the Chromium
processes started by the Go process will be killed:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token boolean&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; exec&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pkill&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-P&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strconv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Itoa&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;os&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Getpid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Chromium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or so I thought, this doesn’t work. As it turns out, the Chrome processes are
not directly attached to the Go process as there are intermediate forks. So
trying to match the parent process will not behave as you would expect.&lt;/p&gt;
&lt;p&gt;While looking at the activity monitor, I noticed there was something else than
the process ID (PID) mentioned: the process group ID (PGID). I was not sure what
this was about. A quick look at the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Process_group&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Wikipedia page&lt;/a&gt; reads:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In a POSIX-conformant operating system, a process group denotes a collection
of one or more processes. Among other things, a process group is used to
control the distribution of a signal; when a signal is directed to a process
group, the signal is delivered to each process that is a member of the group.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It felt like this was one way to go, so I decided to dig this whole process
group concept. Reading &lt;code class=&quot;language-text&quot;&gt;man ps&lt;/code&gt; helped me craft these two commands:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ps -o pid,pgid,command&lt;/code&gt;: which lists all the processes on the system, along
with their PID, PGID, and the full command&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ps -g &amp;lt;PGID&gt;&lt;/code&gt;: which lists all the processes belonging to a specific process
group ID&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By using the first command, I found my Go process PGID (&lt;em&gt;46499&lt;/em&gt;), and by using
the second one I was able to list all of the processes in this group:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;ps&lt;/span&gt; -g &lt;span class=&quot;token number&quot;&gt;46499&lt;/span&gt;
  PID TTY           TIME CMD
&lt;span class=&quot;token number&quot;&gt;46499&lt;/span&gt; ttys001    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;:00.77 go run &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;46518&lt;/span&gt; ttys001    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;:38.43 /var/folders/dg/3zgc8tkd0wg7d0zc0mst6jc00000gn/T/go-build917574381/b001/exe/scraper
&lt;span class=&quot;token number&quot;&gt;46520&lt;/span&gt; ttys001    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;:01.72 /Applications/Chromium.app/Contents/MacOS/Chromium --disable-popup-blocking --safebr
&lt;span class=&quot;token number&quot;&gt;46521&lt;/span&gt; ttys001    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;:00.80 /Applications/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions
&lt;span class=&quot;token number&quot;&gt;46522&lt;/span&gt; ttys001    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;:08.18 /Applications/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This lists all the processes belonging to the Go process group (including
Chromium’s). We are getting close to what we want. As it turns out, &lt;code class=&quot;language-text&quot;&gt;pkill&lt;/code&gt; also
supports the &lt;code class=&quot;language-text&quot;&gt;-g&lt;/code&gt; flag (with the same semantic). So changing the code as follows
should behave as expected:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token boolean&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; exec&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pkill&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-g&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strconv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Itoa&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;os&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Getpid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Chromium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But it doesn’t. If you look carefully at the &lt;code class=&quot;language-text&quot;&gt;ps&lt;/code&gt; command above, you can see the
actual &lt;code class=&quot;language-text&quot;&gt;scraper&lt;/code&gt; process, but above it is the &lt;code class=&quot;language-text&quot;&gt;go run .&lt;/code&gt; process, which is the
process that created the group. As we can see, the process group ID is the PID
of the process that created the group. So we should be careful to use the &lt;em&gt;go
run&lt;/em&gt; PID instead. In Go, you can get the PID of the parent process with
&lt;a href=&quot;https://golang.org/pkg/os/#Getppid&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;os.Getppid()&lt;/a&gt;, which gives us:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token boolean&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; exec&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pkill&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-g&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strconv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Itoa&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;os&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Getppid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Chromium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Does it work? Yes, finally! Well, it works when we &lt;code class=&quot;language-text&quot;&gt;go run .&lt;/code&gt;, but what happens
when we &lt;code class=&quot;language-text&quot;&gt;go build&lt;/code&gt; and directly run the binary? Well, it’s not working. The
reason is that the process group is no longer the one created by &lt;em&gt;go run&lt;/em&gt;, but
the one created by the binary itself as we run it directly. So we need to
account for that when we try to guess the PGID from the code.&lt;/p&gt;
&lt;p&gt;An easy solution is to try to &lt;code class=&quot;language-text&quot;&gt;pkill&lt;/code&gt; both for the current pid &lt;em&gt;and&lt;/em&gt; the parent
pid. At least one of them will be the process group ID. So as long as they don’t
both fail, it means we have succeeded to kill all the zombie processes:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token boolean&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; errA &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; exec&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pkill&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-g&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strconv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Itoa&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;os&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Getppid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Chromium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token boolean&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; errB &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; exec&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pkill&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-g&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strconv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Itoa&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;os&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Getpid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Chromium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This works. But I don’t find this elegant as we expect half of the &lt;code class=&quot;language-text&quot;&gt;pkill&lt;/code&gt;
commands to fail during a normal execution process. Can we take it one step
further? Let’s have a look at &lt;code class=&quot;language-text&quot;&gt;man pkill&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;-g pgrp     Restrict matches to processes with a process group ID in the comma-separated list
            pgrp.  The value zero is taken to mean the process group ID of the running pgrep
            or pkill command.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Reading this teaches us we could pass a comma-separated list of PID to &lt;code class=&quot;language-text&quot;&gt;-g&lt;/code&gt;,
which enables to only call &lt;em&gt;pkill&lt;/em&gt; once by passing both the PGID and the PID at
the same time. But the second part of the description is much more interesting:
by passing &lt;code class=&quot;language-text&quot;&gt;-g 0&lt;/code&gt; we ask &lt;em&gt;pkill&lt;/em&gt; to infer for us what is the current process
group ID. That greatly simplifies the code by moving this responsibility out of
Go.&lt;/p&gt;
&lt;h3 id=&quot;the-solution&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-solution&quot; aria-label=&quot;the solution permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The solution&lt;/h3&gt;
&lt;p&gt;By applying this to our piece of code, we reach this solution:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cancel &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; chromedp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NewContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;cancel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// Prevent Chromium processes from hanging&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; exec&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pkill&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-g&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Chromium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[warn] Failed to kill Chromium processes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This does exactly what we want: it kills all the Chromium processes that have
been started by the Go process without impacting any other Chromium process that
would be running on your machine. This is simple, elegant, and works on all
POSIX systems. It also has the advantage of being transposable to any other
stack you use. Bingo!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You might be wondering: was it worth digging all the way through considering you
already had a working solution from the get-go? That’s a good point. Well, first
it was not working the way I expected it to. And second, I strongly believe our
knowledge is always (and will always be) shallow, which makes me strive to take
the time to dig deeper whenever I have the opportunity.&lt;/p&gt;
&lt;p&gt;It is enjoyable how sometimes a simple problem will challenge you on something
you thought was well outside your comfort zone.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Automatic Persisted Queries: why does it matter?]]></title><description><![CDATA[GraphQL is not to be presented anymore. One main
drawback though in comparison to REST is the upstream bandwidth cost can become
significant…]]></description><link>https://aymericbeaumet.com/automatic-persisted-queries-why-does-it-matter</link><guid isPermaLink="false">https://aymericbeaumet.com/automatic-persisted-queries-why-does-it-matter</guid><pubDate>Tue, 20 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://graphql.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GraphQL&lt;/a&gt; is not to be presented anymore. One main
drawback though in comparison to REST is the upstream bandwidth cost can become
significant as the number of queries increases.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.apollographql.com/docs/apollo-server/performance/apq/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Automatic Persisted Queries&lt;/a&gt;
aims at addressing this problem by allowing to cache the queries server-side.
They can then be queried again through a unique identifier sent by the backend.&lt;/p&gt;
&lt;p&gt;Unfortunately this talk was not recorded, but you can find the slides below.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Resilience: why, how, what?]]></title><description><![CDATA[We live in a world critically relying on a growing mass of information systems:
whether it be for APIs, automation, synchronizing services…]]></description><link>https://aymericbeaumet.com/resilience-why-how-what</link><guid isPermaLink="false">https://aymericbeaumet.com/resilience-why-how-what</guid><pubDate>Thu, 27 Sep 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We live in a world critically relying on a growing mass of information systems:
whether it be for APIs, automation, synchronizing services, or any other
server-side operation. But how do these systems react in case of failure?&lt;/p&gt;
&lt;p&gt;As a back-end engineer, it is your job to implement a resilient system. Through
this talk, we will look into some erroneous Node.js implementations and see how
we can articulate coherent strategies to solve these issues.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This talk was given in French. The slides are in English.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Behold z, the unsung jewel that rethinks shell navigation]]></title><description><![CDATA[I spend a fair amount of time wandering around in the terminal. The chances are
that you are too since you dared to open this story. My…]]></description><link>https://aymericbeaumet.com/behold-z-the-unsung-jewel-that-rethinks-shell-navigation</link><guid isPermaLink="false">https://aymericbeaumet.com/behold-z-the-unsung-jewel-that-rethinks-shell-navigation</guid><pubDate>Wed, 14 Feb 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I spend a fair amount of time wandering around in the terminal. The chances are
that you are too since you dared to open this story. My daily activities led me
to contribute to various kinds of projects (professional, personal and
open-source). For my sanity, I tend to follow strict rules to organize my
workspace, which helps me keep things tidied up and easily reachable. Or so I
thought.&lt;/p&gt;
&lt;p&gt;I decided to arrange my projects by following the
&lt;a href=&quot;https://golang.org/doc/code.html#Workspaces&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Go philosophy&lt;/a&gt;: make the
arborescence mirrors the urls where they are reachable. e.g.,
&lt;code class=&quot;language-text&quot;&gt;~/Workspace/src/github.com/aymericbeaumet/dotfiles&lt;/code&gt; would contain the project
&lt;a href=&quot;https://github.com/aymericbeaumet/dotfiles&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;dotfiles&lt;/a&gt; owned by
&lt;a href=&quot;https://github.com/aymericbeaumet&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@aymericbeaumet&lt;/a&gt; and accessible at
&lt;a href=&quot;https://github.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;github.com&lt;/a&gt;. That’s great, but I am now facing a complex
directory structure tedious to navigate quickly. Making it, in the end, harder
to access the resources I need.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;pwd&lt;/span&gt;
/Users/aymericbeaumet/Workspace/src/github.com/brigad/back-end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Nobody wants to manually deal with this.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Remembering and typing the location of each project (even while leveraging
autocomplete) is time-consuming. Creating shell aliases is not scalable.
Instead, I would like to rely on the pseudo-unicity of each project name to find
it among all the directories on my computer.&lt;/p&gt;
&lt;h2 id=&quot;z&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#z&quot; aria-label=&quot;z permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;z?&lt;/h2&gt;
&lt;p&gt;Several tools exist to tackle this problem. My favorite is
&lt;a href=&quot;https://github.com/rupa/z&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;em&gt;z&lt;/em&gt;&lt;/a&gt;. It follows the Unix philosophy by being small,
focused and interoperable. &lt;em&gt;z&lt;/em&gt; allows jumping around swiftly, automatically
learning from your habits. The entries are ranked based on the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Frecency&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;frecency&lt;/a&gt; at which you access the
directories.&lt;/p&gt;
&lt;p&gt;Let’s walk through the basics of this tool. Below is how I advise to install it
for Zsh on macOS (the install process should be similar for other shells and
operating systems):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; z
$ &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;source &apos;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;brew --prefix z&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;/etc/profile.d/z.sh&apos;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; ~/.zshenv&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Install z for Zsh on macOS.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Note how installing &lt;em&gt;z&lt;/em&gt; is not enough to start using it. You have to source
&lt;code class=&quot;language-text&quot;&gt;z.sh&lt;/code&gt; at the beginning of each shell session to activate it. The &lt;code class=&quot;language-text&quot;&gt;~/.zshenv&lt;/code&gt;
configuration file is appropriate as Zsh
&lt;a href=&quot;http://zsh.sourceforge.net/Intro/intro_3.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;loads it in most circumstances&lt;/a&gt;,
making the tool accessible in a wide-variety of contexts (terminals, editors,
IDEs, scripts, etc.).&lt;/p&gt;
&lt;h2 id=&quot;lets-play&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#lets-play&quot; aria-label=&quot;lets play permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let’s play&lt;/h2&gt;
&lt;p&gt;Once the install and setup are complete: start a new shell session, &lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt; through
some folders and execute &lt;code class=&quot;language-text&quot;&gt;z&lt;/code&gt; to confirm it has been accurately tracking your
activity:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ z &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt; -rn &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;head&lt;/span&gt; -3
&lt;span class=&quot;token number&quot;&gt;5331.72&lt;/span&gt;    /Users/aymericbeaumet/Workspace/src/github.com/brigad/back-end
&lt;span class=&quot;token number&quot;&gt;637.255&lt;/span&gt;    /Users/aymericbeaumet/Workspace/src/github.com/brigad/ops
&lt;span class=&quot;token number&quot;&gt;386.198&lt;/span&gt; /Users/aymericbeaumet/.config/dotfiles&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Top 3 directories based on frecency.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As shown above, I spend quite some time navigating through
&lt;a href=&quot;https://github.com/brigad&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Brigad&lt;/a&gt; projects, but it seems I also often access
my &lt;a href=&quot;https://github.com/aymericbeaumet/dotfiles&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;dotfiles&lt;/a&gt; to tweak some
configuration. The ranking score is volatile, and one could observe significant
changes in a brief amount of time.&lt;/p&gt;
&lt;p&gt;Now that &lt;em&gt;z&lt;/em&gt; has accumulated some knowledge try it by navigating to one of the
tracked folders. Navigating is as simple as executing the &lt;code class=&quot;language-text&quot;&gt;z&lt;/code&gt; command followed
by the directory name:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ z dotfiles
$ &lt;span class=&quot;token builtin class-name&quot;&gt;pwd&lt;/span&gt;
/Users/aymericbeaumet/.config/dotfiles&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Navigating by matching with a whole directory name.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As a matter of facts, I do prefer to leverage partial matching (imagine &lt;code class=&quot;language-text&quot;&gt;**&lt;/code&gt;
surrounding your search pattern) to type fewer characters. Hence, &lt;code class=&quot;language-text&quot;&gt;z dot&lt;/code&gt; is
valid and should produce a similar behavior as &lt;code class=&quot;language-text&quot;&gt;z dotfiles&lt;/code&gt; (modulo possible
name collisions, but you get the idea). This works because &lt;em&gt;z&lt;/em&gt; relies on regular
expressions. For example, the snippet below will navigate to the directory
ending with the letters “tmp” (with the highest score):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ z tmp$
$ &lt;span class=&quot;token builtin class-name&quot;&gt;pwd&lt;/span&gt;
/private/tmp&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Navigating by matching with a regular expression.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Neat right? I guess you start seeing the possibilities of this tool. And we have
only scratched the surface of its capabilities. I suggest you dive in its
&lt;a href=&quot;https://github.com/rupa/z/blob/master/README&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;documentation&lt;/a&gt; to get an idea of
its full potential. Features such as autocomplete, subdirectories matching,
consecutive matching, etc. are a game changer.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;z&lt;/em&gt; is tremendous. This tool saves me a non-trivial amount of time every single
day. When one starts relying on it, there is no going back. And I hope it’s
going to fit your workflow as well as mine.&lt;/p&gt;
&lt;p&gt;I would be grateful to hear any of your time-saving tricks. Feel free to share
your experiences!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Properly shim AngularJS applications using Browserify]]></title><description><![CDATA[Edit (March 5th 2015): the frontend community has evolved in the last few
months and tends to be less hostile to the CommonsJS style (e.g…]]></description><link>https://aymericbeaumet.com/properly-shim-angularjs-applications-using-browserify</link><guid isPermaLink="false">https://aymericbeaumet.com/properly-shim-angularjs-applications-using-browserify</guid><pubDate>Sun, 12 Oct 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Edit (March 5th 2015): the frontend community has evolved in the last few
months and tends to be less hostile to the CommonsJS style (e.g.: Angular is now
available on npm). This article has been rewritten accordingly.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://angularjs.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;AngularJS&lt;/a&gt; is a frontend framework developed by folks
at Google. It allows to build advanced web applications in a modular way by
splitting the code base into small components. This brings a lot of advantages
like a clean separation of concerns and an easier testability.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://browserify.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Browserify&lt;/a&gt; is a tool which allows to benefit from the
&lt;a href=&quot;http://wiki.commonjs.org/wiki/CommonJS&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;CommonJS&lt;/a&gt; modules in theoretically any
JavaScript environments. Given an entry point, it computes a dependency tree,
resolves it and produces a single output file. By consuming the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;,
Browserify enables to require &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; in the build. This allows to rely
on &lt;a href=&quot;https://www.npmjs.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;npm&lt;/a&gt; as a package manager for frontend dependencies,
where &lt;a href=&quot;https://bower.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Bower&lt;/a&gt; or &lt;a href=&quot;http://component.github.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Component&lt;/a&gt;
would have been usually used.&lt;/p&gt;
&lt;p&gt;When I first heard about Browserify, I immediately thought the modularity it
brings would be really nice to build AngularJS applications. And it actually is.
However they are not a perfect match by now, and some drawbacks need to be
fixed.&lt;/p&gt;
&lt;p&gt;This article presents a solution to structure an AngularJS application using
Browserify. It covers the use of non-CommonJS modules as dependencies.&lt;/p&gt;
&lt;h2 id=&quot;a-sample-application&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-sample-application&quot; aria-label=&quot;a sample application permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A sample application&lt;/h2&gt;
&lt;p&gt;Let’s consider a sample application which sets an entry in the local storage,
and uses it to react differently whether it’s the first time a user is loading
the page. It will be used as a support to identify the trouble cases and detail
how to tackle them. So create an empty folder and let’s get started!&lt;/p&gt;
&lt;p&gt;First, create an &lt;code class=&quot;language-text&quot;&gt;app.js&lt;/code&gt; file which will be the entry point:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; angular &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;angular&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; angular&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;app&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;angular-local-storage&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;localStorageService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;localStorageService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;lastVisit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		angular&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;body&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello stranger!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		angular&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;body&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Welcome back!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	localStorageService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;lastVisit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Neat, isn’t it? If you come from a Node.js background I’m sure you do like it.&lt;/p&gt;
&lt;p&gt;Now let’s generate the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; init
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save angular angular-local-storage jquery
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; -D browserify&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then compile the application:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;./node_modules/.bin/browserify app.js -o bundle.js&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And finally create a basic &lt;code class=&quot;language-text&quot;&gt;index.html&lt;/code&gt; to load it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;bundle.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ng-app&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pretty simple huh? But as you might expect, this doesn’t work. Open &lt;code class=&quot;language-text&quot;&gt;index.html&lt;/code&gt;
in a web browser and take a look at the console to find a nice JavaScript error.&lt;/p&gt;
&lt;h2 id=&quot;explanations&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#explanations&quot; aria-label=&quot;explanations permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Explanations&lt;/h2&gt;
&lt;p&gt;There are several issues occurring here.&lt;/p&gt;
&lt;h3 id=&quot;modules-not-defining-an-entry-point&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#modules-not-defining-an-entry-point&quot; aria-label=&quot;modules not defining an entry point permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Modules not defining an entry point&lt;/h3&gt;
&lt;p&gt;When a module is required, Browserify looks in the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; folder to find
its &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; and loads it. Browserify expects it to have a &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; property
which contains the relative path to the file which should be loaded.&lt;/p&gt;
&lt;p&gt;It is usual that this property is missing, that it points to the wrong file or
that the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; itself is missing. In such case, you can override the
file to load in the own project’s &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;browser&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./node_modules/angular/angular.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular-local-storage&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./node_modules/angular-local-storage/dist/angular-local-storage.js&quot;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;modules-not-properly-exporting-their-content&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#modules-not-properly-exporting-their-content&quot; aria-label=&quot;modules not properly exporting their content permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Modules not properly exporting their content&lt;/h3&gt;
&lt;p&gt;When Browserify requires the file indicated by the &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; property in the
module’s &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;, it is usual that this file does not properly export its
content in the CommonJS style. Also, we expect AngularJS modules to export their
names so that we could directly require them in our AngularJS modules
definitions.&lt;/p&gt;
&lt;p&gt;To this end, &lt;a href=&quot;https://github.com/thlorenz/browserify-shim&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;browserify-shim&lt;/a&gt; can
be used.&lt;/p&gt;
&lt;p&gt;First install it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; -D browserify-shim&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, update the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;browserify-shim&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token property&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;angular&quot;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular-local-storage&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token property&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;angular.module(&apos;LocalStorageModule&apos;).name&quot;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;browserify&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;transform&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;browserify-shim&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;angular&lt;/code&gt; exports the global variable &lt;code class=&quot;language-text&quot;&gt;angular&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;angular-local-storage&lt;/code&gt; exports its AngularJS module name &lt;code class=&quot;language-text&quot;&gt;LocalStorageModule&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;modules-fetching-their-dependencies-on-the-global-context&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#modules-fetching-their-dependencies-on-the-global-context&quot; aria-label=&quot;modules fetching their dependencies on the global context permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Modules fetching their dependencies on the global context&lt;/h3&gt;
&lt;p&gt;Some frontend modules relies on the fact their dependencies will be exposed on
the global object (generally the &lt;code class=&quot;language-text&quot;&gt;window&lt;/code&gt; object in most browsers). This is an
anti-pattern of the CommonJS architecture which favors separation of concerns.&lt;/p&gt;
&lt;p&gt;For example, AngularJS expects jQuery to be exposed at the &lt;code class=&quot;language-text&quot;&gt;window.jQuery&lt;/code&gt;
property.&lt;/p&gt;
&lt;p&gt;One solution is to wrap the module into a function which exposes a global object
with the appropriate properties. Hopefully, this could also easily done via
&lt;em&gt;browserify-shim&lt;/em&gt; (see above for the installation).&lt;/p&gt;
&lt;p&gt;Then, update the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;browserify-shim&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token property&quot;&gt;&quot;depends&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;jquery:jQuery&quot;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular-local-storage&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token property&quot;&gt;&quot;depends&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;angular&quot;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;angular&lt;/code&gt; will be provided the &lt;code class=&quot;language-text&quot;&gt;jquery&lt;/code&gt; module on a fake window object at the
property &lt;code class=&quot;language-text&quot;&gt;jQuery&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;angular-local-storage&lt;/code&gt; will be provided the &lt;code class=&quot;language-text&quot;&gt;angular&lt;/code&gt; module the same way&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;wrap-up&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wrap-up&quot; aria-label=&quot;wrap up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wrap up&lt;/h2&gt;
&lt;p&gt;You should have added the following content to your &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;browser&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./node_modules/angular/angular.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular-local-storage&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./node_modules/angular-local-storage/dist/angular-local-storage.js&quot;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;browserify-shim&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token property&quot;&gt;&quot;depends&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;jquery:jQuery&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;token property&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;angular&quot;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;angular-local-storage&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token property&quot;&gt;&quot;depends&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;angular&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;token property&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;angular.module(&apos;LocalStorageModule&apos;).name&quot;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;browserify&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;transform&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;browserify-shim&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once you’ve made those corrections, you should be able to compile and run the
sample application:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;./node_modules/.bin/browserify app.js -o bundle.js&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Check it really works by opening &lt;code class=&quot;language-text&quot;&gt;index.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A working example can be found &lt;a href=&quot;#attachments&quot;&gt;attached to this post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;side-notes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#side-notes&quot; aria-label=&quot;side notes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Side notes&lt;/h2&gt;
&lt;p&gt;Some related facts which can save you time when dealing with Browserify:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;modules not published to npm can be installed by giving their git repository
URL: &lt;code class=&quot;language-text&quot;&gt;npm install git+https://github.com/angular-ui/ui-router.git&lt;/code&gt;. Note that
it is also possible to directly pass a GitHub repository:
&lt;code class=&quot;language-text&quot;&gt;npm install angular-ui/ui-router&lt;/code&gt;. A version can be specified by appending
&lt;code class=&quot;language-text&quot;&gt;#tag&lt;/code&gt;. See the &lt;a href=&quot;https://docs.npmjs.com/cli/install&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;documentation&lt;/a&gt; for more
information&lt;/li&gt;
&lt;li&gt;modules not containing a &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; cannot be installed using npm (even by
directly providing a git repository). To tackle this issue, a third party
installer like &lt;a href=&quot;https://github.com/shama/napa&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;napa&lt;/a&gt; has to be used&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;napa&lt;/code&gt; will directly install the dependencies in the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;the &lt;code class=&quot;language-text&quot;&gt;postinstall&lt;/code&gt; script is equivalent to &lt;code class=&quot;language-text&quot;&gt;install&lt;/code&gt;. It is executed after the
modules installation. However, I find it to be more explicit&lt;/li&gt;
&lt;li&gt;you should place &lt;code class=&quot;language-text&quot;&gt;napa&lt;/code&gt; into the &lt;code class=&quot;language-text&quot;&gt;postinstall&lt;/code&gt; script&lt;/li&gt;
&lt;li&gt;the paths provided in the &lt;code class=&quot;language-text&quot;&gt;browser&lt;/code&gt; field needs to be relative to the root
&lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; path. It is mandatory to start each entry by &lt;code class=&quot;language-text&quot;&gt;./&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;it is possible to indicate files in another repository than &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt;
when filling the browser field (e.g.: &lt;code class=&quot;language-text&quot;&gt;bower_components&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;centralizing Browserify options in the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; is a good practice since
it allows to keep a constant behavior when invoking it in different ways (CLI,
API)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Even though there is a little more code to write to setup a project, this
solution provides a beautiful way to organize its code in logical bricks. It
totally matches the way AngularJS has been thought.&lt;/p&gt;
&lt;p&gt;Also, managing all the dependencies in a single place is really useful.
Especially when developing full-stack JavaScript applications, hence potentially
sharing dependencies between the frontend and the backend (e.g.: Async.js,
Bluebird, Moment.js, highlight.js, …). Using a CommonJS loader allows to rely on
the exact same versions of the modules both client-side and server-side.&lt;/p&gt;</content:encoded></item></channel></rss>