2
votes

I want to create a custom Vue directive that lets me select components on my page which I want to hydrate. In other words, this is what I want to archive

  1. I render my Vue app on the server (ssr)
  2. I attach a directive to some components, like this:

    <template>
        <div v-hydrate @click="do-something"> I will be hydrated</div>
    </template>
    
  3. I send my code to the client and only those components that have the v-hydrate property will be hydrated (as root elements) on the client.

I want to achieve this roughly this way:

I will create a directives that marks and remembers components:

import Vue from "vue";

Vue.directive("hydrate", {
  inserted: function(el, binding, vnode) {
    el.setAttribute("data-hydration-component", vnode.component.name);
  }
});

My idea is that in my inserted method write a data-attribute to the server-rendered element that I can read out in the client and then hydrate my component with.

Now I have 2 questions:

  1. Is that a feasible approach
  2. How do I get the component name in el.setAttribute? vnode.component.name is just dummy code and does not exist this way.

PS: If you want to know why I only want to hydrate parts of my website: It's ads. They mess with the DOM which breaks Vue.

2

2 Answers

3
votes

I could figure it out:

import Vue from "vue";

Vue.directive("hydrate", {
  inserted: function(el, binding, vnode) {
    console.log(vnode.context.$options.name); // the component's name
  }
});
1
votes

I couldn't get the name of my single file components using the previously posted solution, so I had a look at the source code of vue devtools that always manages to find the name. Here's how they do it:

export function getComponentName (options) {
  const name = options.name || options._componentTag
  if (name) {
    return name
  }
  const file = options.__file // injected by vue-loader
  if (file) {
    return classify(basename(file, '.vue'))
  }
}

where options === $vm.$options