Vue 2.0 server-side-render with template inside #app container - vue.js

Server side rendering page for reference: ssr.html
Now the problem, what if we want to define template inside the <div id="app"></div> in html file itself, not in Vue instance template property? Like this:
<div id="app">You have been here for {{ counter }} seconds.</div>
In this case if we want to pre-render it, we will get next pre-rendered html:
<div id="app" server-rendered="true">You have been here for 0 seconds&period;</div>
And here is the conflict problem. If we will output pre-rendered html, we lose our template and Vue doesn't know where to output counter inside our <div id="app">.
Is it possible somehow to provide template inside <div id="app"></div> container and in the same time pre-render it? Or provide template near the pre-rendered in html(so Vue will know that here is pre-rendered and here is template and i will use it if any changes happens in the model)?

Is it possible somehow to provide template inside container and in the same time pre-render it? Or
Short but complete answer: No. For Vue SSR, you cannot use in-DOM templates. You have to use string-based templates (including Single File Components).

Related

Adding Vue only to some parts of an existing application

I see that html files in examples with Vue consist only of one root "div" element with "app" id and actually no more elements in the file. HTML elements inside are rendered as templates in js (or vue) files. And it is fine for SPA.
However, I have a multi-page application which is rendered and routed in backend (PHP) and I don't want to change it. But I would like to use Vue for some reactive elements only (e.g wizard) in the application keeping the other pages and routing as they are.
What is the best practice for it?
A) Creating a new Vue instance for every element I need. So it would be look like:
<body>
<header></header>
<div>
... other html elements ...
<div id="vue_wizard>
<div>
Could I place the html elements for the wizard here or should I render them in VUE JS files?
</div>
</div>
... other html elements ...
</div>
<footer></footer>
</body>
B) Actually I don't have any other idea for it.

v-if breaks nuxt ssr

If I use fetched data (fetchPolicy: 'cache-and-network') from apollo in v-if, it will throw
vue.runtime.esm.js:619 [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
<template>
<div
<div v-if="test">
{{ test }}
</div>
</div>
</template>
but if I use it just as variable to render it works fine.
<template>
<div>
{{ test }}
</div>
</template>
The data in real usage is object, that I need to conditionaly render and pass to another components with v-if.
I have tried geting the data trough get, doing watch over the data and seting them manually, but eventually everything broke.
regarding comment:
if I console the test data it will go -> true on server -> false on client and then true on the client again, if I remove the test from v-if it goes: true on server and true on client
this has nothing to do with structure, in real project it has bunch of components and it works just fine if the data isnt used in condition
For anyone facing the same problem, I have fixed it by setting cache-and-network after the mount and all works just fine.
mounted() {
this.$apollo.queries.getCampaign.setOptions({
fetchPolicy: 'cache-and-network',
})
}
You are trying to make the root element of a component conditionnally disappear, which creates an inconsistency in the virtual DOM.
Can you try:
<template>
<div>
<template v-if="test">
{{ test }}
</template>
</div>
</template>
from my experience, nuxt will failed in SSR if you are using v-if unless you wrap in <no-ssr> or <client-only>
SSR is sometimes difficult to debug and such problems occure quite often.
https://ssr.vuejs.org/#why-ssr
some external libraries may need special treatment to be able to run
in a server-rendered app.
This may be the point. Some vue-components cannot be run via SSR out of the box. This is why I asked about the content from the server.
So the easiest fix could be to wrap your component with the <no-ssr> tag. You can do this for each component separatly to find out which one causes the problem.
Once you have isolated the component you can keep the <no-ssr> tag on it and migrate it's functions to the mounted area of your client component.
If it is a small component you can also use v-show instead.

Run TYPO3 Fluid on VueJS component

I have a VueJS component and I'm trying to add translated text via Fluid tag.
<div xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers">
<h2><f:translate key="search.resultPage"/>"{{mutatedQuery}}".</h2>
</div>
The tags are displayed on frontend, but the <f:translate> tag is empty.
Assumed direction Fluid → Vue
Indeed that's tricky since Fluid does not support escape characters for inference literals like {} which are used in any other client-side frameworks like Vue or Angular as well.
case
Fluid template
rendered output
1
{{item.value}}
ø
2
{{ item.value }}
{{ item.value }}
3
{{<f:comment/>item.value<f:comment/>}}
{{item.value}}
1: empty string (we knew that already)
2: works, adding space between braces and variable name
3: works, since <f:comment/> breaks Fluid inline pattern (but it's "ugly")
Assumed Direction Vue → Fluid
It is not possible to call Fluid (server-side rendering) from Vue (client-side template & document fragment).
Alternative, combining both via slots
It is possible to use Fluid in the base template served by a web server and use slots to inject the content to Vue components, see https://v2.vuejs.org/v2/guide/components-slots.html.
Main Fluid template:
<div
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers">
<my-app>
<template v-slot:resultPageLabel>
<f:translate key="search.resultPage"/>
</template>
</my-app>
</div>
Vue my-app component template:
<h2>
<slot name="resultPageLabel"></slot>
"{{mutatedQuery}}".
</h2>
I didn't succeed to integrate Fluid on Vue, I think that both have different rendering engines and can not be synchronize as I wanted.
I solved this issue by adding <f:translate key="search.resultPage"/> as a data-attribute on another tag(that is not rendered in vue) and get that translates on vue component.

Vue syntax rendered after page load

I am a newbie in Vue.js. I am currently using Vue.js on top of asp.net core.
I noticed that in 99% time page is served before Vue.js syntax is rendered. How can I prevent this from happening?
For example
When page load first I see
<ol>
<li v-for="u in subscribers">{{ u.name }} - {{u.email}}</li>
</ol>
And then after split of a second I see
<ol>
<li>John - john#domain.com</li>
<li>John1 - joh1n#domain.com</li>
</ol>
Since the template is written inside the page HTML code it will always be shown first by the browser when it’s loading the page. Usually Vue components include a template which is used to render the data and this won’t happen.
You can take the template that is written on the page and add it to the Vue component so it will use it to render, not the contents of the page. The simplest way is to just add the template as a parameter to the Vue component, but later on it may be better to use separate template files, or Single File Components which may take a bit more work.

How to disable replacing the app root div with the component HTML while using templates

So basically, when using components - the app root passed to the Vue instance gets replaced by whatever HTML is in the component. Is there a way to disable this and just nest the stuff Vue renders inside the app root instead?
for example - if index.html has a wrapper of
<div id="myVueApp"></div>
and I set el: "#myVueApp" on the Vue instance, the whole node will get removed and replaced by whatever I have in my template resulting in
<div id="myComponent">...</div>
Is there a way to make it into
<div id="myVueApp">
<div id="myComponent">...</div>
</div>
Should work. From what I understand, you want to have multiple parts of your Vue app to be splitted up in the rendered HTML output as well, more specifically into multiple divs.
I think this should work if you use multiple Vue instances.
Set up a structure in your HTML file and give them appropriate id's.
Then, create the Vue instances you want and assign each of them to their specific div using el.
However, I can't tell you if this is a good idea and follows the best practice..
Hope this helps!