Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Template refs to non-Ref class instances error in production builds, but not during development #12029

Open
Vanilagy opened this issue Sep 25, 2024 · 5 comments · May be fixed by #12051
Open
Labels
🐞 bug Something isn't working 🔩 p2-edge-case

Comments

@Vanilagy
Copy link

Vanilagy commented Sep 25, 2024

Vue version

3.5.8

Link to minimal reproduction

https://play.vuejs.org/#__PROD__eNp9UsFq4zAQ/ZVZXZJCcA7dwBLSQroEtntolm5gL4JFlceJWlkSGtlOCPn3HdlpmsNSX6x574385o2PYhlC0TYo5mJBOpqQgDA14V666RQ2O0OgfYlQeiRwPu2M24JxUGILL42xJU34naBSxlImQvTlmZlLp60igiUcT3z2jhIEuAOHHSzHN9L1H/mzUwmUJQ8Yo4+5jdGsK71uanSp0BFVwpXFXI1HYcS9Z01nXOm7vnw4QJfvegStHI+BbE2R0craAyh3GMynLOGxWGLYkHIawVegYPCqXAlP6w3Xz1gV1xZzBG6UBpcfJmeX0xHUHGbAo56BiNX4BvLDwPqlNb4htsI+CDof3+iLdIvpEDsHzkXCOlgelSuARcg33EkRpLj/gdb6xTQvZjG9komJSMTRVmZbvJJ3vMhjbpZC+zoYi3EdkuHopZhDz2SOI/Hdzx5LscHJO653qN/+g7/SPmNS/IpIGFuU4sIlFbeYBnr1+wn3fL6QtS8by+pPyGckb5vscZA9NK5k21e63u1jHXxMvMENrfYJHb0PlY1m5anXS8F/8/dPRv+we1t87fukO3GKf1uM+U4O8LaYFd/E6R/KqQUI

Steps to reproduce

Run the reproduction, it explains the issue with comments:

<script setup>
// This code does nothing in dev builds, but fails in prod builds:
class A {}
const p = new A()

// What also errors:
// p = document.createElement('p')
// p = window
// By what I can see, basically anything that is an instance of a class and NOT a Ref.

// What doesn't error:
// p = 5
// p = { a: 5 }
// p = ref()     // Obviously this works!
</script>

<template>
  <p ref="p">Hello</p>
</template>

The code works fine in dev mode, but breaks in prod builds.

In this case, the component renders successfully in both cases (albeit with the error in prod); however, in actual projects of mine this has typically nuked the entire page.

What is expected?

Template refs pointing to something other than an actual vue Ref is not intentional code. This kind of code has happened in my projects a few times due to oversight; basically due to coding errors. The problem here is that the error is silent during development - the ref might be wrong, but it does not nuke the component and just fails silently. So you never fix it.

Consistency is expected here. I argue that this should fail also in dev, albeit with a nicer error message. It should point out that you have an element that's template ref'd to an object that doesn't make sense.

Alternatively, it should ignore the issue silently in production builds, just like it does in dev now.

What is actually happening?

In dev, the issue is ignored silently and with no repercussions, but in prod it fails loud.

System Info

System:
    OS: macOS 14.6.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 116.27 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.19.0 - /opt/homebrew/opt/node@18/bin/node
    Yarn: 1.22.22 - /opt/homebrew/opt/node@18/bin/yarn
    npm: 10.2.3 - /opt/homebrew/opt/node@18/bin/npm
    pnpm: 8.6.11 - ~/.local/share/pnpm/pnpm
    bun: 1.1.4 - ~/.bun/bin/bun
  Browsers:
    Chrome: 129.0.6668.59
    Safari: 17.6

Any additional comments?

No response

@edison1105
Copy link
Member

duplicate of #11373

@edison1105 edison1105 closed this as not planned Won't fix, can't repro, duplicate, stale Sep 25, 2024
@Vanilagy
Copy link
Author

@edison1105 Are you sure this is a duplicate? I've looked through #11373, and also through #4866 (linked there), and both of these issues reference situations that use dynamically assigned template refs, i.e. code that uses :ref="x".

This is NOT what is going on here in my issue. I have a hardcoded reference to p in my code; perfectly statically analyzable. This issue has (at least by what I can tell) nothing to do with the "design flaw" Evan is referring to in the other two issues.

This issue is similar to the other two in the sense that it concerns template refs and dev/prod build differences, however the bug itself feels different. Maybe I'm wrong here and they are related; could you elaborate how this issue and the other two are caused by the same defect?

@Vanilagy
Copy link
Author

Vanilagy commented Sep 25, 2024

This here seems to be the code causing the divergence: (EDIT: It's not?)
CleanShot 2024-09-25 at 14 22 11

I think it's destructuring owner from the rawRef here, which in my case (new A()) is obviously undefined. Thankfully in non-prod, the code catches this returns out of the function. However, in prod it continues and then runs into an error.

Is there a reason why it continues in production? Is there any scenario in which !owner is true and the code that follows it is still well-behaved?

Perhaps this is the intended code:

  if (!owner) {
    if (process.env.NODE_ENV !== "production") {
      warn$1(
        `Missing ref owner context. ref cannot be used on hoisted vnodes. A vnode with ref must be created inside the render function.`
      );
    }
    return;
  }

@edison1105
Copy link
Member

edison1105 commented Sep 25, 2024

You can switch between DEV and PROD to inspect the compiled code.
image

At runtime

Developers should follow the documentation

  • declare a ref to hold the element reference
  • useTemplateRef

@yyx990803
Copy link
Member

Looked at #12031 and I think the correct change should be detecting such usage during development (when setting the template ref, if the key exists on setupState but is not a ref) and emit a warning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐞 bug Something isn't working 🔩 p2-edge-case
Projects
None yet
3 participants