<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: stefnotch</title>
    <description>The latest articles on DEV Community by stefnotch (@stefnotch).</description>
    <link>https://dev.to/stefnotch</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F680778%2Fd7e488fa-3661-48d0-9070-5e8fc618f2a2.png</url>
      <title>DEV Community: stefnotch</title>
      <link>https://dev.to/stefnotch</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stefnotch"/>
    <language>en</language>
    <item>
      <title>Git Clients Are Disappointing</title>
      <dc:creator>stefnotch</dc:creator>
      <pubDate>Thu, 25 Aug 2022 12:17:00 +0000</pubDate>
      <link>https://dev.to/stefnotch/git-clients-are-disappointing-bl9</link>
      <guid>https://dev.to/stefnotch/git-clients-are-disappointing-bl9</guid>
      <description>&lt;p&gt;(Yes, this applies to CLIs and GUIs)&lt;/p&gt;

&lt;p&gt;Well, I'm just going to run you through the options&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The official CLI&lt;/strong&gt;: Quite unintuitive. Also doesn't teach you very much at all about how Git actually works, you usually have to research that yourself. Standard beginner workflow with &lt;code&gt;git add .&lt;/code&gt; is an anti-pattern that you have to un-teach people. (It leads to people not looking at what they're committing before they commit and push it)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Alternate Git CLIs&lt;/strong&gt;: They're proving my point. The official CLI is not something that I'd recommend. However, I don't have enough experience with the alternate CLIs, so I don't have one specific recommendation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Byron/gitoxide"&gt;&lt;strong&gt;gitoxide&lt;/strong&gt;&lt;/a&gt; deserves a mention at thit point, despite very much being a work in progress. It's one of the more interesting Git rewrites out there.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;And now, time for the GUIs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One major requirement is that they use a graph view by default. One that lets you see the commits, and the branches that exist at the moment.&lt;/p&gt;

&lt;p&gt;Mostly everything else is unwieldy for bigger projects, and ends up not mapping quite as nicely to the "make lots of branches" Git workflow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Official Git GUI&lt;/strong&gt;: Technically functional, but somehow manages to be worse, or rather less popular, than the CLI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://desktop.github.com/"&gt;&lt;strong&gt;GitHub Desktop&lt;/strong&gt;&lt;/a&gt;: Fails that requirement, see &lt;a href="https://github.com/desktop/desktop/issues/1634"&gt;this closed issue&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/extrawurst/gitui"&gt;&lt;strong&gt;GitUI&lt;/strong&gt;&lt;/a&gt;: Lovely terminal UI, fails the requirement&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/jesseduffield/lazygit"&gt;&lt;strong&gt;Lazygit&lt;/strong&gt;&lt;/a&gt;: Lovely terminal UI, fails the requirement&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.visualstudio.com/docs/editor/versioncontrol"&gt;&lt;strong&gt;VSCode&lt;/strong&gt;&lt;/a&gt;: Fails the requirement, though there's &lt;a href="https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph"&gt;an extension&lt;/a&gt; that I've not tried out yet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intellij&lt;/strong&gt;: Yay, a decent-ish Git client. Major pain point at the moment is that they're using different terms for a lot of common operations, which leaves you wondering "what does that mean" and once you figure it out, congrats on successfully teaching yourself something that a single vendor uses. (aka vendor lock-in)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://git-fork.com/"&gt;&lt;strong&gt;Git Fork&lt;/strong&gt;&lt;/a&gt;: Quite lovely. One catch is that the name makes it terribly difficult to look up anything at all if you've got a question. Like seriously, try looking up "git fork three way merge".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.gitkraken.com/"&gt;&lt;strong&gt;GitKraken&lt;/strong&gt;&lt;/a&gt;: That's what I use at the moment. Issues include its startup time, its price (subscription model), the fact that it's slow when discarding thousands of changed files at once, ...&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Most 3rd party GUIs out there (&lt;a href="https://git-scm.com/downloads/guis"&gt;kudos to Git for maintaining a lovely list&lt;/a&gt; ) are either quite limited, abandoned, un-fun to use, are expensive paid software, only work on one operating system or have some combination of factors that make it a no-go. I'd know, I've checked out most of them. &lt;em&gt;If there's one that you think deserves a mention, do send it my way!&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, here we go. I think I've successfully complained about every option on the market.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
      <category>git</category>
    </item>
    <item>
      <title>Enabling COOP/COEP without touching the server</title>
      <dc:creator>stefnotch</dc:creator>
      <pubDate>Thu, 05 Aug 2021 18:04:14 +0000</pubDate>
      <link>https://dev.to/stefnotch/enabling-coop-coep-without-touching-the-server-2d3n</link>
      <guid>https://dev.to/stefnotch/enabling-coop-coep-without-touching-the-server-2d3n</guid>
      <description>&lt;p&gt;&lt;strong&gt;Or how to modify security headers clientside.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ever since the rather impressive &lt;a href="https://meltdownattack.com/"&gt;Meltdown and Spectre&lt;/a&gt; attacks, browser vendors had to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements"&gt;clamp down&lt;/a&gt; on shared memory and high resolution timers. While this conveniently means that the casual user doesn't have to work about &lt;a href="https://xkcd.com/1938/"&gt;phantom trolleys&lt;/a&gt;, it can be an irritating restriction for a developer. Some APIs got &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/now"&gt;limited&lt;/a&gt;, while others were completely disabled unless one does a little dance to appease the web browser.&lt;/p&gt;

&lt;p&gt;This means that certain web-applications have an additional hurdle to overcome.&lt;/p&gt;

&lt;p&gt;A few examples of web-applications that have this problem are in-browser video converters using &lt;a href="https://github.com/ffmpegwasm/ffmpeg.wasm"&gt;ffmpeg.wasm&lt;/a&gt;, a web-based &lt;a href="https://github.com/gzuidhof/starboard-notebook"&gt;notebook that supports Python&lt;/a&gt; and &lt;a href="https://emscripten.org/docs/porting/pthreads.html"&gt;multithreaded Emscripten applications&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;The following APIs are unavailable by default&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SharedArrayBuffer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Atomics&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To re-enable them, the site needs to be served over HTTPS&lt;sup&gt;[1]&lt;/sup&gt;  and two headers need to be set. The headers, which have to be set server side&lt;sup&gt;[2]&lt;/sup&gt;, are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Cross-Origin-Opener-Policy: same-origin&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Cross-Origin-Embedder-Policy: require-corp&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can be quite a challenge for a number of reasons. It is not always a walk in the park for a frontend developer to control the headers that the backend sends. Static frontend applications are becoming more widespread. It is quite common that one uses a CDN which simply doesn't support setting custom HTTP headers. I personally needed a solution, as I was deploying &lt;a href="https://stefnotch.github.io/quantum-sheet/"&gt;a web-based computer algebra system&lt;/a&gt; on GitHub pages.&lt;/p&gt;

&lt;p&gt;Finally, do note that those headers impose some additional restrictions. The main one is that the &lt;code&gt;Cross-Origin-Embedder-Policy&lt;/code&gt; header makes it harder to load cross-origin resources. &lt;/p&gt;

&lt;p&gt;[1] Or be on localhost, since the requirement is that the document has to be in a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts"&gt;secure context&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[2] Those headers cannot be set using &lt;code&gt;&amp;lt;meta http-equiv=".."&amp;gt;&lt;/code&gt;, as they're not included in the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#attr-http-equiv"&gt;whitelist&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if I can't set the headers myself?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Service workers to the rescue!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It turns out that there is something that sits between the server serving the webpage and frontend Javascript. Service workers can intercept all requests, modify the responses and even set arbitrary HTTP headers.&lt;/p&gt;

&lt;p&gt;First, we register our service worker in a Javascript file that gets loaded as soon as the website gets loaded. To make sure that the service worker can intercept all requests, we have to reload the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.js&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Register service worker&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./sw.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;COOP/COEP Service Worker registered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// If the registration is active, but it's not controlling the page&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;COOP/COEP Service Worker failed to register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cannot register a service worker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, place the service worker right next to the script above and call it &lt;code&gt;sw.js&lt;/code&gt;. The important part is that every time the &lt;code&gt;fetch&lt;/code&gt; event listener is invoked, we replace the response with one where the COOP/COEP headers are set. All the other parts are optional.&lt;/p&gt;

&lt;p&gt;Do make sure that the service worker gets served from the topmost directory, right where the &lt;code&gt;index.html&lt;/code&gt; of the website is. This makes sure that the service worker's scope includes all the files on your site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// sw.js&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;install&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;skipWaiting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;activate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;claim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;only-if-cached&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;same-origin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// It seems like we only need to set the headers for index.html&lt;/span&gt;
        &lt;span class="c1"&gt;// If you want to be on the safe side, comment this out&lt;/span&gt;
        &lt;span class="c1"&gt;// if (!response.url.includes("index.html")) return response;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newHeaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cross-Origin-Embedder-Policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;require-corp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newHeaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cross-Origin-Opener-Policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;same-origin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moddedResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;moddedResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this ends up doing is&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;when the page gets loaded for the first time, we register the worker&lt;/li&gt;
&lt;li&gt;then we reload the page&lt;/li&gt;
&lt;li&gt;and finally, now that the worker is controlling everything, every request will now have the appropriate headers set&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I can quite recommend using the &lt;a href="https://github.com/gzuidhof/coi-serviceworker"&gt;&lt;code&gt;coi-serviceworker&lt;/code&gt; library&lt;/a&gt;, which is based on this post and does exactly what is needed. &lt;/p&gt;

&lt;p&gt;Of course the ideal solution is still to set the headers server side. &lt;/p&gt;

&lt;h2&gt;
  
  
  Security issue?
&lt;/h2&gt;

&lt;p&gt;No, I doubt that. There is a &lt;a href="https://w3c-test.org/html/cross-origin-opener-policy/popup-coop-by-sw.https.html"&gt;w3c test&lt;/a&gt; for this. It's a way of opting in into additional security restrictions on your website.&lt;/p&gt;

&lt;p&gt;Opting out with the same approach does not work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Once you add the COEP header, you won't be able to bypass the  restriction by using service workers. If the document is protected by a  COEP header, the policy is respected before the response enters the  document process, or before it enters the service worker that is  controlling the document.&lt;/p&gt;

&lt;p&gt;-- &lt;a href="https://web.dev/why-coop-coep/"&gt;https://web.dev/why-coop-coep/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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