core icon indicating copy to clipboard operation
core copied to clipboard

`v-bind` not working with `computed` properties in SSR

Open brc-dd opened this issue 3 years ago • 4 comments

Vue version

8edf4b3

Link to minimal reproduction

https://sfc.vuejs.org/#__SSR__eNp9kM1uhDAMhF/FyoVFWsgdAVJfoedcWOJtWZEf2YGqQrx7HaiqVSv1lhl7PnmyqZcY63VB1aiWR5piAsa0xN74ycVACTYYg4tLQgs73Ck4KGS/MN74MXhOMp4DQfezdrmU0PVQENqiNL7VJ1eIIhK6OA8JRQG0dlphnAfmzih5G3XYAK9oj7kWU6xWP8VEcvqcEXgMEa04dcZsOXCc0sBa3SZvL4cqM8/4/Tgk53p1VWe1yg2xfnDwUv6Im+8BG9WcwOxJ26yNek8pcqM138f8ZQ+uA71pedW0+DQ5rJFddaPwwUgCNur6xNBirkgVobdISP8xf63+4WasNNrV/gWkXprz

Steps to reproduce

Open link, make sure its on PROD with SSR ON. Near line 20 in SSR tab we have an _unref call. But it isn't imported first.

What is expected?

For build to succeed. (_unref to be imported from vue prior to its call.)

What is actually happening?

ReferenceError: _unref is not defined

System Info

No response

Any additional comments?

https://github.com/vuejs/vitepress/issues/876, https://github.com/nuxt/framework/issues/5546

@skirtles-code observed that it's not just computed, anything deemed setup-maybe-ref will fall into the same problem:

https://sfc.vuejs.org/#__SSR__eNp9UE1rhTAQ/CtLLio8zV1U6F/oqYdcfLq2PjQJu9FSxP/eTezh0UIPgczszOzHoV68r/YNVa0aHmj2ARjD5jtj59U7CnAA4QQnTORWyESaGWvs4CwH2BjfoIW8gLaLsjwjHLMCwNj4LtHgFkeiiuK8MLbRVyNpISDg6pc+oCCAZpx3GJaeuTVK/kYlGuAVx1TXQgrV6CebQA5fCwIPzuMoTBVjjmhIvWvYy/tsxzwhmS7OdqZBoq9TN3XtWq69rx7srFwj2c1PgY2qr8DIyQ0iNuojBM+11jwN8YYPrhy9a/lVtNkwr1ghr+Wd3CcjSbBRt6cMLeSOVBLaEQnpv8xf0j+5MVY2OtX5DXtJnx4=

brc-dd avatar Jun 29 '22 13:06 brc-dd

weirdly, as in the JS tab of the playground, _unref seems to be imported ...

LinusBorg avatar Jun 29 '22 13:06 LinusBorg

@LinusBorg Yeah, it is in the JS tab, but not in the SSR tab.

skirtles-code avatar Jun 29 '22 14:06 skirtles-code

🤦🏻‍♂️thanks

LinusBorg avatar Jun 29 '22 15:06 LinusBorg

I have been experiencing a similar issue on v3.2.37. I am using vite & vite-ssr. The issue seems a bit different for me however.

I have a component that looks like this
<script lang="ts">
import { provideTheme } from '@social/client/themes'
import globalTheme from '@social/client/themes/global'
import { defineComponent } from 'vue'

export default defineComponent({
	name: 'NoLayoutLayout',
})
</script>

<script lang="ts" setup>
const theme = provideTheme(globalTheme)
</script>

<template>
	<RouterView class="no-layout" />
</template>

<style lang="scss" scoped>
.no-layout {
	background-color: v-bind('theme.color.secondary');
	color: v-bind('theme.color.secondaryText');

	font-family: v-bind('theme.font.body');
	font-weight: v-bind('theme.font.bodyWeight');
}

:deep(h1, h2, h3, h4, h5, h6) {
	padding: 0.5em 0px;
	margin: 0px;
	color: v-bind('theme.color.secondaryText');
	font-family: v-bind('theme.font.header');
	font-weight: v-bind('theme.font.headerWeight');
}

:deep(img) {
	max-width: 100%;
	max-height: 100%;
	object-fit: cover;
}

:deep(a) {
	color: inherit;
}
</style>

During dev, works just fine. Once built and running in prod, we get the _unref is not defined error.

If I import `computed` and actually use it like this
<script lang="ts">
import { provideTheme } from '@social/client/themes'
import globalTheme from '@social/client/themes/global'
import { defineComponent, computed } from 'vue'

export default defineComponent({
	name: 'NoLayoutLayout',
})
</script>

<script lang="ts" setup>
const test = computed(() => false)
const theme = provideTheme(globalTheme)
</script>

<template>
        <div v-if="test">test</div>
	<RouterView class="no-layout" />
</template>

<style lang="scss" scoped>
.no-layout {
	background-color: v-bind('theme.color.secondary');
	color: v-bind('theme.color.secondaryText');

	font-family: v-bind('theme.font.body');
	font-weight: v-bind('theme.font.bodyWeight');
}

:deep(h1, h2, h3, h4, h5, h6) {
	padding: 0.5em 0px;
	margin: 0px;
	color: v-bind('theme.color.secondaryText');
	font-family: v-bind('theme.font.header');
	font-weight: v-bind('theme.font.headerWeight');
}

:deep(img) {
	max-width: 100%;
	max-height: 100%;
	object-fit: cover;
}

:deep(a) {
	color: inherit;
}
</style>

Then once built, the previously _unrefs are transformed into vue.unref, which is correct and makes the app work again.

Now, this is the first time really diving into the vue core, so I might have been looking at the wrong thing, but I did some digging and found a couple things.

  1. bug was introduced after 3.2.26
  2. it only happens for me when I don't import computed and use it.
  3. logging ast before and after this transform call to check what the difference is, I found that the UNREF symbol was missing from the helpers property when I did not import computed
  4. Looking even further I found the UNREF helper symbol was being added when computed was imported during this traverseNode call.

This is as far as I got for my case. I look into the traverseNode code, but couldn't find anything glaring at me that could be causing it. It does loop thru the transformNodes tho, so I am going to assume something is going wrong within those calls.

Looking at the possible transformers being run, the only one that caught my eye was ssrInjectCssVars, but again I am not currently seeing anything glaring at me that could be wrong.

MichealPearce avatar Aug 01 '22 16:08 MichealPearce

PR for the fix: https://github.com/vuejs/core/pull/6489

antfu avatar Aug 29 '22 00:08 antfu