Subscribe on changes!

Setting custom directive to empty string causes syntax error in generated code

avatar
Jul 17th 2022

Vue version

3.2.37

Link to minimal reproduction

https://sfc.vuejs.org/#eNp9kLFuwzAMRH+F1eIWqC10NRwD3foHXbS4Dp04sERBpN3B0L+XcooOHbLpeKcnHXfzHmOzrWha0/GY5ijAKGvsXZh9pCSwQ8IJMkyJPFQarVxwYaTAAp4vcCr+c/WBy0LwSWk5P1UvLnT2jlOQCkEfl0FQFUB3fev3/bicc2dVHVOOQ4CtHlcW8vV5TjjKvOHJGWd6xan9MNhORP/Cnf172Lyae6HaD7G5MQWtvBee+zXYmRaOSZlp0aKduYpEbq3laSyLunFD6WL11KQ1yOyxQfb1V6JvxqRg/YEisgvZ5B9G9njt

Steps to reproduce

Use a custom directive in your template with an empty string as the value, e.g. <span v-custom-directive=""> or <span v-custom-directive:foo="">

What is expected?

The custom directive handler is invoked. I don't know what binding.value should be, probably some bottom value like '' or undefined or null.

What is actually happening?

When using client-side template interpretation, the custom directive handler is invoked with binding.value = undefined;, which is fine.

However, when server-side template compilation is used, the JS code that is generated for this template has a syntax error. For v-custom-directive="" the generated code looks like this: (note trailing comma in array, which is invalid)

    _withDirectives(_createElementVNode("span", null, null, 512 /* NEED_PATCH */), [
      [_directive_custom_directive, ]
    ]),

For v-custom-directive:foo="" it looks like this: (note double comma in array, which is invalid)

    _withDirectives(_createElementVNode("span", null, null, 512 /* NEED_PATCH */), [
      [_directive_custom_directive, , "foo"]
    ])

Something similar happens in SSR mode:

// v-custom-directive="" generates:
_ssrRenderAttrs(_ssrGetDirectiveProps(_ctx, _directive_custom_directive, ))

// v-custom-directive:foo="" generates:
_ssrRenderAttrs(_ssrGetDirectiveProps(_ctx, _directive_custom_directive, , "foo"))

This then results in the entire app crashing, because Vue attempts to execute the generated code, which fails with a syntax error.

System Info

System:
    OS: Linux 5.4 Ubuntu 20.04.4 LTS (Focal Fossa)
    CPU: (8) x64 Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
    Memory: 189.98 MB / 15.39 GB
    Container: Yes
    Shell: 5.0.17 - /bin/bash
  Binaries:
    Node: 16.9.1 - ~/.nvm/versions/node/v16.9.1/bin/node
    Yarn: 1.22.11 - ~/.nvm/versions/node/v16.9.1/bin/yarn
    npm: 8.5.3 - ~/.nvm/versions/node/v16.9.1/bin/npm
  Browsers:
    Chrome: 103.0.5060.114
    Chromium: 102.0.5005.115
    Firefox: 102.0
  npmPackages:
    vue: ^3.2.37 => 3.2.37

Any additional comments?

No response

avatar
Jul 17th 2022

From a quick first look: Both of these Syntax "errors" in arrays are valid Javascript.

Its just that the implentation expects a expression in the directive value and doesnt account for an empty one - much like Vue's own directives dont like empty values.

The SSR ones need a fix though.

avatar
Jul 18th 2022

Yes, you're right, I didn't realize that double/trailing commas are allowed in arrays, but they are. They're not allowed in function calls though, which is why the SSR ones are broken as you say (and SSR is where I ran into this bug)

avatar
Jul 18th 2022

It's still a kind of edge case., or rather, the workaround is simple:

if you don't need a value, skip the =""

That's likely why i hasn't come up before - people don't write custom directive like that often.