<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Jouni Kantola. Web developer.</title>
  <subtitle>I do web. I enjoy doing so.</subtitle>
  <link href="https://jouni.kantola.se/feed.xml" rel="self"/>
  <link href="https://jouni.kantola.se/"/>
  <updated>2021-04-02T00:00:00.000Z</updated>
  <id>https://jouni.kantola.se/</id>
  <author>
    <name>Jouni Kantola</name>
    <uri>https://jouni.kantola.se/contact/</uri>
  </author>
  
  <entry>
    <title>Power to the reader</title>
    <link href="https://jouni.kantola.se/blog/2021-04-02/power-to-the-reader/"/>
    <updated>2021-04-02T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2021-04-02/power-to-the-reader/</id>
    <content type="html">&lt;p&gt;Let me ask you a question. &lt;em&gt;How do your readers prefer to read?&lt;/em&gt; All I know
about people visiting, are based on what pages have most visits. That
information gives me clues about who are reading, but nothing about their
preferences.&lt;/p&gt;
&lt;p&gt;More and more, I&#39;ve come to read blogs with my browser&#39;s Reader View. I&#39;ve been
driven to it. Half the joy of reading is killed by trying to dismiss cookie
consent banners and recommendations to download apps. Honestly, all I want to do
is to read the text you&#39;ve put hard effort into writing.&lt;/p&gt;
&lt;h2&gt;Kindle&lt;/h2&gt;
&lt;p&gt;For over a year, I&#39;ve been pixel pushing, trying to improve readability. I&#39;ve
spent hours on end, comparing font sizes, margin widths and letter spacing. I&#39;ll
probably never be satisfied. Even if I would, it would be for my own reading
experience.&lt;/p&gt;
&lt;p&gt;I&#39;ve had a Kindle for years, and I love reading on it. The &lt;strong&gt;power to decide&lt;/strong&gt;
how to consume text has been handed over to me. I, the user, get to pick what
font, line height and text size best suits my needs. I get to control my own
user experience.&lt;/p&gt;
&lt;h2&gt;Here, you pick&lt;/h2&gt;
&lt;p&gt;I&#39;ve got a hypothesis, that if you have the option to, you&#39;d like to choose how
content you read is presented. That&#39;s why I&#39;ve given you some choices. The
formatting alternatives I&#39;ve started with are based on what I fiddle with mostly
on my Kindle.&lt;/p&gt;
&lt;p&gt;If you have the time, I&#39;d be happy to &lt;a href=&quot;https://jouni.kantola.se/contact&quot;&gt;hear from you&lt;/a&gt;. I want to get
your improvement ideas and share your reactions about being able to choose how
text is presented. My personal hopes are that others pick up on this. I don&#39;t
want to use my browser&#39;s Reader View, I want to read your blogs!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Permalinks for Eleventy headings</title>
    <link href="https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/"/>
    <updated>2021-02-05T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/</id>
    <content type="html">&lt;p&gt;Quite often I share URLs to a specific section of a web page. For code snippets,
on the other hand, I tend to copy &amp;amp; paste. On mobile, the chore of selecting,
copying and pasting text is a pain. For a recipient, &lt;strong&gt;snippet sharing also
results in loss of context&lt;/strong&gt;. A link would&#39;ve been more helpful.&lt;/p&gt;
&lt;p&gt;I&#39;ll describe how I use Eleventy, to handle links to sections and code snippets
here on the site.&lt;/p&gt;
&lt;h2 id=&quot;github-style-headings&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;GitHub style headings&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/#github-style-headings&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;The backstory for my choice of in-page permalink design, is inspiration from
GitHub&#39;s direct links to README sections. I wanted to automate generation of IDs
for headings and couple them with &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tags. For blogs in Markdown, Eleventy
can be extended with
&lt;a href=&quot;https://www.npmjs.com/package/markdown-it-anchor&quot; title=&quot;Node.js module markdown-it-anchor&quot;&gt;markdown-it-anchor&lt;/a&gt;.
I however, have blogs using both HTML and Markdown templates.&lt;/p&gt;
&lt;p&gt;I created a
&lt;a href=&quot;https://github.com/11ty/eleventy/issues/1593&quot; title=&quot;Eleventy feature request for generating section direct links&quot;&gt;feature
request issue for Eleventy&lt;/a&gt;, to find a source agnostic solution. The
following discussion, provided guidance towards the approach I&#39;ve taken.&lt;/p&gt;
&lt;h2 id=&quot;text-and-snippet-headings&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Text and snippet headings&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/#text-and-snippet-headings&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;11ty provides reusable functions for generating page content via shortcodes.
Shortcodes can be tweaked to fit site specifics, and are usable in both Markdown
and HTML templates. I aimed at creating headings for blog sections and code
snippets, mimicking how headings are generated by
&lt;code class=&quot;package&quot;&gt;markdown-it-anchor&lt;/code&gt;.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;eleventy-shortcode&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Eleventy shortcode&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/#eleventy-shortcode&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// direct link&#39;s text&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; symbol &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; slug &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;slug&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;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addShortcode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;h&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;level&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; classList &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;level&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// URL safe heading IDs&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&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;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[^&#92;w-]&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&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;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
&amp;lt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;tag&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; id=&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;classList &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; class=&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;classList&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&gt;
  &amp;lt;span class=&quot;heading&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;text&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;
  &amp;lt;a class=&quot;direct-link&quot; href=&quot;#&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;symbol&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/a&gt;
&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;tag&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&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;!-- prettier-ignore-end --&gt;
&lt;p&gt;The shortcode &lt;code&gt;h&lt;/code&gt; declares parameters for heading &lt;code&gt;level&lt;/code&gt; (e.g. &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;) and
&lt;code&gt;text&lt;/code&gt;. The heading&#39;s text is used to generate IDs and associated anchor tags.
Optionally, the shortcode also supports specifying additional CSS classes to
style headings contextually.&lt;/p&gt;
&lt;h2 id=&quot;shortcode-in-action&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Shortcode in action&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/#shortcode-in-action&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Regardless if a blog&#39;s template is HTML or Markdown, the shortcode is used the
same way. Below follows an example for how the shortcode is called.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;use-heading-shortcode&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Use heading shortcode&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/#use-heading-shortcode&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;HyperText Markup Language&quot; class=&quot;code-snippet__lang bold&quot;&gt;html&lt;/abbr&gt;
    &lt;/div&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;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&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;code-snippet__description&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;
  {% h 4 &quot;Eleventy shortcode&quot; &quot;code-snippet__comment&quot; %}
  &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;abbr&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&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;JavaScript&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&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;code-snippet__lang&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;js&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;abbr&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;div&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;!-- prettier-ignore-end --&gt;
&lt;p&gt;I specify page headings to use &lt;code&gt;flexbox&lt;/code&gt;, to enable styling based on page
layout. The advantage of doing this, is that the heading&#39;s direct link&#39;s can be
repositioned. To render the direct link before the heading text, the following
CSS can be used.&lt;/p&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;reverse-heading-and-link-order&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Reverse heading and link order&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/#reverse-heading-and-link-order&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;Cascading Style Sheets&quot; class=&quot;code-snippet__lang bold&quot;&gt;css&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* reverse heading&#39;s element order */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;flex-direction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; row-reverse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex-end&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;low-key-discoverable-links&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Low-key, discoverable links&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/#low-key-discoverable-links&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Permalinks don&#39;t add any value if they aren&#39;t used. After all, the use case is
navigation and sharing. Poorly chosen additional elements are noise. In
contrast, without visible elements in-page navigation is hard to discover. In my
opinion, (subtle) hints should always be visible for touch device users. For
desktop users, the sweet spot is to show the links as the user tracks the page
with their mouse or keyboard.&lt;/p&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;heading-and-link-css&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Heading and link CSS&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-02-05/permalinks-for-eleventy-headings/#heading-and-link-css&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;Cascading Style Sheets&quot; class=&quot;code-snippet__lang bold&quot;&gt;css&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.direct-link:active,
.direct-link:hover,
.direct-link:focus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; underline&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&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 selector&quot;&gt;:is(h2, h3, h4) &gt; .direct-link&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inherit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin-left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&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 selector&quot;&gt;:is(h2, h3, h4):active &gt; .direct-link,
:is(h2, h3, h4):hover &gt; .direct-link,
:is(h2, h3, h4):focus &gt; .direct-link&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inherit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin-left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&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 atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;hover&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hover&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;:is(h2, h3, h4) &gt; .direct-link&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&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;In this blog, I&#39;ve intentionally included direct links for all sections. Often,
that&#39;s likely over the top. Keep your reader&#39;s experience top of mind, but do
help them share your legwork.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Call Google Cloud Functions with C#</title>
    <link href="https://jouni.kantola.se/blog/2021-01-15/call-google-cloud-functions-with-csharp/"/>
    <updated>2021-01-15T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2021-01-15/call-google-cloud-functions-with-csharp/</id>
    <content type="html">&lt;p&gt;When using C# and .NET to consume IAM protected cloud functions in Google Cloud
Platform (GCP), a lot of information unpacking is needed. In particular, when
calls are made from outside of GCP. I hope I can provide a little guidance.&lt;/p&gt;
&lt;h2&gt;Authentication&lt;/h2&gt;
&lt;p&gt;Cloud function invocation is secured by IAM (acronym of Cloud Identity and
Access Management). Callers of HTTP Functions need the IAM role
&lt;code&gt;roles/cloudfunctions.invoker&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Function requests should carry a resource specific access token, a &lt;em&gt;bearer
token&lt;/em&gt;. The resource&#39;s identifier is called &lt;em&gt;audience&lt;/em&gt;. For HTTP functions the
resource identifier/audience is the endpoint&#39;s URL. In C#, authentication is
provided by the
&lt;a href=&quot;https://www.nuget.org/packages/Google.Apis.Auth/&quot; title=&quot;NuGet package for Google Cloud Platform authentication&quot;&gt;Google.Apis.Auth
NuGet package&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once the bearer token is acquired, the cloud function request can be sent, with
the token included in the &lt;em&gt;Authorization&lt;/em&gt; HTTP header.
&lt;code&gt;AuthenticationHeaderValue&lt;/code&gt; in namespace &lt;code&gt;System.Net.Http.Headers&lt;/code&gt;, provide
functionality for formatting the HTTP request header.&lt;/p&gt;
&lt;h2&gt;Cloud function request&lt;/h2&gt;
&lt;p&gt;The below example fetches an access token and then invokes a HTTP Function.
Authentication credentials are catered by a
&lt;a href=&quot;https://cloud.google.com/docs/authentication/production#manually&quot; title=&quot;Generate service account key&quot;&gt;service
account key&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;post-file-to-cloud-function&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Post file to cloud function&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-01-15/call-google-cloud-functions-with-csharp/#post-file-to-cloud-function&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;C#&quot; class=&quot;code-snippet__lang bold&quot;&gt;C#&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;Google&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Apis&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OAuth2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PostFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FileInfo&lt;/span&gt; file&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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; functionUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://[REGION].cloudfunctions.net/my-function&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; credentialsPath &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Environment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;GOOGLE_APPLICATION_CREDENTIALS&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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; oidcToken &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; GoogleCredential
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FromFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;credentialsPath&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;GetOidcTokenAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;OidcTokenOptions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FromTargetAudience&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;functionUrl&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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; token &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; oidcToken&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetAccessTokenAsync&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;using&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; stream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; File&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;OpenRead&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;FullName&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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; formData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;MultipartFormDataContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Guid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NewGuid&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;ToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;N&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;
  formData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;StreamContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stream&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;file&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Name&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;using&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;HttpClient&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;
  client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DefaultRequestHeaders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Authorization &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;AuthenticationHeaderValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bearer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; token&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;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;PostAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;functionUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; formData&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&gt;Subpar docs&lt;/h2&gt;
&lt;p&gt;Put politely, the .NET API docs for Google Cloud Platform has improvement
potential. Often, to understand what APIs and NuGet packages to use and how,
involves tying together code samples from other programming languages and
documentation from multiple sources. Exploration can be confusing, but the docs
site for
&lt;a href=&quot;https://googleapis.github.io/google-cloud-dotnet/&quot; title=&quot;.NET client library docs&quot;&gt;Google
Cloud Libraries for .NET&lt;/a&gt; seems to be a decent starting point.&lt;/p&gt;
&lt;p&gt;I hope I&#39;ve now assisted somewhat, if nothing else than by showing how to call
secured cloud functions.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Generate selfie favicons</title>
    <link href="https://jouni.kantola.se/blog/2021-01-12/generate-selfie-favicons/"/>
    <updated>2021-01-12T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2021-01-12/generate-selfie-favicons/</id>
    <content type="html">&lt;p&gt;Just over 10 years ago, in the green sea off the west coast of Malaysia, I shot
an underwater selfie. That image has since become part of my online presence.
Now also as favicons, a set generated with Node.js.&lt;/p&gt;
&lt;h2&gt;Face blowing a kiss&lt;/h2&gt;
&lt;p&gt;Until recently, I used an emoji as favicon. The icon set was generated from the
Unicode character 😘 with an
&lt;a href=&quot;https://favicon.io/&quot; title=&quot;Favicon generator&quot;&gt;online favicon
generator&lt;/a&gt;. I&#39;m pro emoji, but I wanted a more personal touch for
&lt;a href=&quot;https://jouni.kantola.se/&quot; title=&quot;Jouni Kantola. Web developer.&quot;&gt;my web site&lt;/a&gt;. Like an underwater selfie.&lt;/p&gt;
&lt;h2&gt;Source photo&lt;/h2&gt;
&lt;p&gt;Once I decided to generate selfie favicons, I had to dig through my photo
archive to find the source photo. The images I used on Twitter, GitHub and
Gravatar were all of poor quality. Once I found the original, I cropped it to a
quadratic (high resolution) image.&lt;/p&gt;
&lt;h2&gt;Node.js module&lt;/h2&gt;
&lt;p&gt;Instead of the online favicon generator, I wanted more control of which
platforms to create images for. I found the Node.js module
&lt;a href=&quot;https://www.npmjs.com/package/favicons&quot; title=&quot;Favicons @ npm&quot;&gt;Favicons&lt;/a&gt;.
Not only does the module generate favicons, it also scaffolds a
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Manifest&quot; title=&quot;Web app manifest documentation&quot;&gt;web
app manifest&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Generate favicons&lt;/h2&gt;
&lt;p&gt;After a couple of test runs, I opted for an icon set targeting web, iOS and
Android. The favicon module supports other platforms and legacy formats than the
ones I cherry picked.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;favicons-setup&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Favicons setup&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2021-01-12/generate-selfie-favicons/#favicons-setup&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fs &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;fs&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;promises&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; favicons &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;favicons&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;const&lt;/span&gt; config &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 literal-property property&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;appName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Jouni Kantola. Web developer.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;appShortName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Jouni Kantola&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;appDescription&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;I&#39;m Jouni. I do web.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ltr&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#222&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;theme_color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#222&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;standalone&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;orientation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;any&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;start_url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;https://jouni.kantola.se/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;icons&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 literal-property property&quot;&gt;favicons&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;appleIcon&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;appleStartup&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;coast&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;firefox&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;yandex&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&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 keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateFavicons&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;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; selfie &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;selfie-2728x2728.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; outputPath &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;__dirname&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/favicons&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;outputPath&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;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      images&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      files&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      html&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 operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;favicons&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selfie&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; config&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;const&lt;/span&gt; out &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 operator&quot;&gt;...&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;images&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;map&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 parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; contents &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
      fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;outputPath&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        contents
      &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;
    out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;outputPath&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/meta-tags.html&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        html&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&#92;n&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;

    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;out&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;catch&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;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&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 function&quot;&gt;generateFavicons&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;!-- prettier-ignore-end --&gt;
&lt;p&gt;Currently I use seven favicons (View Source is your friend). Them and my
&lt;a href=&quot;https://jouni.kantola.se/assets/images/avatar-512x512.png&quot; title=&quot;og:image&quot;&gt;image for social shares&lt;/a&gt; are all
generated with the above code snippet. Now go personalize your web site! 😘&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>No fuzz development with EcmaScript modules</title>
    <link href="https://jouni.kantola.se/blog/2020-12-20/no-fuzz-development-with-ecmascript-modules/"/>
    <updated>2020-12-20T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2020-12-20/no-fuzz-development-with-ecmascript-modules/</id>
    <content type="html">&lt;p&gt;Browser support for EcmaScript modules (ESM) is good. In my opinion, widespread
enough to take advantage of to reduce complexity in your development workflow.&lt;/p&gt;
&lt;p&gt;Let me describe a bundler free approach for developing, unit testing and
shipping JavaScript. We&#39;ll unit test our code in Node.js and then serve the code
unchanged to the browser.&lt;/p&gt;
&lt;h2&gt;Unit testing ES modules&lt;/h2&gt;
&lt;p&gt;By using file extension &lt;code class=&quot;path&quot;&gt;.mjs&lt;/code&gt; with your JavaScript
files, you&#39;ll get out of the box Node.js support (as of v13.2.0) for EcmaScript
modules, and have &lt;code&gt;import&lt;/code&gt; and &lt;code class=&quot;path&quot;&gt;export&lt;/code&gt; statements
available to you.&lt;/p&gt;
&lt;p&gt;Let&#39;s build a module, for which we&#39;ll add unit tests and then ship to the
browser.&lt;/p&gt;
&lt;p&gt;First install the test runner
&lt;a href=&quot;https://www.npmjs.com/package/ava&quot; title=&quot;AVA Node.js test runner&quot;&gt;AVA&lt;/a&gt;
and thereafter create &lt;code class=&quot;path&quot;&gt;test-convert-temp-units.mjs&lt;/code&gt; for
our unit tests.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;prepare-unit-testing&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Prepare unit testing&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-12-20/no-fuzz-development-with-ecmascript-modules/#prepare-unit-testing&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;Shell Script&quot; class=&quot;code-snippet__lang bold&quot;&gt;sh&lt;/abbr&gt;
    &lt;/div&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;# Install ava with npm&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&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; ava --save-dev

&lt;span class=&quot;token comment&quot;&gt;# Create folder and unit tests script&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; test/test-convert-temp-units.mjs&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;As the filename hints, we&#39;ll be converting units of temperature, between Celsius
to/from Fahrenheit.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;unit-tests&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Unit tests&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-12-20/no-fuzz-development-with-ecmascript-modules/#unit-tests&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// test/test-convert-temp-units.mjs&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; test &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ava&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; cToF&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fToC &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../src/convert-temp-units.mjs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;celsius to fahrenheit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cToF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&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 number&quot;&gt;50&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 function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fahrenheit to celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fToC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;95&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 number&quot;&gt;35&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 function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;same °F as °C&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cToF&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;&lt;span class=&quot;token number&quot;&gt;40&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;fToC&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;&lt;span class=&quot;token number&quot;&gt;40&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;!-- prettier-ignore-end --&gt;
&lt;p&gt;If we execute the tests with &lt;code class=&quot;command&quot;&gt;npx test&lt;/code&gt;, we&#39;ll get an
error explaining &lt;em&gt;Cannot find module [...]/src/convert-temp-units.mjs&lt;/em&gt;. Let&#39;s
create our application code module.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;code-for-temperature-conversion&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Code for temperature conversion&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-12-20/no-fuzz-development-with-ecmascript-modules/#code-for-temperature-conversion&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/convert-temp-units.mjs&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cToF&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;celsius&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  celsius &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fToC&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;fahrenheit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fahrenheit &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&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; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Another run with AVA should now show us 3 passing tests.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;run-unit-tests&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Run unit tests&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-12-20/no-fuzz-development-with-ecmascript-modules/#run-unit-tests&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;Shell Script&quot; class=&quot;code-snippet__lang bold&quot;&gt;sh&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; npx ava &lt;span class=&quot;token parameter variable&quot;&gt;--verbose&lt;/span&gt;

  ✔ celsius to fahrenheit
  ✔ fahrenheit to celsius
  ✔ same °F as °C

  &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; tests passed&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;h2&gt;ES modules in the browser&lt;/h2&gt;
&lt;p&gt;To consume our code in the browser, we&#39;ll have to declare that the script is an
EcmaScript module. This is achieved with &lt;code&gt;&amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;/code&gt;. Let&#39;s create
a web page for converting temperature units, where we &lt;code&gt;import&lt;/code&gt; the file
&lt;code class=&quot;path&quot;&gt;convert-temp-units.mjs&lt;/code&gt;.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;import-es-module-in-browser&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Import ES module in browser&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-12-20/no-fuzz-development-with-ecmascript-modules/#import-es-module-in-browser&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;HyperText Markup Language&quot; class=&quot;code-snippet__lang bold&quot;&gt;html&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&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;html&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;lang&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;en&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;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;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;°C to °F&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;title&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 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;main&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Temperature unit conversion&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;h1&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;form&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;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&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;celsius&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;°C&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;label&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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;number&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;celsius&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&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;celsius&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;output&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-unit&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;fahrenheit&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;output&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;form&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;form&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;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&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;fahrenheit&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;°F&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;label&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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;number&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;fahrenheit&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&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;fahrenheit&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;output&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-unit&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;celsius&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;output&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;form&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;main&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;type&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;module&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 class=&quot;token language-javascript&quot;&gt;
    &lt;span class=&quot;token comment&quot;&gt;// import functions from .mjs&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; cToF&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fToC &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./convert-temp-units.mjs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; asFahrenheit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;*[data-unit=&#39;fahrenheit&#39;]&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;const&lt;/span&gt; asCelsius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;*[data-unit=&#39;celsius&#39;]&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;

    celsius&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input&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 parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        asFahrenheit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cToF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&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;

    fahrenheit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input&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 parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        asCelsius&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fToC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&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&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;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;!-- prettier-ignore-end --&gt;
&lt;p&gt;Notice how the the conversion functions are imported and called the same way as
in Node.js.&lt;/p&gt;
&lt;h2&gt;No bundler&lt;/h2&gt;
&lt;p&gt;If you know your target audience, you can make life easier for yourself by
developing interactive web pages like in the good ol&#39; days. Choose your
development stack to match your user&#39;s needs. Make deliberate decisions. Ask
yourself if you can serve your application without using a bundler. I&#39;ll bet,
quite often you can improve your development experience by not adding
unnecessary tooling.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The unpragmatic programmer</title>
    <link href="https://jouni.kantola.se/blog/2020-05-09/the-unpragmatic-programmer/"/>
    <updated>2020-05-09T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2020-05-09/the-unpragmatic-programmer/</id>
    <content type="html">&lt;p&gt;I have a &lt;code&gt;DIARY.md&lt;/code&gt; for logging progress at the gym. It&#39;s a long file, partly
because I&#39;ve been consistently going since late 2018. For that, I pat myself on
the shoulder. It&#39;s also long, because I early on decided to build a web app for
logging my sessions. While at it, I figured I&#39;d take on the challenge to build a
UI framework.&lt;/p&gt;
&lt;h2&gt;Choosing problem&lt;/h2&gt;
&lt;p&gt;From the get-go, I knew I&#39;d end up with a ton of problems to solve. I was, and
am fine with that. What I&#39;ve done miserably wrong is to not turn back, and start
solving one problem at the time. I could&#39;ve solved data storage for my sessions.
That would be an isolated problem. I could&#39;ve opted for static HTML pages. That
would suffice for complete user flows. Here I am, 1.5 years later, still
committing training logs to a Markdown file. Point being, even with
opportunities for self-improvement, problems shouldn’t be conflated into
unnecessary complexity.&lt;/p&gt;
&lt;h2&gt;Project fatigue&lt;/h2&gt;
&lt;p&gt;Every software undertaking comes with constraints. Likely, these constraints
exist to not over-consume scarce resources. Time being one of them, which is of
particular importance in side-projects. I&#39;m balancing side-project efforts with
family time or sleep. If I overstep, I hurt my family and/or myself. Clear
checkpoints are an energy source. Once I reach one, I can enjoy the result. Too
vague goals opens up for ineffective drifting. Drifting is mentally taxing for
me, sometimes enough to negatively affect the constraints I move within. When
I&#39;m out of bounds, I drain myself for unclear reasons. Here my interest starts
to fade. I stagnate and I tire.&lt;/p&gt;
&lt;h2&gt;Stop-and-go&lt;/h2&gt;
&lt;p&gt;I&#39;m driven by learning. In this, I have one side of me that is keen on
experimenting to understand topics at depth. I also have an impatient side,
which constantly has me looking for new input. Both of these tend to barge in
when I myself is the sole stakeholder. When I let any of these traits take too
much mental space, I often find myself doing something unplanned. Over time,
I&#39;ve tried to find patterns to look out for, to manage myself. The success rate
of steering myself back on track is varied, but I&#39;m getting better at it. Key
for me is to stop starting new things.&lt;/p&gt;
&lt;h2&gt;Make it work, make it better&lt;/h2&gt;
&lt;p&gt;I tend to overthink things. Thinking alone doesn&#39;t result in any code. On the
contrary, it opens up a Pandora&#39;s Box of possible solutions. Possibilities, by
definition are things that may happen. Better are solutions in the hands of
users. Interactions enable feedback. In this case, for my own benefit. In my
training, I have a range of about 10 exercises. To list these, I do not need a
unidirectional data flow architecture. Yet, it&#39;s that architectural problem
space I keep finding myself in. In part the reason is interest, but the main
offender is probably procrastination. At the point where a hack enables
shipping, that is what I should choose. Code is meant to be run and used. Naive
implementations pave the way for better things. The learning opportunity I’ve
enabled for myself should be scoped as improvements, not a requirement.&lt;/p&gt;
&lt;h2&gt;Focus on outcome&lt;/h2&gt;
&lt;p&gt;I strive to be deliberate in the choices I make. If I’m not deliberate, I’m
annoyed with myself. That’s why this side project has become something of a
thorn in my side. At work I’m outcome focused. I have colleagues for whom
pragmatism comes naturally, who are a great inspiration for me. They complement
my weaker sides. We prioritize usefulness. I cannot even recall when I last
could guilt my work I for taking me off balance. I’ve noticed this makes me feel
better overall.&lt;/p&gt;
&lt;p&gt;As usefulness is what makes me tick, the next time I feel an urge for
reusability, it’s a hardcoding I’ll type.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Audit web performance in development environment</title>
    <link href="https://jouni.kantola.se/blog/2020-04-05/lighthouse-development-audits/"/>
    <updated>2020-04-05T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2020-04-05/lighthouse-development-audits/</id>
    <content type="html">&lt;p&gt;I&#39;ve listed this site into the
&lt;a href=&quot;https://twitter.com/jouni_kantola/status/1244406108938174465&quot; title=&quot;Eleventy Performance Leaderboard ranking&quot;&gt;Eleventy Performance
Leaderboard&lt;/a&gt;. When doing so, I figured it&#39;d be good to &lt;strong&gt;tighten the feedback
loop&lt;/strong&gt; for tracking effect of changes. Shipping to production and then
measuring, is a long roundtrip to find a change made performance worse.&lt;/p&gt;
&lt;h2 id=&quot;production-like-performance-audits&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Production-like performance audits&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-04-05/lighthouse-development-audits/#production-like-performance-audits&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;With a static site generator, like Eleventy, serving its output with a web
server enables running &lt;strong&gt;local performance audits&lt;/strong&gt;. Eleventy&#39;s built-in
development server doesn&#39;t quite cut it, as it includes assets you don&#39;t want to
account for in an analysis. Another hurdle to achieve production-like audits, is
that tools like Lighthouse expect your assets to be served with HTTP/2.&lt;/p&gt;
&lt;p&gt;Serving your static site with HTTP/2 can be achieved with
&lt;a href=&quot;https://github.com/GoogleChromeLabs/simplehttp2server&quot; title=&quot;A simple HTTP/2 server for development&quot;&gt;simplehttp2server&lt;/a&gt;.
Via &lt;strong&gt;npm script&lt;/strong&gt; you can run the web server with Eleventy&#39;s output in an easy
way.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;run-simplehttp2server&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Run simplehttp2server&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-04-05/lighthouse-development-audits/#run-simplehttp2server&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript Object Notation&quot; class=&quot;code-snippet__lang bold&quot;&gt;json&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eleventy --input=./src/ --output=_site&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eleventy --input=./src/ --serve&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;serve&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yarn build &amp;amp;&amp;amp; cd ./_site &amp;amp;&amp;amp; simplehttp2server&quot;&lt;/span&gt;&lt;/mark&gt;
&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;After executing &lt;code class=&quot;command&quot;&gt;yarn serve&lt;/code&gt;, you&#39;ll likely get a
warning about the certificate not being trusted when browsing your site. Instead
of getting your browser to trust &lt;code class=&quot;command&quot;&gt;simplehttp2server&lt;/code&gt;&#39;s self-signed certificate, I
recommend &lt;strong&gt;generating a development certificate&lt;/strong&gt; with
&lt;a href=&quot;https://mkcert.dev/&quot; title=&quot;mkcert&quot;&gt;mkcert&lt;/a&gt;. Use
&lt;code class=&quot;command&quot;&gt;mkcert&lt;/code&gt; to configure a local certificate authority.
Once done, replace &lt;code class=&quot;command&quot;&gt;simplehttp2server&lt;/code&gt;&#39;s with a trusted development
certificate.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;replace-certificate&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Replace certificate&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-04-05/lighthouse-development-audits/#replace-certificate&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;Shell Script&quot; class=&quot;code-snippet__lang bold&quot;&gt;sh&lt;/abbr&gt;
    &lt;/div&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;# Static site root&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ./_site

&lt;span class=&quot;token comment&quot;&gt;# Generate development certificate&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; mkcert localhost

&lt;span class=&quot;token comment&quot;&gt;# Replace certificate&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mv&lt;/span&gt; localhost.pem cert.pem

&lt;span class=&quot;token comment&quot;&gt;# Replace public key&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mv&lt;/span&gt; localhost-key.pem key.pem&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Now run &lt;code class=&quot;command&quot;&gt;yarn serve&lt;/code&gt; again. If you browse to your
site, you&#39;ll notice it&#39;s served with HTTP/2 with a valid &lt;strong&gt;mkcert development
certificate&lt;/strong&gt; issued by &lt;strong&gt;mkcert development CA&lt;/strong&gt;. With that, run a Lighthouse
audit to see what it recommends for you to adjust.&lt;/p&gt;
&lt;h2 id=&quot;development-vs-production&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Development vs Production&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-04-05/lighthouse-development-audits/#development-vs-production&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;As we now have production-like audits close at hand, we can track how changes
affect performance. To further extend this capability, install Node.js module
&lt;a href=&quot;https://www.npmjs.com/package/performance-leaderboard&quot; title=&quot;performance-leaderboard Node.js module&quot;&gt;performance-leaderboard&lt;/a&gt;.
Create a &lt;code class=&quot;path&quot;&gt;perf-test.js&lt;/code&gt; module in your repository, with
specification for what sites to test. I&#39;m running tests against development and
production to determine optimization efficacy.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;automated-lighthouse-audit&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Automated Lighthouse audit&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-04-05/lighthouse-development-audits/#automated-lighthouse-audit&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// perf-test.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; leaderboard &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;performance-leaderboard&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;async&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 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;let&lt;/span&gt; urls &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;https://localhost:5000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;https://jouni.kantola.se&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;

  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;leaderboard&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;urls&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;In practice, I run automated tests in two terminal windows; one with
&lt;code class=&quot;command&quot;&gt;yarn serve&lt;/code&gt; and another running
&lt;code class=&quot;command&quot;&gt;yarn perf-test&lt;/code&gt;. The audit provides you with a
comparison between development and production.
&lt;code class=&quot;package&quot;&gt;performance-leaderboard&lt;/code&gt; also keeps history of
executed runs in a &lt;code class=&quot;path&quot;&gt;./log&lt;/code&gt; folder.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;perform-audit&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Perform audit&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-04-05/lighthouse-development-audits/#perform-audit&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript Object Notation&quot; class=&quot;code-snippet__lang bold&quot;&gt;json&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eleventy --input=./src/ --output=_site&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eleventy --input=./src/ --serve&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;serve&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yarn build &amp;amp;&amp;amp; cd ./_site &amp;amp;&amp;amp; simplehttp2server&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;perf-test&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 ./perf-test&quot;&lt;/span&gt;&lt;/mark&gt;
&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Worth noting, comparisons against production are tricky. Infrastructure, like
hosting static assets on CDNs, affect performance a lot. With logs you can
detect what patterns works and which don&#39;t.&lt;/p&gt;
&lt;p&gt;Once you&#39;ve covered common well-known practices, you&#39;ll have to adapt
performance optimizations with &lt;strong&gt;your site&#39;s specific setup and UX top of
mind&lt;/strong&gt;. This is when your web performance audits will really shine.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Inline PostCSS generated CSS with Eleventy</title>
    <link href="https://jouni.kantola.se/blog/2020-03-15/inline-postcss-generated-css-with-11ty/"/>
    <updated>2020-03-15T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2020-03-15/inline-postcss-generated-css-with-11ty/</id>
    <content type="html">&lt;p&gt;Inlining CSS is a common practice for optimizing the
&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/critical-rendering-path/page-speed-rules-and-recommendations?hl=en#inline_render-blocking_css&quot; title=&quot;Inline render-blocking CSS&quot;&gt;critical rendering path&lt;/a&gt;. Once
you&#39;ve analyzed and factored out styles blocking rendering, you&#39;ll likely want
build time enhancements provided by tooling like PostCSS, before inlining.&lt;/p&gt;
&lt;h2 id=&quot;eleventy-shortcode&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Eleventy shortcode&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-15/inline-postcss-generated-css-with-11ty/#eleventy-shortcode&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Eleventy can extend the static site generation with definitions for reusable
content. You can utilize this capability to generate your web&#39;s critical path
CSS. Configure 11ty with an
&lt;a href=&quot;https://www.11ty.dev/docs/shortcodes/#shortcodes&quot; title=&quot;11ty Shortcodes&quot;&gt;universal
template shortcode&lt;/a&gt; for processing render blocking styles.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;postcss-shortcode&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;PostCSS shortcode&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-15/inline-postcss-generated-css-with-11ty/#postcss-shortcode&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPairedShortcode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postcss&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// for relative path CSS imports&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; filepath &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    __dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;src/_includes/critical-path.css&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;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postcss&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;// PostCSS plugins&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;postcss-import&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;precss&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;autoprefixer&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;cssnano&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;&lt;span class=&quot;token function&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    code&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 literal-property property&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; filepath &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;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;css&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;!-- prettier-ignore-end --&gt;
&lt;p&gt;The above shortcode configures PostCSS to process files imported to an entry
point, for which vendor prefix are generated, and finally minified.&lt;/p&gt;
&lt;h2 id=&quot;inline-styles&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Inline styles&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-15/inline-postcss-generated-css-with-11ty/#inline-styles&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;The shortcode is available to be referenced in a page layout, and fed the
critical rendering path CSS. An entry file is specified, which in turn enables
inlining of required component styles with the &lt;code&gt;@import&lt;/code&gt; directive.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;shortcode-in-page-layout&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Shortcode in page layout&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-15/inline-postcss-generated-css-with-11ty/#shortcode-in-page-layout&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;Liquid template language&quot; class=&quot;code-snippet__lang bold&quot;&gt;liquid&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-liquid&quot;&gt;&lt;code class=&quot;language-liquid&quot;&gt;&lt;span class=&quot;highlight-line&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&gt;
&lt;span class=&quot;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ... --&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;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;      &lt;span class=&quot;token liquid language-liquid&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{%&lt;/span&gt; postcss &lt;span class=&quot;token delimiter punctuation&quot;&gt;%}&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;        &lt;span class=&quot;token liquid language-liquid&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;include&lt;/span&gt; critical&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;css &lt;span class=&quot;token delimiter punctuation&quot;&gt;%}&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;      &lt;span class=&quot;token liquid language-liquid&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{%&lt;/span&gt; endpostcss &lt;span class=&quot;token delimiter punctuation&quot;&gt;%}&lt;/span&gt;&lt;/span&gt;&lt;/mark&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;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ... --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Template shortcodes can be used for definitions of styles for specific pages or
for inlining all CSS. What granularity you aim for, mostly becomes a matter of
prioritizing maintainability or performance requirements.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>webpack assets in ASP.NET</title>
    <link href="https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/"/>
    <updated>2020-03-10T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/</id>
    <content type="html">&lt;p&gt;As webpack continues to grow in popularity, more tooling evolves for a smooth
development experience. This is true for a story with webpack and ASP.NET
together as well, at least if you&#39;re running .NET Core. I want to share a
&lt;strong&gt;framework-neutral setup&lt;/strong&gt; with a satisfactory experience independent of
ASP.NET version.&lt;/p&gt;
&lt;p&gt;I&#39;ll describe how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integrate &lt;strong&gt;webpack 4 with ASP.NET MVC 5&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Use webpack&#39;s &lt;strong&gt;development server&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Get started with &lt;strong&gt;Hot Module Replacement&lt;/strong&gt; (HMR)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;p&gt;The first thing to do, in the root of your web project, is to install webpack
and its CLI. Run &lt;code class=&quot;command&quot;&gt;npm install webpack webpack-cli
--save-dev&lt;/code&gt;. Once installed, I recommend adding a convenience task in
&lt;code class=&quot;path&quot;&gt;package.json&lt;/code&gt; for executing webpack.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;build-task&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Build task&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#build-task&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript Object Notation&quot; class=&quot;code-snippet__lang bold&quot;&gt;json&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;echo &#92;&quot;Error: no test specified&#92;&quot; &amp;amp;&amp;amp; exit 1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;webpack&quot;&lt;/span&gt;&lt;/mark&gt;
&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;If you try &lt;code class=&quot;command&quot;&gt;npm run build&lt;/code&gt;, you&#39;ll likely get an
error stating &lt;em&gt;Can&#39;t resolve &#39;./src&#39;&lt;/em&gt;. To fix this, a configuration file for
webpack will come in handy. In the root of your project, add a
&lt;code class=&quot;path&quot;&gt;webpack.config.js&lt;/code&gt; file with the following content:&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;initial-webpack-configuration&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Initial webpack configuration&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#initial-webpack-configuration&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &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 comment&quot;&gt;// point this path to your entry,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// your non-minified start file&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./Scripts/main.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;!-- prettier-ignore-end --&gt;
&lt;p&gt;Once saved, webpack is now configured to build your JavaScript application and
output in into the folder &lt;code class=&quot;path&quot;&gt;./dist&lt;/code&gt;. For now, ASP.NET has
no understanding of webpack&#39;s output. Let&#39;s start integrating.&lt;/p&gt;
&lt;h2&gt;webpack 💝 ASP.NET&lt;/h2&gt;
&lt;p&gt;To be able to &lt;strong&gt;reference webpack&#39;s output in ASP.NET&lt;/strong&gt;, use npm to install
&lt;a href=&quot;https://www.npmjs.com/package/razor-partial-views-webpack-plugin&quot; title=&quot;Razor Partial Views Webpack Plugin&quot;&gt;razor-partial-views-webpack-plugin&lt;/a&gt;.
The plugin extends webpack&#39;s build with capability to &lt;strong&gt;generate Razor views&lt;/strong&gt;
for webpack assets. Which assets to create views for are configurable.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;generate-razor-views-with-webpack&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Generate Razor views with webpack&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#generate-razor-views-with-webpack&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; RazorPartialViewsWebpackPlugin &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;razor-partial-views-webpack-plugin&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;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &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 literal-property property&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./Scripts/main.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;output&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 comment&quot;&gt;// runtime asset location&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;publicPath&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/dist/&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 literal-property property&quot;&gt;plugins&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 keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RazorPartialViewsWebpackPlugin&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 literal-property property&quot;&gt;rules&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 punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// view for default chunk&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;template&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 comment&quot;&gt;// Razor directive&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@inherits System.Web.Mvc.WebViewPage&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;&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;!-- prettier-ignore-end --&gt;
&lt;p&gt;With the plugin for generating Razor views configured, a webpack build outputs a
&lt;code class=&quot;path&quot;&gt;main.cshtml&lt;/code&gt;. The partial view&#39;s content is a script
tag referencing webpack&#39;s built JavaScript file.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;partial-view-for-webpack-asset&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Partial view for webpack asset&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#partial-view-for-webpack-asset&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;C# HTML&quot; class=&quot;code-snippet__lang bold&quot;&gt;cshtml&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;@inherits System.Web.Mvc.WebViewPage

&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;type&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;text/javascript&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;/dist/main.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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Now reference the generated view in ASP.NET MVC&#39;s
&lt;code class=&quot;path&quot;&gt;_Layout.cshtml&lt;/code&gt;.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;partial-view-in-layout&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Partial view in layout&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#partial-view-in-layout&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;C# HTML&quot; class=&quot;code-snippet__lang bold&quot;&gt;cshtml&lt;/abbr&gt;
    &lt;/div&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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ... --&gt;&lt;/span&gt;
  @Html.Partial(&quot;~/dist/main.cshtml&quot;)
&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;That&#39;s it for using webpack&#39;s output in ASP.NET.&lt;/p&gt;
&lt;h2&gt;Improving development experience&lt;/h2&gt;
&lt;p&gt;With webpack integrated with ASP.NET, let&#39;s build on that to &lt;strong&gt;enhance the
development experience&lt;/strong&gt;. &lt;code class=&quot;package&quot;&gt;webpack-dev-server&lt;/code&gt;
provides automatic page refresh and hot swapping of modules, which saves you
from restarting the whole application after code updates. Install the
development server with npm and extend &lt;code class=&quot;path&quot;&gt;package.json&lt;/code&gt; to
run it for serving webpack&#39;s assets.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;run-webpack-development-server&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Run webpack development server&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#run-webpack-development-server&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript Object Notation&quot; class=&quot;code-snippet__lang bold&quot;&gt;json&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;echo &#92;&quot;Error: no test specified&#92;&quot; &amp;amp;&amp;amp; exit 1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;webpack-dev-server --hot&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/mark&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;webpack&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Update &lt;code class=&quot;path&quot;&gt;webpack.config.js&lt;/code&gt; to include &lt;code&gt;devServer&lt;/code&gt; and signal that
assets no longer are served from &lt;code class=&quot;path&quot;&gt;./dist&lt;/code&gt; folder. These configuration updates
also function as scaffolding for partial views used in ASP.NET.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;serve-assets-with-development-server&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Serve assets with development server&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#serve-assets-with-development-server&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;output&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 comment&quot;&gt;// assets served by webpack-dev-server&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;publicPath&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://localhost:8080/&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 literal-property property&quot;&gt;devServer&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 comment&quot;&gt;// output assets to disk for ASP.NET&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;writeToDisk&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// clearly display errors&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;overlay&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// include CORS headers&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;headers&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-property property&quot;&gt;&quot;Access-Control-Allow-Origin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&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 comment&quot;&gt;// use self-signed certificate&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Run &lt;code class=&quot;command&quot;&gt;npm start&lt;/code&gt; and start your ASP.NET web
application. Open your browser&#39;s development tools and take notice of &lt;em&gt;Loading
failed for the &amp;lt;script&amp;gt; with source
&amp;quot;https://localhost:8080/main.js&amp;quot;&lt;/em&gt;. The reason for the error, is the
browser not trusting the development server&#39;s self-signed certificate. For now,
browse to &lt;code class=&quot;url&quot;&gt;https://localhost:8080/&lt;/code&gt; to accept the
certificate. We&#39;ll get to a proper fix shortly.&lt;/p&gt;
&lt;p&gt;Browse back to the web application and see your JavaScript code running. Now we
reap rewards of our work. In the development console you should have webpack&#39;s
development server signaling &lt;em&gt;Hot Module Replacement enabled&lt;/em&gt; and &lt;em&gt;Live
Reloading enabled&lt;/em&gt;. Make a JavaScript update and notice the browser refresh.
Happy times!&lt;/p&gt;
&lt;h2&gt;Trusted development certificate&lt;/h2&gt;
&lt;p&gt;I recommend generating a &lt;strong&gt;trusted development certificate&lt;/strong&gt; for
&lt;code class=&quot;package&quot;&gt;webpack-dev-server&lt;/code&gt;. That&#39;ll smoothen cross-browser
testing, without having to hack about with getting your browser to trust a
self-signed certificate. &lt;a href=&quot;https://mkcert.dev/&quot; title=&quot;mkcert&quot;&gt;mkcert&lt;/a&gt;
provides the feature to create an ample certificate. Install the tool, and run
the setup of a local certificate authority. Thereafter, generate a development
certificate in your web project root.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;generate-development-certificate&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Generate development certificate&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#generate-development-certificate&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;Shell Script&quot; class=&quot;code-snippet__lang bold&quot;&gt;sh&lt;/abbr&gt;
    &lt;/div&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;# Install local certificate authority&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; mkcert &lt;span class=&quot;token parameter variable&quot;&gt;-install&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Generate development certificate&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; mkcert localhost&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Once the certificate is generated, update webpack&#39;s
&lt;code class=&quot;package&quot;&gt;devServer&lt;/code&gt; configuration to start using it.
Afterwards, your browser will consider the connection to the development server
as secure.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;certificate-for-webpack-dev-server&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Certificate for webpack-dev-server&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#certificate-for-webpack-dev-server&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fs &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;fs&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;/*...*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;devServer&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;writeToDisk&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;overlay&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;headers&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;     &lt;span class=&quot;token string-property property&quot;&gt;&quot;Access-Control-Allow-Origin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;// use development certificate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;https&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&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;cert&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./localhost.pem&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;/mark&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./localhost-key.pem&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/mark&gt;
&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;h2&gt;Hot Module Replacement&lt;/h2&gt;
&lt;p&gt;So far, you&#39;ve gained automatic page refresh when updating JavaScript. This
alone is an improvement compared to full recycle via Visual Studio&#39;s Start
Debugging. With Hot Module Replacement (HMR) the &lt;strong&gt;feedback loop is tightened&lt;/strong&gt;
even more.&lt;/p&gt;
&lt;p&gt;HMR enables swapping updated modules without reloading the page. When you update
front-end code, take notice of the message &lt;em&gt;[HMR] Aborted because [module] is
not accepted&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Hot Module Replacement is activated by signaling to webpack if and when changes
are accepted by using the &lt;code&gt;module.hot&lt;/code&gt; API. Pay attention to side-effects (like
appending elements to DOM), as they likely have to be accounted for before
modules are reapplied.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;allow-swapping-modules&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Allow swapping modules&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#allow-swapping-modules&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; create &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./state-picker&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; statePicker &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;create&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;
document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prepend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;statePicker&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;// is HMR activated?&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// don&#39;t activate in production&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;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hot&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;// accept changes&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// for this module and dependencies&lt;/span&gt;
  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;accept&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;

  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dispose&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 operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// prevent multiple&lt;/span&gt;
    statePicker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&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;!-- prettier-ignore-end --&gt;
&lt;p&gt;Include &lt;code&gt;module.hot.accept()&lt;/code&gt; in your JavaScript code. You&#39;ll notice how the
page doesn&#39;t refresh on every update. Instead &lt;strong&gt;webpack knows what modules have
been updated&lt;/strong&gt;. Great success!&lt;/p&gt;
&lt;h2&gt;Build for production&lt;/h2&gt;
&lt;p&gt;webpack comes with decent defaults for managing development and production
builds. Over time, you&#39;ll likely need to adapt your configuration more granular
according to target environment. For now, adapt webpack&#39;s &lt;code&gt;output&lt;/code&gt; configuration
to &lt;strong&gt;match your production environment&lt;/strong&gt; (e.g. use of CDN). Ensure paths and
cache busting are properly configured.&lt;/p&gt;
&lt;p&gt;To run a production build, execute &lt;code class=&quot;command&quot;&gt;npm run build --
--mode=production&lt;/code&gt; (yes, that&#39;s four hyphens, so consider another npm
script).&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;production-output&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Production output&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#production-output&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// export webpack.config.js as function&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&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 parameter&quot;&gt;env&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; argv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;/*...*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;output&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&gt;
&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mode &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;production&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[name].js&quot;&lt;/span&gt;&lt;/span&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[name].[contenthash].min.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/mark&gt;
&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;publicPath&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mode &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;production&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://localhost:8080/&quot;&lt;/span&gt;&lt;/span&gt;
&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/dist/&quot;&lt;/span&gt;&lt;/mark&gt;
&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Run a production build and peek into the generated
&lt;code class=&quot;path&quot;&gt;main.cshtml&lt;/code&gt;. It now references a minifed asset. Ship
it! 📦&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;production-script-minified&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Production script minified&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-03-10/webpack-assets-in-aspnet/#production-script-minified&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;C# HTML&quot; class=&quot;code-snippet__lang bold&quot;&gt;cshtml&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;@inherits System.Web.Mvc.WebViewPage

&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;type&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;text/javascript&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;/dist/main.66ca108e268.min.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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;webpack is a &lt;strong&gt;powerful toolbox&lt;/strong&gt; to utilize for delivering front-end assets.
One use case I thoroughly recommend using it for, is to evolve legacy
applications. webpack comes with support for multiple module systems, which
enables migration scenarios, like updating from AMD to ES modules.&lt;/p&gt;
&lt;p&gt;Plugins like
&lt;a href=&quot;https://www.npmjs.com/package/razor-partial-views-webpack-plugin&quot; title=&quot;Razor Partial Views Webpack Plugin&quot;&gt;razor-partial-views-webpack-plugin&lt;/a&gt;
takes the webpack ecosystem closer to ASP.NET&#39;s. Try it out! Adopt the habit of
running webpack in a terminal on the side. I hope you&#39;ll appreciate it as much
as I do.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Dark mode toggle</title>
    <link href="https://jouni.kantola.se/blog/2020-02-29/dark-mode-toggle/"/>
    <updated>2020-02-29T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2020-02-29/dark-mode-toggle/</id>
    <content type="html">&lt;p&gt;Dark mode for everyone, right? If you&#39;re about to add it to your web site, there
are a few things to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How do you &lt;strong&gt;toggle&lt;/strong&gt; between dark and light mode; by time of day, satisfy
operating system settings or user activation?&lt;/li&gt;
&lt;li&gt;How do you &lt;strong&gt;persist&lt;/strong&gt; the user&#39;s choice?&lt;/li&gt;
&lt;li&gt;How do you &lt;strong&gt;reactivate&lt;/strong&gt; the user&#39;s preference on return?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Automagic toggle&lt;/h2&gt;
&lt;p&gt;Lately color schemes, especially dark mode, have become &lt;strong&gt;inherent features&lt;/strong&gt; in
devices people use. When rendering color scheme, automatically setting mode can
be achieved both in CSS and JavaScript. You have the options to base mode on
operating system settings or time of day.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;background-by-preference&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Background by preference&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-02-29/dark-mode-toggle/#background-by-preference&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;Cascading Style Sheets&quot; class=&quot;code-snippet__lang bold&quot;&gt;css&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dark&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&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 atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; light&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fafafa&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 selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--background-color&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;!-- prettier-ignore-end --&gt;
&lt;p&gt;When using media queries, be thoughtful of feature detection and to fall back to
a default color scheme.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;append-class-based-on-preference&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Append class based on preference&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-02-29/dark-mode-toggle/#append-class-based-on-preference&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;matchMedia &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;(prefers-color-scheme: dark)&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;matches
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentElement
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dark-mode&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;
  &lt;span class=&quot;token comment&quot;&gt;// fallback&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentElement
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;light-mode&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;!-- prettier-ignore-end --&gt;
&lt;p&gt;A friendly gesture to your user could be to switch on &lt;strong&gt;dark mode in the
evening&lt;/strong&gt;. It&#39;s common that I adjust screen brightness when I browse web sites
with light colors in the evening.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;nighttime-dark-mode&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Nighttime dark mode&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-02-29/dark-mode-toggle/#nighttime-dark-mode&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;JavaScript&quot; class=&quot;code-snippet__lang bold&quot;&gt;js&lt;/abbr&gt;
    &lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hour &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&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;toLocaleTimeString&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 literal-property property&quot;&gt;hour&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;2-digit&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;hour12&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; hour &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; hour &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;19&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;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentElement
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;light-mode&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;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentElement
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dark-mode&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;!-- prettier-ignore-end --&gt;
&lt;h2&gt;Persist preference&lt;/h2&gt;
&lt;p&gt;It&#39;s a frequent sighting nowadays to have a dark and light switch, allowing
users to chose preferred mode. Quite plausible, the user would favor the same
choice on return. To persist the user&#39;s preference, it&#39;s key to consider how and
when to react to the stored value.&lt;/p&gt;
&lt;p&gt;Cookies enables server-side &lt;strong&gt;scaffolding the page&lt;/strong&gt; to reflect the user&#39;s
preference. The advantage of considering dark or light mode server-side, is that
it enables the right mode prior to applying styles.&lt;/p&gt;
&lt;p&gt;Another route is to save the user&#39;s choice in &lt;code&gt;localStorage&lt;/code&gt;. The &lt;em&gt;Web Storage
API&lt;/em&gt; is only accessible in the browser, and therefor confines you to toggle
accordingly client-side.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;store-users-choice&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Store user&#39;s choice&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-02-29/dark-mode-toggle/#store-users-choice&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;HyperText Markup Language&quot; class=&quot;code-snippet__lang bold&quot;&gt;html&lt;/abbr&gt;
    &lt;/div&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;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
  &lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;--background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;--text-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fafafa&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 selector&quot;&gt;input[name=&#39;color-scheme&#39;],
  input[name=&#39;color-scheme&#39;]:checked + label&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&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 selector&quot;&gt;#light-mode:checked ~ .content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;--background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fafafa&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;--text-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #222&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 selector&quot;&gt;.content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--background-color&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;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--text-color&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&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;style&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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;radio&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;light-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token attr-name&quot;&gt;value&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;light-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&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;color-scheme&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;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&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;light-mode&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;Light&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;label&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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;radio&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;dark-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token attr-name&quot;&gt;value&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;dark-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&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;color-scheme&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token attr-name&quot;&gt;checked&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;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&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;dark-mode&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;Dark&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;label&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;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&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;content&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;One ring&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;h1&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;In the darkness bind them&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;p&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;article&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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; modes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;input[name=&#39;color-scheme&#39;]&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;
  
  modes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token parameter&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;color-scheme&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&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&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;h2&gt;Preference activation&lt;/h2&gt;
&lt;p&gt;Don&#39;t welcome your visitors with a flash. &lt;strong&gt;Leaking a default color scheme&lt;/strong&gt;,
even for a brief moment, will result in an unpleasant user experience. Consider
color scheme activation without flashing when choosing toggling strategy.&lt;/p&gt;
&lt;p&gt;CSS media queries enables rendering the page without flash, but depends on
modern capabilities to exist in the user environment.&lt;/p&gt;
&lt;p&gt;For predictable dark or light mode activation in JavaScript, first bear in mind
whether the user even has JavaScript enabled. You&#39;ll also briefly be blocking
rendering as the page initial state is required to be &lt;strong&gt;determined prior to
rendering&lt;/strong&gt; a color scheme.&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
    &lt;div class=&quot;code-snippet__description&quot;&gt;
&lt;h3 id=&quot;activate-dark-or-light-mode&quot; class=&quot;code-snippet__comment&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Activate dark or light mode&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2020-02-29/dark-mode-toggle/#activate-dark-or-light-mode&quot;&gt;#&lt;/a&gt;
&lt;/h3&gt;
        &lt;abbr title=&quot;HyperText Markup Language&quot; class=&quot;code-snippet__lang bold&quot;&gt;html&lt;/abbr&gt;
    &lt;/div&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;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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; colorScheme &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;color-scheme&quot;&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; &lt;span class=&quot;token string&quot;&gt;&quot;light-mode&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&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 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 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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;radio&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;dark-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
   &lt;span class=&quot;token attr-name&quot;&gt;value&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;dark-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&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;color-scheme&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;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&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;dark-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
   &lt;span class=&quot;token attr-name&quot;&gt;class&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;color-scheme&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;Light&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;label&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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;radio&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;light-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
   &lt;span class=&quot;token attr-name&quot;&gt;value&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;light-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&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;color-scheme&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
   &lt;span class=&quot;token attr-name&quot;&gt;checked&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;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&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;light-mode&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
   &lt;span class=&quot;token attr-name&quot;&gt;class&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;color-scheme&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;Dark&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;label&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;type&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;text/javascript&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 class=&quot;token language-javascript&quot;&gt;
    &lt;span class=&quot;token comment&quot;&gt;// use preferred color scheme&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; useDark &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
      colorScheme &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dark-mode&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;dark-mode&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;checked &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; useDark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;light-mode&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;checked &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;useDark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ... --&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;I hope I&#39;ve provided some insights about things to consider when creating a dark
mode toggle. Carefully consider your UI to be &lt;strong&gt;predictable&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For inspiration, check the following examples. Try them out with or without
JavaScript enabled. For implementation details, &lt;em&gt;View Page Source&lt;/em&gt; is your
friend.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A widely supported example that use the
&lt;a href=&quot;https://jouni.kantola.se/blog/2020-02-29/dark-mode-toggle/example/&quot; title=&quot;Dark &amp; light mode switch using the radio button hack (with preferred choice kept in localStorage)&quot;&gt;Radio
Button Hack&lt;/a&gt; to pick mode.&lt;/li&gt;
&lt;li&gt;As of Safari 15.4 or later (example added 2022-04-29), you can test the
&lt;a href=&quot;https://jouni.kantola.se/blog/2020-02-29/dark-mode-toggle/has-selector/&quot; title=&quot;:has selector dark/light mode toggle&quot;&gt;:has
selector&lt;/a&gt;, which enable better structured HTML.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Decentraliserat lagarbete</title>
    <link href="https://jouni.kantola.se/blog/2018-11-25/decentraliserat-lagarbete/"/>
    <updated>2018-11-25T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2018-11-25/decentraliserat-lagarbete/</id>
    <content type="html">&lt;p&gt;Sedan jag nämnde konceptet &lt;em&gt;remote-first lagarbete&lt;/em&gt; för min fru så har hon
återkommit med jämna mellanrum om att hon inte gillar benämningen. Jag medger
att begreppet klingar &amp;quot;hellre än bra&amp;quot;. Jag uppskattar hennes engagemang, och
tolkar det som positivt att kritiken snabbt istället övergår till att prata om
arbetsformen. Enligt mig handlar arbetssättet i huvudsak om att &lt;strong&gt;arbetet är där
du är&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Arbetssätt är ett aggregat&lt;/h2&gt;
&lt;p&gt;Summan av det du och dina lagmedlemmar gör under arbetsdagen är för mig ert
arbetssätt. Om du och dina kollegor jobbar på distans, remote eller hemifrån,
vad uttrycker det om ert samarbete? För mig är tankar kring &lt;strong&gt;lagarbete
viktigare än eventuell distans&lt;/strong&gt;. Fokus bör inte vara avlägset arbete. Ni
&lt;strong&gt;förändrar tillsammans era förutsättningar&lt;/strong&gt; för att samarbete blir mindre
platsberoende. Jag föreslår att vi framgent istället pratar om &lt;strong&gt;decentraliserat
lagarbete&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Eftersom att jag anser det viktigt att beskriva arbetsformen på ett objektivt
sätt så har jag hittills inte sökt efter nya begrepp. Det jag vill understryka
med arbetssättet är:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lagarbete&lt;/li&gt;
&lt;li&gt;Samarbete kring arbetsuppgifter&lt;/li&gt;
&lt;li&gt;Fysisk plats är sekundärt&lt;/li&gt;
&lt;li&gt;Vilja att minska avstånd&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Där jag upplever att begreppet &lt;strong&gt;&amp;quot;remote-first&amp;quot; haltar&lt;/strong&gt; är att det inbyggt har
en underton som fokuserar på distans, att arbetet genomförs någon annanstans.
Jag vill &lt;strong&gt;fokusera på lagarbetet&lt;/strong&gt;. Lägg till komponenten att &lt;strong&gt;beslutsfattande
ska vara oberoende av plats&lt;/strong&gt;, så tycker jag att ordet &amp;quot;remote&amp;quot; inte räcker
till.&lt;/p&gt;
&lt;h2&gt;Vilja lyckas&lt;/h2&gt;
&lt;p&gt;Samarbete där plats ska ha liten betydelse ändrar förutsättningarna för hur
arbetet genomförs. Jag hävdar att det inte behöver innebära försämrade
förutsättningar. Lagarbete i sig kräver mycket omsorg och &lt;strong&gt;ständiga
förbättringar&lt;/strong&gt; för att förfinas. Respektera hindren och &lt;strong&gt;omfamna möjligheterna
med decentraliserat lagarbete&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Allt lagarbete kräver förtroende&lt;/strong&gt; för varandra och en vilja att lyckas för
att bli mer effektiva. För decentraliserat lagarbete kräver det även att dina
&lt;strong&gt;kollegor omkring laget vill lyckas med samarbetet&lt;/strong&gt;. Tålamod, gemensamt ansvar
och nyfikenhet är nyckelfaktorer för att tillsammans komma framåt när fysisk
plats ska vara sekundärt. Att decentralisera lagarbete är att flytta fokus från
fysiska begränsningar till &lt;strong&gt;förtroende för laget&lt;/strong&gt;. Effekten av förtroendet
&lt;strong&gt;speglas i utfall och kvalitet&lt;/strong&gt;.&lt;/p&gt;
&lt;p class=&quot;article__footer&quot;&gt;Jag har arbetat inom IT-branschen sedan 2006. De senaste fem åren har jag arbetat i företag
  där iterativ utveckling och snabba releaser är vardag. I dessa organisationer är förbättringsarbete kring samarbete
  centralt. Hur arbetet uppmuntras och går till ser däremot olika ut. Nu arbetar jag som webbutvecklare för Nepa Sweden
  AB, i ett team med lagmedlemmarna utspridda på flera svenska orter. Jag berättar gärna mer i detalj om hur vår
  vardag ser ut och mina erfarenheter av remote/distribuerat/decentraliserat lagarbete.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Hellre övertydlig, än otydlig</title>
    <link href="https://jouni.kantola.se/blog/2018-10-31/hellre-overtydlig-an-otydlig/"/>
    <updated>2018-10-31T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2018-10-31/hellre-overtydlig-an-otydlig/</id>
    <content type="html">&lt;p&gt;Föreställ dig själv som deltagare i en gruppövning. Mötesrummet har frostade
glasväggar. Dörren till rummet står på glänt. Ljudet smiter ut, av och till
tydligt, varvat med nästan ohörbart. Du deltar ståendes utanför. &lt;em&gt;&amp;quot;Jämför dessa
med de här&amp;quot;&lt;/em&gt; säger en av personerna och pekar på whiteboarden i rummet.
Förflytta dig i tanken till ditt hemmakontor, fortfarande deltagare i samma
övning med instruktionerna &amp;quot;dessa&amp;quot; och &amp;quot;de här&amp;quot;. Efter övningen känns deltagarna
i mötesrummet nöjda med resultatet. Du känner dig utanför. Ganska ofta så känns
&lt;strong&gt;möten som de situationer då distansarbete provtrycks&lt;/strong&gt; som mest.&lt;/p&gt;
&lt;p&gt;Föreställ dig själv som deltagare i &lt;strong&gt;en gruppövning. Det finns inget mötesrum
bokat.&lt;/strong&gt; Alla i övningen arbetar i samma
&lt;a href=&quot;https://trello.com/&quot;&gt;Trello-tavla&lt;/a&gt;. Digitala versioner av post-its
poppar upp i ett organiserat kaos. Efter sju tysta minuter så frågar en av
deltagarna &lt;em&gt;&amp;quot;Är alla klara, för att gå igenom idéerna?&amp;quot;&lt;/em&gt;. En efter en
förtydligas de brainstormade idéerna. Förslagen sorteras under &amp;quot;Behöver mer
information&amp;quot;, &amp;quot;Inget behov&amp;quot; eller &amp;quot;Att göra&amp;quot;. Flera av idéerna är snarlika
varandra och kan sorteras ut. Innan gruppövningen är klar &lt;strong&gt;väljer gruppen
tillsammans ut de idéer&lt;/strong&gt; som verkar mest intressanta att börja arbeta med.
Efter övningen känner sig deltagarna nöjda med resultatet. Du också.&lt;/p&gt;
&lt;p&gt;Båda scenarierna ovan är upplevda under min resa till remote-first. Jag har lärt
mig att tydlighet är viktigt. Det är viktigt att presentera, dela med sig av och
efterfråga information på ett tydligt sätt. &lt;strong&gt;Hellre övertydlig, än otydlig.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Lär dig krypa innan du går&lt;/h2&gt;
&lt;p&gt;Arbete remote ställer krav på att minska upplevda avstånd och vara lyhörd
gentemot dina kollegor. De &lt;strong&gt;upplevda avstånden förändras&lt;/strong&gt; i takt med vanan av
remote samarbete. Det är viktigt att pejla in känslorna i teamet, där vana
personer behöver betydligt mindre signaler om aktivitet, medan &lt;strong&gt;ovana kan känna
obehagskänslor&lt;/strong&gt; av detaljer som att kommunicera med en avatar. Om ni har lyxen
att organisera så att ert team kan träffas fysiskt under en period innan ni
påbörjar ett remote lagarbete, så rekommenderar jag er att göra det. Det är
lättare att lära känna varandra under samma tak. Ett överkomligt andra steg är
att förflytta någon eller några av lagmedlemmarna till andra rum, för att
&lt;strong&gt;börja öva på remote lagarbete&lt;/strong&gt; och kommunikation genom headsets.&lt;/p&gt;
&lt;p&gt;Oavsett vana av remote samarbete är &lt;strong&gt;kontinuerliga reflektioner&lt;/strong&gt; viktiga. Gör
medvetna val. Var tydlig med vad teamet bör fortsätta med och förändra ovanor
som påverkar arbetet negativt. Retrospektiv är om möjligt ännu viktigare i
remote-first samarbete. &lt;strong&gt;Ta tid i anspråk för att stärka lagkänsla&lt;/strong&gt; och att
individer ska få uttrycka frustrationer. För många är kafferaster en möjlighet
för att behandla skavande förhållanden. I team som arbetar remote är mötet kring
kaffemaskinen i bästa fall ersatt av en gemensam paus från arbetet. Var proaktiv
för att skapa miljöer för att andas ut. För att understryka medvetna val, när en
&lt;strong&gt;förändring genomförs så planera också in en utvärdering&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Teknik (inte) en förutsättning&lt;/h2&gt;
&lt;p&gt;Remote-first står inte och faller med tekniska förutsättningar, trots att det
ofta är teknik som anges som anledning till att samarbete remote är för
besvärligt för att satsa på. Enligt mig, är det &lt;strong&gt;största hindret för remote
samarbete att inte vara proaktiv då information är otydlig&lt;/strong&gt;, både då den delges
och tillgodoses. Många av de situationer som sker på kontor för att få klarhet
handlar om att intressenter ställer frågor, medan det på distans oftare handlar
om det omvända, att aktivt visa för att få feedback. Som remote-first, våga
kräva att inte bli utelämnad.&lt;/p&gt;
&lt;p&gt;Teknik underlättar kommunikationen mellan lagmedlemmar om de har ändamålsenliga
headsets som aktivt kopplar bort omkringliggande brus. Det är också behagligare
för kollegor om så många som möjligt har en &lt;strong&gt;lugn omgivning&lt;/strong&gt;. Sunt förnuft,
respekt för varandra och att aktivt använda mute-knappen räcker långt. Var
proaktiva och inbjudande under remote samarbete, och eftersträva att &lt;strong&gt;hålla den
kommunikativa bandbredden så bred&lt;/strong&gt; som möjligt. Minska distansen till varandra
lite extra genom att aktivera video, i synnerhet då personen bakom tangentbordet
bör framträda lite extra, exempelvis under retrospektiv.&lt;/p&gt;
&lt;h2&gt;Strö remote frön&lt;/h2&gt;
&lt;p&gt;Med tiden kommer du och dina remote-first teammedlemmar känna er mer bekväma än
era kollegor under remote samarbete. Hitta tillfällen för att coacha andra och
etablera nätverk till andra team. Några rekommendationer jag har för att börja
vänja andra med remote-first är:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Du gör dig troligen en björntjänst om du utgår från att alla kan och vill
förbättra sättet de kommunicerar remote. Det underlättar om mer vana personer
är proaktiva och framhåller vikten av &lt;strong&gt;inte göra skillnad på kollegor som
arbetar remote&lt;/strong&gt;. Gör medvetna val för att gemensamt träna på att arbeta
remote.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avboka mötesrum för stående möte(n)&lt;/strong&gt;. Efter några försök kommer
förutsättningarna klarna för vad som bör förberedas för att få till ett
produktivt möte och hur kommunikationen underlättas. &lt;strong&gt;Onlinemöten har med
fördel en tydlig agenda&lt;/strong&gt; och beslut när mötet avrundas.&lt;/li&gt;
&lt;li&gt;I &lt;strong&gt;retrospektiv, ta gärna hjälp av personer utanför teamet&lt;/strong&gt; för att
facilitera mötet. Utöver att alla lagmedlemmar kan delta aktivt, så medför
detta den positiva effekten att öka andra kollegors förståelse för
remote-first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Håll kommunikation öppet i publika forum&lt;/strong&gt;. Styr aktivt kommunikation från
privata möten, chat eller korrespondens via epost till publika forum och/eller
chatkanaler. Reagera på signaler om att &lt;em&gt;&amp;quot;vi på kontoret har diskuterat&amp;quot;&lt;/em&gt;.
Desto fler som har tillgång till information, ju färre beroenden finns till
att vara på rätt plats vid rätt tidpunkt.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Förtroende trumfar fysisk närhet&lt;/h2&gt;
&lt;p&gt;Respektera hindren med att arbeta &lt;strong&gt;remote-first, och omfamna möjligheterna&lt;/strong&gt;.
Jobba från ett kontor, en sommarstuga, om du hellre trivs på landet eller i ett
tyst hörn av ett café. Det som är viktigt är att du aktivt jobbar för ett
respektfullt samarbete och gror förtroendet, där fysisk närhet är sekundärt.
Tillåt inte laget att stagnera, utan &lt;strong&gt;var nyfikna för att hitta
förbättringsområden&lt;/strong&gt; eller bättre tekniska verktyg, men &lt;strong&gt;låt vanor
stabiliseras&lt;/strong&gt; för att inte spendera för mycket tid på omlärning. Låt &lt;strong&gt;utfall
och kvalitet vara ett bevis för ett gott samarbete&lt;/strong&gt;. Personberoenden ska hållas
tillbaka genom att täppa hål som synliggörs extra mycket de gånger det inte
finns en kollega tillgänglig. Ta ett &lt;strong&gt;gemensamt ansvar för att bygga
förtroende&lt;/strong&gt; och vilja dela med sig av remote-first resan.&lt;/p&gt;
&lt;p class=&quot;article__footer&quot;&gt;Jag har arbetat inom IT-branschen sedan 2006. De senaste fem åren har jag arbetat i företag
  där iterativ utveckling och snabba releaser är vardag. I dessa organisationer är förbättringsarbete kring samarbete
  centralt. Hur arbetet uppmuntras och går till, ser däremot olika ut. Nu arbetar jag som webbutvecklare för Nepa Sweden
  AB, i ett Remote-First team. Jag berättar gärna mer i detalj om hur vår vardag ser ut och mina erfarenheter av
  distribuerade team och/eller Remote-First.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Närhet är relativt</title>
    <link href="https://jouni.kantola.se/blog/2018-10-09/narhet-ar-relativt/"/>
    <updated>2018-10-09T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2018-10-09/narhet-ar-relativt/</id>
    <content type="html">&lt;p&gt;Med laptopen i knät och solen gassandes över dig, så att du får kisa för att
urskilja texten på skärmen. Är det den romantiska bilden du ser framför dig när
du tänker på remote-first? Eller är det kanske att få komma undan från öppna
kontorslandskap, där du inte får flyt för att du blir störd av frågor och hög
ljudnivå? Distansjobb kan ge dig både palmer och sinnesro, men för mig är det
främst möjligheten att vara tillgänglig och nära familjen som är viktigt. Jag
vill att &lt;strong&gt;arbetet ska vara en pusselbit i livspusslet, inte ramen&lt;/strong&gt; för det.&lt;/p&gt;
&lt;p&gt;Jag tycker att människors självkänsla, egenvärde och personliga frihet alltför
länge har fått stå tillbaka för att &lt;strong&gt;samarbete arrangerats med begränsningen
att fysisk närhet är ett krav&lt;/strong&gt;. Vi behöver fler företag som ser nytta i att
medarbetare har en chans att få arbete och privatliv att funka tillsammans.
Istället för att optimera för kontroll, våga främja medarbetarnas välmående. Om
hållbart samarbete anses viktigt, att medarbetare får växa som lag, så &lt;strong&gt;tänk om
fysisk närhet är ett lokalt optimum&lt;/strong&gt;. Jag tror att vi istället ska få människor
att känna egenvärde och växa med förtroende, och genom det främja företaget.&lt;/p&gt;
&lt;h2&gt;Jag, inte längre pendlare&lt;/h2&gt;
&lt;p&gt;Jag är webbutvecklare i ett remote-first team där medlemmarna är utspridda i
Sverige. Vi på Nepa har startat ett teknikkontor i Uppsala, varifrån jag oftast
väljer att arbeta. Perioden inför att kontorsdörrarna skulle öppnas, så arbetade
jag från hemmet eller caféer. Jag föredrar nuvarande lösning eftersom att &lt;strong&gt;jag
anser att lagarbete på distans underlättas av en lugn arbetsmiljö&lt;/strong&gt;.
Flexibiliteten med att kunna jobba oberoende av plats, med närhet till familjen,
har gjort att jag upplever ett &lt;strong&gt;större andrum i livet&lt;/strong&gt; nu jämfört med tiden
som pendlare (som jag berättade om i
&lt;a href=&quot;https://jouni.kantola.se/blog/2018-10-02/arbete-ekar-i-huvudet/&quot; title=&quot;Stressad jobbpendlare&quot;&gt;förra delen&lt;/a&gt;).
Det är inte förrän nu, med pendelstressen bakom mig, som jag inser att jag
åsidosatte privatlivet. Jag känner mig allmänt mer välmående, men i synnerhet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Jag sover bättre. Jag har tvillingar som är drygt ett år, ändå upplever jag
min sömn nu som bättre än åren innan. Delvis har jag bestämt mig för att
prioritera sömn, men jag tolkar det framförallt som &lt;strong&gt;ett tecken på att jag
kan varva ner&lt;/strong&gt; på kvällarna.&lt;/li&gt;
&lt;li&gt;Jag har tid och ork att umgås med min fru och mina barn både före och efter
arbetsdagen. Jobbet stannar oftast på jobbet, så att jag är &lt;strong&gt;hemma både
kroppsligt och mentalt&lt;/strong&gt;. På morgonen är promenaden till skolan med mina barn
en trevlig pratstund istället för ett måste på vägen till jobbet.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Remote först, inte också&lt;/h2&gt;
&lt;p&gt;Jag hör ofta kompisar förklara att det är &lt;em&gt;&amp;quot;skönt att jobba hemifrån&amp;quot;&lt;/em&gt;, att få
komma ifrån kontoret för att få ro att tänka. Samma personer förklarar också att
dagarna hemma helst ska vara mötesfria, eftersom att distansmöten medför
frustration på grund av teknikstrul. Hur ofta är inte en telefon på högtalarläge
lösningen för att få åsikter från personer som inte är i mötesrummet? Att jobba
&lt;strong&gt;remote-first ska ge samma förutsättningar oavsett var&lt;/strong&gt; du än väljer att
(sam)arbeta från.&lt;/p&gt;
&lt;p&gt;Mitt teams (och andra på Nepa också) ständiga förbättringsresa kring remote
lagarbete, till skillnad från att också ha kollegor på distans, handlar mycket
om att &lt;strong&gt;minska upplevda avstånd. Närhet är relativt&lt;/strong&gt;, har jag med tiden lärt
mig. I grund och botten handlar lagarbete om förtroende och att lära av misstag,
inte varifrån personer sammanstrålar. Ett exempel på en förändring som jag
upplever gör skillnad direkt, är att avstå konferensrum för möten eller
workshops. Detta ger &lt;strong&gt;alla samma möjlighet&lt;/strong&gt; att dela med sig av, tillgodose
sig och efterfråga information.&lt;/p&gt;
&lt;p&gt;Som annat i livet som inte är helt bekvämt, så &lt;strong&gt;kräver remote-first träning&lt;/strong&gt;.
Var beredd på att i många situationer krypa igen, innan du lär dig gå. I
synnerhet, glöm inte att du jobbar med människor, trots att de inte är i din
direkta närhet. Gör medvetna val om vilka vanor som funkar för ditt team, och ni
därför ska fortsätta med. Lär dig respektera begränsningarna som remote-first
medför, men omfamna möjligheterna. &lt;strong&gt;När distans inte längre är ett hinder, så
är remote-first lysande&lt;/strong&gt;! I
&lt;a href=&quot;https://jouni.kantola.se/blog/2018-10-31/hellre-overtydlig-an-otydlig/&quot; title=&quot;Underlätta remote-first&quot;&gt;nästa del&lt;/a&gt;
skriver jag mer om att komma igång med remote-first lagarbete.&lt;/p&gt;
&lt;p class=&quot;article__footer&quot;&gt;
  Jag har arbetat inom IT-branschen sedan 2006. De senaste fem åren har jag arbetat i företag där iterativ
  utveckling och snabba releaser är vardag. I dessa organisationer är förbättringsarbete kring samarbete centralt.
  Hur arbetet uppmuntras och går till, ser däremot olika ut. Nu arbetar jag som webbutvecklare för Nepa Sweden AB,
  i ett Remote-First team. Jag berättar gärna mer i detalj om hur vår vardag ser ut och mina erfarenheter av
  distribuerade team och/eller Remote-First.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Arbete ekar i huvudet</title>
    <link href="https://jouni.kantola.se/blog/2018-10-02/arbete-ekar-i-huvudet/"/>
    <updated>2018-10-02T00:00:00.000Z</updated>
    <id>https://jouni.kantola.se/blog/2018-10-02/arbete-ekar-i-huvudet/</id>
    <content type="html">&lt;p&gt;Har du hört ledmotivet till den tecknade serien En cell-sam historia?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Livet, livet, livet livet, se vad livet ger, ger oss av tiden sin egen rytm,
i den värld vi lever, andas lyssnar och ser&amp;quot;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Fundera en stund på vad det stycket betyder för dig. Jämför din känsla med när
du precis har satt dig på tåget, efter morgonens bestyr och lämning av barn, och
får höra att det är ett &lt;strong&gt;signalfel&lt;/strong&gt; som gör att du missar det inbokade
morgonmötet.&lt;/p&gt;
&lt;p&gt;För ungefär ett år sedan började en ny resa för mig, början på slutet av en över
tio år lång resa. En grov överslagsräkning berättar att jag har spenderat nästan
ett kalenderår pendlande till och från jobbet. Under den tiden har jag hunnit
med att byta arbetsgivare fyra gånger, varav lejonparten av tiden som konsult.
Jag har också gift mig och fått fyra barn. Med tiden gick det upp för mig att
jag under vardagarna spenderade &lt;strong&gt;mer tid på resa än med mina barn&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;jag-pendlare&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Jag, pendlare&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2018-10-02/arbete-ekar-i-huvudet/#jag-pendlare&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;En typisk dag för mig som pendlare börjar med att jag stiger upp för trött,
eftersom att &lt;strong&gt;nedvarvningen börjat för sent&lt;/strong&gt; dagen innan. Därefter dags att
slänga i sig frukost under konstant tjat på barnen att mata sig själva. Tjatet
tycks nödvändigt eftersom att de inte har någon tågtid att passa. Däremot
påpekar de mer än gärna hur rörigt det är varenda morgon för att &lt;strong&gt;pappa har så
bråttom&lt;/strong&gt;. Efter att halvsprungit och lämnat på (för)skola så tar jag cykeln för
att nätt och jämnt hinna till tåget. Så här ser det ut nästan varje dag.&lt;/p&gt;
&lt;p&gt;Jag reser med tåg och alltid med brusreducerande hörlurar. När väl pulsen lagt
sig en aning, så tar jag skydd i en värld där övriga pendlare inte kan nå mig.
Jag avskärmar mig så mycket jag kan med datorn uppslagen i knät och med musik i
hörlurarna. Jag upplever resan, i min egen lilla värld, som en av höjdpunkterna
under dagen. Det är min egentid. Vad jag som pendlare inte tycks begripa, är att
det jag egentligen vill åt är &lt;strong&gt;möjligheten att andas ut&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;När jag kommer fram till kontoret så börjar ofta kontorsarbetet med att ta vid
där skärmen slogs igen på tåget. Det är inte ovanligt att jag medvetet har
lämnat en tydlig brytpunkt, som att programmet inte kompilerar eller ett
enhetstest som inte går igenom. Egentligen har alltså &lt;strong&gt;arbetsdagen redan börjat
på tåget&lt;/strong&gt;. Pendlingen är ett utrymme och marginaler för att minska stressen
under resterande arbetsdag på kontoret. Det resulterar också i att en arbetsdag
ofta är längre än åtta timmar.&lt;/p&gt;
&lt;p&gt;Jag använder sällan brusreducerande hörlurar på kontoret, trots att jag upplever
att höga diskussioner påverkar mig kognitivt negativt. Den huvudsakliga
anledningen till att jag inte avskärmar mig är för att jag trivs med att jobba
tillsammans med andra för att förstå och lösa problem. Jag tycker om att kunna
ställa mig &lt;strong&gt;vid en whiteboard tillsammans&lt;/strong&gt; med kollegor för att få en
gemensam, tydlig bild av ett problem och därifrån forma en plan att utgå från.
Priset för att ständigt vara en del av en &lt;strong&gt;obruten ström av information&lt;/strong&gt;, mer
eller mindre frivilligt, är att &lt;strong&gt;arbete ekar i huvudet&lt;/strong&gt; även utanför
arbetstid.&lt;/p&gt;
&lt;p&gt;Efter att ha stressat till tåget, där jag försöker avsluta några
arbetsuppgifter, så kommer jag äntligen hem. Väl hemma upptäcker jag att jag har
missat middagen med familjen och att det snart är dags för läggning av barnen.
Jag &lt;strong&gt;försöker hinna med lite lek&lt;/strong&gt; och bus innan det blir tjafs med barnen om
att äta ordentlig middag istället för ett extra kvällsmål. Därefter är det
läsning av böcker, följt av rännande i och ur sängen. När barnen väl somnar &lt;strong&gt;är
jag helt slut&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;jag-remote&quot;&gt;
  &lt;span class=&quot;heading&quot;&gt;Jag, remote&lt;/span&gt;
  &lt;a class=&quot;direct-link&quot; href=&quot;https://jouni.kantola.se/blog/2018-10-02/arbete-ekar-i-huvudet/#jag-remote&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;När jag började arbeta för min nuvarande arbetsgivare fick jag möjlighet att
jobba på distans från hemort, att &lt;strong&gt;jobba remote&lt;/strong&gt;. Nu efter ett år vill jag
dela med mig av mina erfarenheter och hur jag idag förespråkar att &lt;strong&gt;fördelarna
för arbete remote övertrumfar nackdelarna&lt;/strong&gt;, som välmående och personlig frihet.
I &lt;a href=&quot;https://jouni.kantola.se/blog/2018-10-09/narhet-ar-relativt/&quot; title=&quot;Remote först, inte också&quot;&gt;nästa del&lt;/a&gt;
berättar jag om min upplevelse av att jobba på distans, i synnerhet om
samarbetsformen som kallas &lt;strong&gt;Remote-First&lt;/strong&gt;.&lt;/p&gt;
&lt;p class=&quot;article__footer&quot;&gt;
  Jag har arbetat inom IT-branschen sedan 2006. De senaste fem åren har jag arbetat i företag där iterativ
  utveckling och snabba releaser är vardag. I dessa organisationer är förbättringsarbete kring samarbete centralt.
  Hur arbetet uppmuntras och går till, ser däremot olika ut. Nu arbetar jag som webbutvecklare för Nepa Sweden AB,
  i ett Remote-First team. Jag berättar gärna mer i detalj om hur vår vardag ser ut och mina erfarenheter av
  distribuerade team och/eller Remote-First.
&lt;/p&gt;
</content>
  </entry>
</feed>
