next.js icon indicating copy to clipboard operation
next.js copied to clipboard

appDir + async server component + css-modules causes syntax error

Open mxmul opened this issue 3 years ago • 6 comments

Verify canary release

  • [X] I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 22.1.0: Sun Oct  9 20:14:30 PDT 2022; root:xnu-8792.41.9~2/RELEASE_ARM64_T8103
Binaries:
  Node: 18.11.0
  npm: 8.19.2
  Yarn: 1.22.10
  pnpm: N/A
Relevant packages:
  next: 13.0.2
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0

What browser are you using? (if relevant)

Chrome, Safari

How are you deploying your application? (if relevant)

next dev

Describe the Bug

When using the experimental /app mode with the following setup, RSC seems to stream in a malformed script tag, causing a crash:

  • Uses /app directory
  • Root page has both a layout.tsx and a loading.tsx
  • page.tsx exports an async server component
  • page.tsx uses a class name from a CSS module, styles.module.css
Screenshot 2022-11-03 at 10 14 23 PM Screenshot 2022-11-03 at 10 11 36 PM

Unexpected string literal ",". Parse error.

See minimal repro in code here: https://github.com/mxmul/next13-async-component-css-modules-repro/commit/c562d4dcf3745c365eae6f9515e8680980245d79

Expected Behavior

Page should render the loading state immediately, then the loaded content.

e.g. Screenshot 2022-11-03 at 10 14 44 PM

Link to reproduction

https://github.com/mxmul/next13-async-component-css-modules-repro

To Reproduce

Clone the repo, and run yarn dev.

The first time you load the page, it seems to render properly. You see a loading state, then the rendered page:

Screenshot 2022-11-03 at 10 14 44 PM

After refreshing the page, you should see next crash with a syntax error:

Screenshot 2022-11-03 at 10 14 23 PM

mxmul avatar Nov 04 '22 02:11 mxmul

I do not seem to be able to reproduce this. Can you try next@canary? Can you see any more information in the terminal?

After refreshing the page

Is this a hard refresh (eg. F5) or hot reload (eg. editing and saving a file, in that case which one?)

balazsorban44 avatar Nov 06 '22 01:11 balazsorban44

It still reproduces with next@canary. No errors or warnings in the terminal. By "refresh", I mean a Cmd+R.

Something I just discovered is that it reproduces in Node.js 18 but not Node.js 17

mxmul avatar Nov 06 '22 01:11 mxmul

I see this breaking change in the Node.js 18 release notes. I wonder if it could be related?:

(SEMVER-MAJOR) stream: remove thenable support (Robert Nagy) #40773

mxmul avatar Nov 06 '22 17:11 mxmul

Getting this same error Node v18.7.0, [email protected].

chrisco512 avatar Nov 07 '22 07:11 chrisco512

Ok I investigated a bit, so I can confirm that this happens with Node 18 and not Node 16.

It does not reproduce on the first hit to the page but on all of them afterwards (refresh or not). What causes the error is that on subsequent page loads, we seem to miss a part of the script payload.

what we are suppose to inject

    <script>
      $RC = function (b, c, e) {
        c = document.getElementById(c)
        c.parentNode.removeChild(c)
        var a = document.getElementById(b)
        if (a) {
          b = a.previousSibling
          if (e) (b.data = '$!'), a.setAttribute('data-dgst', e)
          else {
            e = b.parentNode
            a = b.nextSibling
            var f = 0
            do {
              if (a && 8 === a.nodeType) {
                var d = a.data
                if ('/$' === d)
                  if (0 === f) break
                  else f--
                else ('$' !== d && '$?' !== d && '$!' !== d) || f++
              }
              d = a.nextSibling
              e.removeChild(a)
              a = d
            } while (a)
            for (; c.firstChild; ) e.insertBefore(c.firstChild, a)
            b.data = '$'
          }
          b._reactRetry && b._reactRetry()
        }
      }
      $RM = new Map()
      $RR = function (p, q, v) {
        function r(l) {
          this.s = l
        }
        for (
          var t = $RC,
            u = $RM,
            m = new Map(),
            n = document,
            g,
            e,
            f = n.querySelectorAll(
              'link[data-precedence],style[data-precedence]'
            ),
            d = 0;
          (e = f[d++]);

        )
          m.set(e.dataset.precedence, (g = e))
        e = 0
        f = []
        for (var c, h, b, a; (c = v[e++]); ) {
          var k = 0
          h = c[k++]
          if ((b = u.get(h))) 'l' !== b.s && f.push(b)
          else {
            a = n.createElement('link')
            a.href = h
            a.rel = 'stylesheet'
            for (a.dataset.precedence = d = c[k++]; (b = c[k++]); )
              a.setAttribute(b, c[k++])
            b = a._p = new Promise(function (l, w) {
              a.onload = l
              a.onerror = w
            })
            b.then(r.bind(b, 'l'), r.bind(b, 'e'))
            u.set(h, b)
            f.push(b)
            c = m.get(d) || g
            c === g && (g = a)
            m.set(d, a)
            c
              ? c.parentNode.insertBefore(a, c.nextSibling)
              : ((d = n.head), d.insertBefore(a, d.firstChild))
          }
        }
        Promise.all(f).then(
          t.bind(null, p, q, ''),
          t.bind(null, p, q, 'Resource failed to load')
        )
      }
      $RR('B:0', 'S:0', [
        [
          '/_next/static/css/app_styles_module_css.css?ts=1667831282087',
          'high',
        ],
      ])
    </script>

what we end up receiving, hence the unexpected string

 <script>
    B:0","S:0",[["/_next/static/css/app_styles_module_css.css?ts=1667830880867","high"]])
  </script>

we seem to be missing some part of the payload🤔

Will investigate further.

https://github.com/vercel/next.js/blob/70e7e58c379a68ac3b73628bae8abb6cf54aacb1/packages/next/compiled/react-dom/cjs/react-dom-server.browser.development.js#L4630

this particular buffer seems to get cleared out at some point, which causes the error

feedthejim avatar Nov 07 '22 14:11 feedthejim

Found the bug, let's hope I can get https://github.com/facebook/react/pull/25645 merged fast!

feedthejim avatar Nov 07 '22 18:11 feedthejim

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

github-actions[bot] avatar Dec 24 '22 00:12 github-actions[bot]