vue-pre-render-and-mount

by lid0

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.5/vue.global.js"></script>
<!-- 
This is a rendered decorated template
we wrap expressions in ref tag, with the original expression

Note: this approach does not work for conditional rendering 
--> 
<script id ="source" type="text/html" id="my-comp-template">
  <div>Welcome : <ref v="{{ hello }}">someone</ref> </div>
  <button @click="click"><ref v="{{clickMsg}}"> click for nothing</ref> </button>
  <div>is mounted :<ref v='{{isMounted ? "yes" : "no" }}'>no</ref> </div>
  
  <!-- v-if conditional render, will not work as it will always show its content   -->
  <div class="msg" v-if="false"> will be removed when mounted </div>
  <div class="msg" v-else > v-else this will stay </div>
</script>

<pre>Wait 3 seconds for app to mount</pre>
<div id="content">
<!-- will be populated synchronously search engine should pick it up -->  
</div>

CSS

#content {
  border:1px solid gray;
  padding:10px;
  width:400px;
  
}

.msg {
  width:400px;
  background:#cece44;
  padding:2px;
}

JavaScript

var src = document.getElementById("source")
var target = document.getElementById("content")
const annotationTag = 'ref';
trasnferTemplateToContainer(src,target)

function trasnferTemplateToContainer(src,target){
	target.innerHTML = src.innerHTML
}
/**
take an annotated rendered template, and convert back to template.
<div><ref v="{{msg}}">hello</ref></div>
output 
<div>{{msg}}</div>
**/
function templetaize(sourceElement){
  var el =  document.createElement("div") 
  el.innerHTML = sourceElement
  // find all ref tags, and replace tags with content in "v" attribute
  m = el.querySelectorAll(annotationTag)
  m.forEach((el)=>{
    el.parentNode.replaceChild(document.createTextNode(el.getAttribute("v")), el)
  })
  return el.innerHTML
}

setTimeout(loadAppInDelay, 3000)

function loadAppInDelay(){
app.mount("#content")
}
const App = {
  template: templetaize(source.innerHTML),
  data(){
    return { 
    hello: "you, app is now mounted",
    clickMsg: "click for alert",
    isMounted : "false"
    }
  },
  methods: {
    click(){
    alert("you clicked")
    },
    mounted(){
      isMounted = true
    }
  }
}
let app = Vue.createApp(App)