FormData object is empty when script type is set to module

I came across some weird edge case and I narrowed it down to a solution. I created a form with vue and I thought that vue was causing this weird behavior but it was the fact that the script had a type="module" attribute.

When I moved the script into it’s own file and added a defer attribute then everything worked fine. My question is why. I know there are differences with type module and a normal script tag with a defer attribute but I’m not clear on why the FormData object is empty when using an inline script with type module.

NOTE: I know about the form data object and how to view it with

for (const [key, value] of formData.entries()) {
  console.log(`${key}: ${value})
}

The below code was sending empty string to my backend express server. I noted that on the frontend the testSubmit function was showing no value from the console.log.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Home</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <script src="https://unpkg.com/[email protected]/dist/vue.global.js" defer></script>
  </head>
  <body>
    <h1>app</h1>
    <div id="app-main">
      <form @submit="testSubmit($event)" id="test-form">
        <input type="text" name="foo">
        <button type="submit">submit</button>
      </form>
    </div>

    <!-- <script src="./index.js" defer></script> -->
    <script type="module">
      const form = document.querySelector('#test-form')
      
      const app = Vue.createApp({
      name: 'test app',
      data() {
        return {
          foo: 'foo'
        }
      },
      methods: {
        testSubmit(e) {
          e.preventDefault()

          /** nothing was logged here
          * and empty strings were showing up on the server
          */
          const formData = new FormData(form)
          for (const [key, value] of formData.entries()) {
            console.log(`${key}: ${value}`)
          }

          fetch('/form', {
            method: 'POST',
            body: new FormData(form)
          })
        }
      }
    }).mount('#app-main')
    </script>
  </body>
</html>

If I change the code to this

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Home</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <script src="https://unpkg.com/[email protected]/dist/vue.global.js" defer></script>
  </head>
  <body>
    <h1>app</h1>
    <div id="app-main">
      <form @submit="testSubmit($event)" id="test-form">
        <input type="text" name="foo">
        <button type="submit">submit</button>
      </form>
    </div>

    <!-- Now everything works and the FormData object contains values
         The values are also showing up on the server end
    -->
    <script src="./index.js" defer></script>
  </body>
</html>