alexjoverm / v-runtime-template

Vue component for compiling templates on the fly using a v-html like API
MIT License
605 stars 70 forks source link

Error when using v-render-template with vue-class-component #3

Closed padcom closed 5 years ago

padcom commented 6 years ago

https://github.com/padcom/v-runtime-template-example-with-poi

Problem description

In src/index.js there are 2 imports.

//import App from './components/App1'
import App from './components/App2'

App1 uses standard Vue component definition (object-literal syntax). App2 uses class components (the actual component is a class that extends Vue by using vue-class-component package).

App1 works but in dev mode throws an error when loading the page about template compiler not being available. However, there is no error in production build.

App2 does not work at all - see error message in the console.

Example application

The example application allows the user to edit the template and then to use it with v-render-template. To start the example application run

$ npm start

and navigate to http://localhost:4000

To do the production build run:

$ npm run build
alexjoverm commented 6 years ago

As stated in the Readme, you need the with-compiler Vue version. You can see how to do it with Vue CLI and Nuxt.

So it'd be a matter of do the same in Poi, could you check that?

hariseldon78 commented 6 years ago

I also have problems with class based components. I have configured the project with the suggested vue.config.js, and when using a traditional component like this:

<template>
    <div>
         <v-runtime-template :template="template"></v-runtime-template>
    </div>
</template>

<script lang="ts">
        import Vue from 'vue';  
    import VRuntimeTemplate from 'v-runtime-template';

    export default Vue.extend({
        name: 'FreeListPanel',
        props: {
            msg: String,
        },
        components:{VRuntimeTemplate},
        data: function() {
            return {
                template:'<h2>this is a dynamic template in object based component</h2>'
                };
            }
    });
</script>

everything is working and i see the string. When using the class based component instead:

<template>
    <div>
         <v-runtime-template :template="template"></v-runtime-template>
    </div>
</template>

<script lang="ts">
    import Vue from 'vue';  
    import Component from 'vue-class-component';
    import {Prop} from 'vue-property-decorator';
    import VRuntimeTemplate from 'v-runtime-template';

    @Component({components:{VRuntimeTemplate}})
    export default class FreeListPanel extends Vue {
        @Prop() msg:string;
        template='<h2>this is a dynamic template in class based component'
    }
</script>

the template is not compiled/rendered and I get this error in the console:

[Vue warn]: Error in render: "TypeError: Cannot read property 'props' of undefined"

found in

---> <VRuntimeTemplate>
       <FreeListPanel> at src/components/FreeListPanel.vue
         <VCard>
           <Panel> at src/components/Panel.vue
             <Grid> at src/components/Grid.vue
               <VContent>
                 <VApp>
                   <App> at src/App.vue
                     <Root>
warn @ vue.common.js?5ee5:593
logError @ vue.common.js?5ee5:1739
globalHandleError @ vue.common.js?5ee5:1734
handleError @ vue.common.js?5ee5:1723
Vue._render @ vue.common.js?5ee5:4548
updateComponent @ vue.common.js?5ee5:2790
get @ vue.common.js?5ee5:3144
Watcher @ vue.common.js?5ee5:3133
mountComponent @ vue.common.js?5ee5:2797
Vue.$mount @ vue.common.js?5ee5:8542
Vue.$mount @ vue.common.js?5ee5:10941
init @ vue.common.js?5ee5:4139
createComponent @ vue.common.js?5ee5:5610
createElm @ vue.common.js?5ee5:5557
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
patch @ vue.common.js?5ee5:6093
Vue._update @ vue.common.js?5ee5:2662
updateComponent @ vue.common.js?5ee5:2790
get @ vue.common.js?5ee5:3144
Watcher @ vue.common.js?5ee5:3133
mountComponent @ vue.common.js?5ee5:2797
Vue.$mount @ vue.common.js?5ee5:8542
Vue.$mount @ vue.common.js?5ee5:10941
init @ vue.common.js?5ee5:4139
createComponent @ vue.common.js?5ee5:5610
createElm @ vue.common.js?5ee5:5557
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
patch @ vue.common.js?5ee5:6093
Vue._update @ vue.common.js?5ee5:2662
updateComponent @ vue.common.js?5ee5:2790
get @ vue.common.js?5ee5:3144
Watcher @ vue.common.js?5ee5:3133
mountComponent @ vue.common.js?5ee5:2797
Vue.$mount @ vue.common.js?5ee5:8542
Vue.$mount @ vue.common.js?5ee5:10941
init @ vue.common.js?5ee5:4139
createComponent @ vue.common.js?5ee5:5610
createElm @ vue.common.js?5ee5:5557
patch @ vue.common.js?5ee5:6093
Vue._update @ vue.common.js?5ee5:2662
updateComponent @ vue.common.js?5ee5:2790
get @ vue.common.js?5ee5:3144
Watcher @ vue.common.js?5ee5:3133
mountComponent @ vue.common.js?5ee5:2797
Vue.$mount @ vue.common.js?5ee5:8542
Vue.$mount @ vue.common.js?5ee5:10941
init @ vue.common.js?5ee5:4139
createComponent @ vue.common.js?5ee5:5610
createElm @ vue.common.js?5ee5:5557
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
patch @ vue.common.js?5ee5:6093
Vue._update @ vue.common.js?5ee5:2662
updateComponent @ vue.common.js?5ee5:2790
get @ vue.common.js?5ee5:3144
Watcher @ vue.common.js?5ee5:3133
mountComponent @ vue.common.js?5ee5:2797
Vue.$mount @ vue.common.js?5ee5:8542
Vue.$mount @ vue.common.js?5ee5:10941
init @ vue.common.js?5ee5:4139
createComponent @ vue.common.js?5ee5:5610
createElm @ vue.common.js?5ee5:5557
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
patch @ vue.common.js?5ee5:6093
Vue._update @ vue.common.js?5ee5:2662
updateComponent @ vue.common.js?5ee5:2790
get @ vue.common.js?5ee5:3144
Watcher @ vue.common.js?5ee5:3133
mountComponent @ vue.common.js?5ee5:2797
Vue.$mount @ vue.common.js?5ee5:8542
Vue.$mount @ vue.common.js?5ee5:10941
init @ vue.common.js?5ee5:4139
createComponent @ vue.common.js?5ee5:5610
createElm @ vue.common.js?5ee5:5557
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
createChildren @ vue.common.js?5ee5:5684
createElm @ vue.common.js?5ee5:5586
patch @ vue.common.js?5ee5:6093
Vue._update @ vue.common.js?5ee5:2662
updateComponent @ vue.common.js?5ee5:2790
get @ vue.common.js?5ee5:3144
Watcher @ vue.common.js?5ee5:3133
mountComponent @ vue.common.js?5ee5:2797
Vue.$mount @ vue.common.js?5ee5:8542
Vue.$mount @ vue.common.js?5ee5:10941
init @ vue.common.js?5ee5:4139
createComponent @ vue.common.js?5ee5:5610
createElm @ vue.common.js?5ee5:5557
patch @ vue.common.js?5ee5:6093
Vue._update @ vue.common.js?5ee5:2662
updateComponent @ vue.common.js?5ee5:2790
get @ vue.common.js?5ee5:3144
Watcher @ vue.common.js?5ee5:3133
mountComponent @ vue.common.js?5ee5:2797
Vue.$mount @ vue.common.js?5ee5:8542
Vue.$mount @ vue.common.js?5ee5:10941
init @ vue.common.js?5ee5:4139
createComponent @ vue.common.js?5ee5:5610
createElm @ vue.common.js?5ee5:5557
patch @ vue.common.js?5ee5:6132
Vue._update @ vue.common.js?5ee5:2662
updateComponent @ vue.common.js?5ee5:2790
get @ vue.common.js?5ee5:3144
Watcher @ vue.common.js?5ee5:3133
mountComponent @ vue.common.js?5ee5:2797
Vue.$mount @ vue.common.js?5ee5:8542
Vue.$mount @ vue.common.js?5ee5:10941
Vue._init @ vue.common.js?5ee5:4642
Vue @ vue.common.js?5ee5:4731
(anonymous) @ main.ts?bc82:34
./src/main.ts @ app.js:12907
__webpack_require__ @ app.js:722
fn @ app.js:99
0 @ app.js:13028
__webpack_require__ @ app.js:722
(anonymous) @ app.js:789
(anonymous) @ app.js:792
vue.common.js?5ee5:1743 TypeError: Cannot read property 'props' of undefined
    at FreeListPanel.Component._init (vue-class-component.common.js?65d9:54)
    at FreeListPanel.Vue (vue.common.js?5ee5:4731)
    at new FreeListPanel (FreeListPanel.vue?ec28:47)
    at collectDataFromConstructor (vue-class-component.common.js?65d9:72)
    at Object.data (vue-class-component.common.js?65d9:135)
    at getKeysFromOptions (v-runtime-template.es.js?dd1e:7)
    at Proxy.render (v-runtime-template.es.js?dd1e:45)
    at VueComponent.Vue._render (vue.common.js?5ee5:4546)
    at VueComponent.updateComponent (vue.common.js?5ee5:2790)
    at Watcher.get (vue.common.js?5ee5:3144)

Inspecting the compiled source code i see that the error is caused by this line in the class-component code:


function collectDataFromConstructor(vm, Component) {
    // override _init to prevent to init as Vue instance
    var originalInit = Component.prototype._init;
    Component.prototype._init = function () {
        var _this = this;
        // proxy to actual vm
        var keys = Object.getOwnPropertyNames(vm);
        // 2.2.0 compat (props are no longer exposed as self properties)
        if (vm.$options.props) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            for (var key in vm.$options.props) {
                if (!vm.hasOwnProperty(key)) {
                    keys.push(key);
                }
            }
        }
        keys.forEach(function (key) {
            if (key.charAt(0) !== '_') {
                Object.defineProperty(_this, key, {
                    get: function () { return vm[key]; },
                    set: function (value) { return vm[key] = value; },
                    configurable: true
                });
            }
        });
hariseldon78 commented 6 years ago

I found that i can use the class based component without problems if i add this line in the @Component decorator:

@Component({
    components:{VRuntimeTemplate},
    $options:{props:{}}
^^^^^^^^^^^^^^^^^^^^^^^^^^
})
DelfsEngineering commented 5 years ago

I found that i can use the class based component without problems if i add this line in the @component decorator:

@hariseldon78 Could you explain more on how / where you added this line?

thanks

BegeMode commented 5 years ago

@hariseldon78 Could you explain more on how / where you added this line?

You just need to define in .d.ts file:

declare module "vue/types/options" {
  interface ComponentOptions<V extends Vue> {
    $options?: any
  }
}
WhereBeTheDan commented 5 years ago

I would add that after updating to 1.6 the fix needed is: @Component({ props: {}, computed: {}, ... })

This is only necessary if the component isn't receiving any props and/or doesn't have computed properties. I think this is fixable with a check on parent in the VRuntimeTemplate component.

alexjoverm commented 5 years ago

This issue is probably fixed already by #30. Could you guys check it out? Feel free to open it again if not

Worie commented 5 years ago

I have similar problem, just installed the latest version from master and the errors seem to persist :( I'm using Component decorator from vue-property-decorator, error appears if there are any properties defined in the component 🤔