Issues with CSP on a Next.js Exported Extension

Hi

I am currently building an extension using Next.js, where I am using the export feature to export as HTML, JS and CSS. I have managed to get it to the point where my extension renders the CSS and images correctly however the JavaScript is failing to load.

When I investigate using the browser dev tools I have spotted

Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy.

which looks like the likely culprit, here is my sample HTML that is trying to load the JavaScript files, it appears to be trying to load the files correctly from the relative path

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="preload" as="image" href="./nib.png" />
    <link rel="preload" as="image" href="./bit.png" />
    <link
      rel="stylesheet"
      href="./_next/static/css/be13a162851989e9.css"
      crossorigin=""
      data-precedence="next"
    />
    <link
      rel="stylesheet"
      href="./_next/static/css/ab5189d8a6da231d.css"
      crossorigin=""
      data-precedence="next"
    />
    <link
      rel="preload"
      as="script"
      fetchPriority="low"
      href="./_next/static/chunks/webpack-4d6cbf53789c5a22.js"
      crossorigin=""
    />
    <script
      src="./_next/static/chunks/fd9d1056-b78abccdcf7e09a8.js"
      async=""
      crossorigin=""
    ></script>
    <script
      src="./_next/static/chunks/938-57e9749fe7baaed3.js"
      async=""
      crossorigin=""
    ></script>
    <script
      src="./_next/static/chunks/main-app-20c797ddb2dc8be3.js"
      async=""
      crossorigin=""
    ></script>
    <script
      src="./_next/static/chunks/app/panel/page-23318e298438fdda.js"
      async=""
    ></script>
    <title>MooseyNibs</title>
    <meta name="description" content="MooseyNibs Twitch Extension" />
    <link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="16x16" />
    <script src="https://extension-files.twitch.tv/helper/v1/twitch-ext.min.js"></script>
    <script
      src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"
      crossorigin=""
      nomodule=""
    ></script>
  </head>
  <body>
    <main>
      <div>
        <h2
          class="border-b-2 border-violet-800 mb-2 text-center py-2 bg-violet-700"
        >
          Hello World
        </h2>
      </div>
    </main>
    <script
      src="./_next/static/chunks/webpack-4d6cbf53789c5a22.js"
      crossorigin=""
      async=""
    ></script>
    <script>
      (self.__next_f = self.__next_f || []).push([0]);
      self.__next_f.push([2, null]);
    </script>
    <script>
      self.__next_f.push([
        1,
        '1:HL["./_next/static/css/be13a162851989e9.css","style",{"crossOrigin":""}]\n0:"$L2"\n',
      ]);
    </script>
    <script>
      self.__next_f.push([
        1,
        '3:HL["./_next/static/css/ab5189d8a6da231d.css","style",{"crossOrigin":""}]\n',
      ]);
    </script>
    <script>
      self.__next_f.push([
        1,
        '4:I[7690,[],""]\n6:I[7831,[],""]\n7:I[7740,["790","static/chunks/app/panel/page-23318e298438fdda.js"],""]\n8:I[5613,[],""]\n9:I[1778,[],""]\nb:I[8955,[],""]\n',
      ]);
    </script>
    <script>
      self.__next_f.push([
        1,
        '2:[[["$","link","0",{"rel":"stylesheet","href":"./_next/static/css/be13a162851989e9.css","precedence":"next","crossOrigin":""}]],["$","$L4",null,{"buildId":"EmwqK0FT5P0AGCk6IPOmS","assetPrefix":".","initialCanonicalUrl":"/panel","initialTree":["",{"children":["panel",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],"initialSeedData":["",{"children":["panel",{"children":["__PAGE__",{},["$L5",["$","$L6",null,{"propsForComponent":{"params":{}},"Component":"$7","isStaticGeneration":true}],null]]},[null,["$","html",null,{"lang":"en","children":[["$","head",null,{"children":["$","script",null,{"src":"https://extension-files.twitch.tv/helper/v1/twitch-ext.min.js"}]}],["$","body",null,{"children":["$","$L8",null,{"parallelRouterKey":"children","segmentPath":["children","panel","children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L9",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined","styles":null}]}]]}],null]]},[null,["$","$L8",null,{"parallelRouterKey":"children","segmentPath":["children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L9",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\\"Segoe UI\\",Roboto,Helvetica,Arial,sans-serif,\\"Apple Color Emoji\\",\\"Segoe UI Emoji\\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[],"styles":[["$","link","0",{"rel":"stylesheet","href":"./_next/static/css/ab5189d8a6da231d.css","precedence":"next","crossOrigin":""}]]}],null]],"initialHead":[false,"$La"],"globalErrorComponent":"$b"}]]\n',
      ]);
    </script>
    <script>
      self.__next_f.push([
        1,
        'a:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"MooseyNibs"}],["$","meta","3",{"name":"description","content":"MooseyNibs Twitch Extension"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"16x16"}]]\n5:null\n',
      ]);
    </script>
    <script>
      self.__next_f.push([1, ""]);
    </script>
  </body>
</html>

image

You can’t use inline JS