Source

src/vue-wrapper.js

import editor from 'vue2-ace-editor'
import _ from 'underscore'

/**
 * This is a wrapper component for Vue.js
 * It renders the code in the editor and displays the result in the preview window
 * It also provides a button to toggle the editor
 * @function renderComponent
 * @param {string} code - the code to be rendered
 * @returns {VueComponent} - the rendered component
 * @example
 * <vue-wrapper :default-code="code"></vue-wrapper>
 */

export default {
  template: `
    <div ref="wrapperBox">
      <component :is="userComponent"></component>
      <p class="bd__button"><a href="#" @click.prevent="toggleEditor">Modify Example Code</a></p>
      <div style="margin-bottom: 20px" v-show="isActive">
        <editor
          v-model="code"
          @init="editorInit"
          lang="jsx"
          theme="monokai"
          width="100%"
          height="200"
          mode="jsx">
        </editor>
      </div>
    </div>
  `,
  props: {
    defaultCode: String
  },
  data: function () {
    return {
      code: this.defaultCode,
      userComponent: this.renderComponent(this.defaultCode),
      isActive: false,
    }
  },
  components: {editor},
  created: function () {
    this.debounceRenderComponent = _.debounce(this.renderComponent, 500).bind(this)
  },
  methods: {
    toggleEditor: function () {
      this.isActive = !this.isActive
    },
    editorInit: function () {
      require('brace/ext/language_tools') //language extension prerequsite...      
      require('brace/mode/jsx')    //language
      require('brace/theme/monokai')
    },
    renderComponent: function (originalCode) {
      const code = originalCode || this.code
      let json = {}
      try {
        if (code && code.length && code[0] === '{') {
          json = eval('(' + code + ')')
        }
      } catch(e) {
        // simply example is not a json object
      }

      try {
        json.components = vueComponents
        json.template = json.template || code
        const component = Vue.component('user-component', json)
        this.userComponent = component
        return component
      } catch (error) {
        console.log(error)
      }
    }
  },
  updated: function () {
    this.$nextTick(function () {
      window.updateHeight(this.$refs.wrapperBox.clientHeight)
    })
  },
  mounted: function () {
    this.$nextTick(function () {
      window.updateHeight(this.$refs.wrapperBox.clientHeight)
    })
  },
  watch: {
    // whenever question changes, this function will run
    code: function (newCode, oldCode) {
      this.debounceRenderComponent(newCode)
    }
  },
}