fizzydrinks
fizzydrinks

Reputation: 634

How can I insert a VueJS app into an existing page?

At this project I'm working on there is a legacy server-rendered web page and some components had problems I've been assigned to fix, and I convinced the team to rewrite those parts in Vue to kickstart our migration.

I wrote the whole mini-app using the Webpack template provided by Vue CLI and it works like a charm... in that specific environment.

If I npm run build the built index.html also works fine in a static server.

However, I can't seem to include the app in an existing page composed of many other elements. Shouldn't it be as simple as adding the <div id='myApp'></div> element to the HTML and loading the generated JS files?

If it helps, the legacy app is a Rails app using .erb templates and the JS files are being loaded through the main pipeline in application.js.

Does anyone know why nothing happens when I try this?

Edit: more information - this is how main.js looks before build:

/* eslint-disable */
import Vue from 'vue'

// UI components
import VueSelect from 'vue-select'

import DynamicForm from './components/DynamicForm/'

Vue.component('vue-select', VueSelect)
Vue.config.productionTip = false

const DynamicForms = new Vue({
   el: '.dynamic-form',
   render: h => h(DynamicForm)
})

Edit: I managed to get Vue to work by integrating Webpack to Rails with Webpacker. However I still have some problems regarding context:

This is my main.js in one of the Vue components. It was working fine until I tried the PropData stunt so I could reuse the component with different data in a few places.

/* eslint-disable */
import Vue from 'vue'

// UI components
import VueSelect from 'vue-select'
// import 'nouislider'

import DynamicForm from './components/DynamicForm/'

import fields from './fields'
import fieldRules from './field-rules'

Vue.component('vue-select', VueSelect)
Vue.config.productionTip = false

document.addEventListener('DOMContentLoaded', () => {
  const el = document.createElement('div')
  document.querySelector('.dynamic-form').appendChild(el)

  const vm = new DynamicForm({
    propsData: {
      fields,
      fieldRules
    },
    el,
    render: h => h(DynamicForm)
  })
})

This is DynamicForm/index.vue

<template>
  <div id='app'>
    <ParamList :fields='paramFields' :fieldRules='paramRules'></ParamList>
    <Output></Output>
  </div>
</template>

<script>
import Vue from 'vue'

import ParamList from './ParamList'
import Output from './Output'

export default Vue.extend({
  props: [ 'fields', 'fieldRules' ],
  name: 'DynamicForm',
  components: {
    ParamList,
    Output
  },
  data () {
    return {
      paramFields: this.fields,
      paramRules: this.fieldRules
    }
  }
})
</script>

<style>
</style>

The field and fieldData props are merely JSON/JSONP with some data I'm going to use inside those components. The idea is that I could write another main.js changing just the field and fieldData when initing the Vue instance.

What am I doing wrong?

Upvotes: 2

Views: 4257

Answers (1)

fizzydrinks
fizzydrinks

Reputation: 634

I've managed to fix everything in a three-step change to my components.

  1. Integrate Webpack into Rails using Webpacker. There's even a Vue template!
  2. Change the root component (the one mounted at a real DOM element) to a Vue subclass using Vue.extend (so the module line @ the .vue file read export default Vue.extend({ instead of simply export default {
  3. Remove the render function from the new DynamicForm (the name I assigned Vue.extend to) so it renders its own template.

I hope it helps as it was quite a pain to me!

Upvotes: 1

Related Questions