Local variables references in dev script setup don't work
Link to minimal reproduction
Steps to reproduce
In dev mode, try to use a local variable that is not a reference, i.e. a plain value, not an object, nor array nor ref, directly from a script setup template.
The linked repro is a repro, but not inside the SFC playground because it compiles to non-dev!
The repro has two buttons that increment a local variable, and one to show its value in an alert box. Buttons that go through functions with a capture inside setup function work. Button that manipulate the variable directly don't.
What is expected?
In build mode, which is what SFC playground runs, clicking Inc buttons increment the value by 1, as can be visualised with the third button.
What is actually happening?
In dev mode, the non-working button (the one without a local function that captures the x
variable, does not increment the value.
Neither would it read the correct value if that was a case.
The reason is that in dev mode, for the dev tools, a regular script setup object is built like so:
const __returned__ = { props, emit, x };
Of course, this just puts a copy of the current value of local variable in the setup object.
Any reference to this x
value in template is totally disconnected from the variable in code.
To clarify why this works in build mode, this is because the SFC compiler doesn't use a setup object at all but rather creates a render function that immediately closes over the local variables, like so:
let x = 0;
return (_ctx, _cache) => {
return (_openBlock(), _createElementBlock("div", null, [
_createElementVNode("button", {
onClick: _cache[0] || (_cache[0] = $event => (_isRef(x) ? x.value++ : x++))
}, "Inc (does not work)"),
]))
System Info
System:
OS: Windows 10 10.0.19042
CPU: (12) x64 Intel(R) Core(TM) i7-9850H CPU @ 2.60GHz
Memory: 4.68 GB / 15.79 GB
Binaries:
Node: 16.6.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.10 - ~\AppData\Roaming\npm\yarn.CMD
npm: 7.19.1 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Spartan (44.19041.1266.0), Chromium (101.0.1210.39), ChromiumDev (103.0.1253.0)
Internet Explorer: 11.0.19041.1566
npmPackages:
vue: ^3.2.33 => 3.2.33
Any additional comments?
This might be a bit ugly to fix, I see two solutions:
The dev-mode setup object should contain get/set properties that actually proxy local variables that are
let
notconst
.User JS code is rewritten so that all returned
let
local variables live on the__returned__
object from the start, and all setup code referencing these variables is rewritten to dereference that object. That requires modifying the user code so it's quite more tricky than option 1.