├── .gitignore
├── .idea
├── .gitignore
├── modules.xml
├── v-runtime-template-vue3.iml
└── vcs.xml
├── .vscode
└── settings.json
├── App.vue
├── LICENSE
├── README.md
├── Test.vue
├── dist
├── vue3-runtime-template.es.js
├── vue3-runtime-template.es.js.map
├── vue3-runtime-template.js
├── vue3-runtime-template.js.map
├── vue3-runtime-template.umd.js
└── vue3-runtime-template.umd.js.map
├── index.js
├── main.js
├── package-lock.json
├── package.json
├── test.plugin.js
├── vue.config.js
└── vue3-runtime-template.d.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/v-runtime-template-vue3.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": false,
3 | }
--------------------------------------------------------------------------------
/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
53 |
54 |
56 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Alex Jover
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue3-runtime-template
2 |
3 | [](https://www.npmjs.com/package/vue3-runtime-template)
4 |
5 | [](https://www.npmjs.com/package/vue3-runtime-template)
6 |
7 | A Vue.js components that makes easy compiling and interpreting a Vue.js template at runtime by using a `v-html` like API.
8 |
9 | vue3-runtime-template is based off v-runtime-template but tweaked to work with Vue 3.
10 |
11 | ## Motivation
12 |
13 | This library solves the case where you get a vue-syntax template string on runtime, usually from a server. Think of a feature where you allow the user to create their own interfaces and structures. You save that as a vue template in your database, which your UI will request later. While components are pre-compiled at build time, this case isn't (since the template is received at runtime) and needs to be compiled at runtime.
14 |
15 | vue3-runtime-template compiles that template and attaches it to the scope of the component that uses it, so it has access to its data, props, methods and computed properties.
16 |
17 | Think of it as the `v-html` equivalent that also understands vue template syntax (while `v-html` is just for plain HTML).
18 |
19 | ## Getting Started
20 |
21 | Install it:
22 |
23 | ```
24 | npm install vue3-runtime-template
25 | ```
26 |
27 | You must **use the with-compiler Vue.js version**. This is needed in order to compile on-the-fly Vue.js templates. For that, you can set a webpack alias for `vue` to the correct file.
28 |
29 | For example, if you use the [Vue CLI](https://github.com/vuejs/vue-cli), create or modify the `vue.config.js` file adding the following alias:
30 |
31 | ```js
32 | // vue.config.js
33 | module.exports = {
34 | configureWebpack: {
35 | resolve: {
36 | alias: {
37 | vue$: 'vue/dist/vue.esm-bundler.js',
38 | // ...
39 | ```
40 |
41 | In [Nuxt v2](http://nuxtjs.org/), open the `nuxt.config.js` file and extend the webpack config by adding the following line to the `extend` key:
42 |
43 | ```js
44 | // nuxt.config.js
45 | {
46 | build: {
47 | extend(config, { isDev, isClient }) {
48 | config.resolve.alias["vue"] = "vue.esm-bundler.js";
49 | // ...
50 | ```
51 |
52 | In [Nuxt v3](https://v3.nuxtjs.org/), open the `nuxt.config.js` file and extend the vite config by adding the following hook, just on client:
53 |
54 | ```js
55 | // nuxt.config.js
56 | {
57 | (...)
58 |
59 | hooks: {
60 | 'vite:extendConfig': (config, { isClient, isServer }) => {
61 | if (isClient) {
62 | config.resolve.alias.vue = 'vue/dist/vue.esm-bundler'
63 | }
64 | },
65 | },
66 |
67 | (...)
68 | ```
69 |
70 | You can read about different bundles of Vue in the official [help guides](https://v3.vuejs.org/guide/installation.html#with-a-bundler).
71 | ## Usage
72 |
73 | You just need to import the `vue3-runtime-template` component, and pass the template you want:
74 |
75 | ```html
76 |
77 |
78 |
79 |
80 |
81 |
82 |
99 | ```
100 |
101 | The template you pass **have access to the parent component instance**. For example, in the last example we're using the `AppMessage` component and accessing the `{{ name }}` state variable.
102 |
103 | But you can access computed properties and methods as well from the template:
104 |
105 | ```js
106 | export default {
107 | data: () => ({
108 | name: "Mellow",
109 | template: `
110 |
111 |
Hello {{ name }}!
112 |
Say Hi!
113 |
{{ someComputed }}
114 |
115 | `,
116 | }),
117 | computed: {
118 | someComputed() {
119 | return "Wow, I'm computed";
120 | },
121 | },
122 | methods: {
123 | sayHi() {
124 | console.log("Hi");
125 | },
126 | },
127 | };
128 | ```
129 |
130 | ## Limitations
131 |
132 | Keep in mind that the template can only access the instance properties of the component who is using it.
133 |
134 | ## Comparison
135 |
136 | ### vue3-runtime-template VS v-html
137 |
138 | _TL;DR: If you need to interpret only HTML, use `v-html`. Use this library otherwise._
139 |
140 | They both have the same goal: to interpret and attach a piece of structure to a scope at runtime. The difference is, `[v-html](https://vuejs.org/v2/api/#v-html)` doesn't understand vue template syntax, but only HTML. So, while this code works:
141 |
142 | ```html
143 |
144 |
145 |
146 |
147 |
11 |
12 |
--------------------------------------------------------------------------------
/dist/vue3-runtime-template.es.js:
--------------------------------------------------------------------------------
1 | import{h as t}from"vue";var o=function(t,o,e){if(!o.hasOwnProperty(e)){var r=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(o,e,r)}};export default{props:{template:String,parent:Object,templateProps:{type:Object,default:function(){return{}}}},render:function(){if(this.template){var e=this.parent||this.$parent,r=e.$data;void 0===r&&(r={});var n=e.$props;void 0===n&&(n={});var a=e.$options;void 0===a&&(a={});var p=a.components;void 0===p&&(p={});var i=a.computed;void 0===i&&(i={});var c=a.methods;void 0===c&&(c={});var s=this.$data;void 0===s&&(s={});var d=this.$props;void 0===d&&(d={});var v=this.$options;void 0===v&&(v={});var m=v.methods;void 0===m&&(m={});var f=v.computed;void 0===f&&(f={});var u=v.components;void 0===u&&(u={});var h={$data:{},$props:{},$options:{},components:{},computed:{},methods:{}};Object.keys(r).forEach(function(t){void 0===s[t]&&(h.$data[t]=r[t])}),Object.keys(n).forEach(function(t){void 0===d[t]&&(h.$props[t]=n[t])}),Object.keys(c).forEach(function(t){void 0===m[t]&&(h.methods[t]=c[t])}),Object.keys(i).forEach(function(t){void 0===f[t]&&(h.computed[t]=i[t])}),Object.keys(p).forEach(function(t){void 0===u[t]&&(h.components[t]=p[t])});var $=Object.keys(h.methods||{}),O=Object.keys(h.$data||{}),b=Object.keys(h.$props||{}),j=Object.keys(this.templateProps),y=O.concat(b).concat($).concat(j),k=(E=e,P={},$.forEach(function(t){return o(E,P,t)}),P),l=function(t){var e={};return t.forEach(function(t){t&&Object.getOwnPropertyNames(t).forEach(function(r){return o(t,e,r)})}),e}([h.$data,h.$props,k,this.templateProps]);return t({template:this.template||"
",props:y,computed:h.computed,components:h.components,provide:this.$parent.$.provides?this.$parent.$.provides:{}},Object.assign({},l))}var E,P}};
2 | //# sourceMappingURL=vue3-runtime-template.es.js.map
3 |
--------------------------------------------------------------------------------
/dist/vue3-runtime-template.es.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"vue3-runtime-template.es.js","sources":["../index.js"],"sourcesContent":["import {h} from 'vue';\n\nconst defineDescriptor = (src, dest, name) => {\n // eslint-disable-next-line no-prototype-builtins\n if (!dest.hasOwnProperty(name)) {\n const descriptor = Object.getOwnPropertyDescriptor(src, name);\n Object.defineProperty(dest, name, descriptor);\n }\n};\n\nconst merge = (objs) => {\n const res = {};\n objs.forEach((obj) => {\n obj &&\n Object.getOwnPropertyNames(obj).forEach((name) =>\n defineDescriptor(obj, res, name),\n );\n });\n return res;\n};\n\nconst buildFromProps = (obj, props) => {\n const res = {};\n props.forEach((prop) => defineDescriptor(obj, res, prop));\n return res;\n};\n\nexport default {\n props: {\n template: String,\n parent: Object,\n templateProps: {\n type: Object,\n default: () => ({}),\n },\n },\n render() {\n if (this.template) {\n const parent = this.parent || this.$parent;\n const {\n $data: parentData = {},\n $props: parentProps = {},\n $options: parentOptions = {},\n } = parent;\n const {\n components: parentComponents = {},\n computed: parentComputed = {},\n methods: parentMethods = {},\n } = parentOptions;\n const {\n $data = {},\n $props = {},\n $options: {methods = {}, computed = {}, components = {}} = {},\n } = this;\n const passthrough = {\n $data: {},\n $props: {},\n $options: {},\n components: {},\n computed: {},\n methods: {},\n };\n\n // build new objects by removing keys if already exists (e.g. created by mixins)\n Object.keys(parentData).forEach((e) => {\n if (typeof $data[e] === 'undefined') {\n passthrough.$data[e] = parentData[e];\n }\n });\n Object.keys(parentProps).forEach((e) => {\n if (typeof $props[e] === 'undefined') {\n passthrough.$props[e] = parentProps[e];\n }\n });\n Object.keys(parentMethods).forEach((e) => {\n if (typeof methods[e] === 'undefined') {\n passthrough.methods[e] = parentMethods[e];\n }\n });\n Object.keys(parentComputed).forEach((e) => {\n if (typeof computed[e] === 'undefined') {\n passthrough.computed[e] = parentComputed[e];\n }\n });\n Object.keys(parentComponents).forEach((e) => {\n if (typeof components[e] === 'undefined') {\n passthrough.components[e] = parentComponents[e];\n }\n });\n\n const methodKeys = Object.keys(passthrough.methods || {});\n const dataKeys = Object.keys(passthrough.$data || {});\n const propKeys = Object.keys(passthrough.$props || {});\n const templatePropKeys = Object.keys(this.templateProps);\n const allKeys = dataKeys.concat(propKeys).concat(methodKeys).concat(templatePropKeys);\n const methodsFromProps = buildFromProps(parent, methodKeys);\n const finalProps = merge([\n passthrough.$data,\n passthrough.$props,\n methodsFromProps,\n this.templateProps,\n ]);\n\n const provide = this.$parent.$.provides ? this.$parent.$.provides : {}; // Avoids Vue warning\n\n const dynamic = {\n template: this.template || '
',\n props: allKeys,\n computed: passthrough.computed,\n components: passthrough.components,\n provide: provide,\n };\n // debugger;\n\n return h(dynamic, {...finalProps});\n }\n },\n};\n"],"names":["const","defineDescriptor","src","dest","name","hasOwnProperty","descriptor","Object","getOwnPropertyDescriptor","defineProperty","props","template","String","parent","templateProps","type","default","render","this","$parent","passthrough","$data","$props","$options","components","computed","methods","keys","parentData","forEach","e","parentProps","parentMethods","parentComputed","parentComponents","methodKeys","dataKeys","propKeys","templatePropKeys","allKeys","concat","methodsFromProps","obj","res","prop","finalProps","objs","getOwnPropertyNames","merge","h","provide","$","provides"],"mappings":"wBAEAA,IAAMC,WAAoBC,EAAKC,EAAMC,OAE9BD,EAAKE,eAAeD,GAAO,KACxBE,EAAaC,OAAOC,yBAAyBN,EAAKE,GACxDG,OAAOE,eAAeN,EAAMC,EAAME,mBAqBvB,CACbI,MAAO,CACLC,SAAUC,OACVC,OAAQN,OACRO,cAAe,CACbC,KAAMR,OACNS,+BAGJC,qBACMC,KAAKP,SAAU,KACXE,EAASK,KAAKL,QAAUK,KAAKC,iCAEb,kCACE,oCACI,sCAGK,oCACJ,mCACF,UAMvBD,0BAHM,UAGNA,2BAFO,UAEPA,6BADyD,IAAjD,+BAAW,oCAAe,sCAAiB,QAEjDE,EAAc,CAClBC,MAAO,GACPC,OAAQ,GACRC,SAAU,GACVC,WAAY,GACZC,SAAU,GACVC,QAAS,IAIXnB,OAAOoB,KAAKC,GAAYC,iBAASC,QACP,IAAbT,EAAMS,KACfV,EAAYC,MAAMS,GAAKF,EAAWE,MAGtCvB,OAAOoB,KAAKI,GAAaF,iBAASC,QACP,IAAdR,EAAOQ,KAChBV,EAAYE,OAAOQ,GAAKC,EAAYD,MAGxCvB,OAAOoB,KAAKK,GAAeH,iBAASC,QACR,IAAfJ,EAAQI,KACjBV,EAAYM,QAAQI,GAAKE,EAAcF,MAG3CvB,OAAOoB,KAAKM,GAAgBJ,iBAASC,QACR,IAAhBL,EAASK,KAClBV,EAAYK,SAASK,GAAKG,EAAeH,MAG7CvB,OAAOoB,KAAKO,GAAkBL,iBAASC,QACR,IAAlBN,EAAWM,KACpBV,EAAYI,WAAWM,GAAKI,EAAiBJ,UAI3CK,EAAa5B,OAAOoB,KAAKP,EAAYM,SAAW,IAChDU,EAAW7B,OAAOoB,KAAKP,EAAYC,OAAS,IAC5CgB,EAAW9B,OAAOoB,KAAKP,EAAYE,QAAU,IAC7CgB,EAAmB/B,OAAOoB,KAAKT,KAAKJ,eACpCyB,EAAUH,EAASI,OAAOH,GAAUG,OAAOL,GAAYK,OAAOF,GAC9DG,GA1EYC,EA0EsB7B,EAzEtC8B,EAAM,GAyEwCR,EAxE9CN,iBAASe,UAAS3C,EAAiByC,EAAKC,EAAKC,KAC5CD,GAwEGE,WAtFGC,OACPH,EAAM,UACZG,EAAKjB,iBAASa,GACZA,GACEnC,OAAOwC,oBAAoBL,GAAKb,iBAASzB,UACvCH,EAAiByC,EAAKC,EAAKvC,OAG1BuC,EA8EgBK,CAAM,CACvB5B,EAAYC,MACZD,EAAYE,OACZmB,EACAvB,KAAKJ,uBAcAmC,EATS,CACdtC,SAAUO,KAAKP,UAAY,cAC3BD,MAAO6B,EACPd,SAAUL,EAAYK,SACtBD,WAAYJ,EAAYI,WACxB0B,QAPchC,KAAKC,QAAQgC,EAAEC,SAAWlC,KAAKC,QAAQgC,EAAEC,SAAW,IAWlD7C,iBAAIsC,QA7FJH,EAChBC"}
--------------------------------------------------------------------------------
/dist/vue3-runtime-template.js:
--------------------------------------------------------------------------------
1 | var t=require("vue"),o=function(t,o,e){if(!o.hasOwnProperty(e)){var r=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(o,e,r)}},e={props:{template:String,parent:Object,templateProps:{type:Object,default:function(){return{}}}},render:function(){if(this.template){var e=this.parent||this.$parent,r=e.$data;void 0===r&&(r={});var n=e.$props;void 0===n&&(n={});var a=e.$options;void 0===a&&(a={});var p=a.components;void 0===p&&(p={});var i=a.computed;void 0===i&&(i={});var c=a.methods;void 0===c&&(c={});var s=this.$data;void 0===s&&(s={});var d=this.$props;void 0===d&&(d={});var v=this.$options;void 0===v&&(v={});var u=v.methods;void 0===u&&(u={});var h=v.computed;void 0===h&&(h={});var m=v.components;void 0===m&&(m={});var f={$data:{},$props:{},$options:{},components:{},computed:{},methods:{}};Object.keys(r).forEach(function(t){void 0===s[t]&&(f.$data[t]=r[t])}),Object.keys(n).forEach(function(t){void 0===d[t]&&(f.$props[t]=n[t])}),Object.keys(c).forEach(function(t){void 0===u[t]&&(f.methods[t]=c[t])}),Object.keys(i).forEach(function(t){void 0===h[t]&&(f.computed[t]=i[t])}),Object.keys(p).forEach(function(t){void 0===m[t]&&(f.components[t]=p[t])});var $=Object.keys(f.methods||{}),O=Object.keys(f.$data||{}),b=Object.keys(f.$props||{}),j=Object.keys(this.templateProps),y=O.concat(b).concat($).concat(j),k=(E=e,P={},$.forEach(function(t){return o(E,P,t)}),P),l=function(t){var e={};return t.forEach(function(t){t&&Object.getOwnPropertyNames(t).forEach(function(r){return o(t,e,r)})}),e}([f.$data,f.$props,k,this.templateProps]);return t.h({template:this.template||"
",props:y,computed:f.computed,components:f.components,provide:this.$parent.$.provides?this.$parent.$.provides:{}},Object.assign({},l))}var E,P}};module.exports=e;
2 | //# sourceMappingURL=vue3-runtime-template.js.map
3 |
--------------------------------------------------------------------------------
/dist/vue3-runtime-template.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"vue3-runtime-template.js","sources":["../index.js"],"sourcesContent":["import {h} from 'vue';\n\nconst defineDescriptor = (src, dest, name) => {\n // eslint-disable-next-line no-prototype-builtins\n if (!dest.hasOwnProperty(name)) {\n const descriptor = Object.getOwnPropertyDescriptor(src, name);\n Object.defineProperty(dest, name, descriptor);\n }\n};\n\nconst merge = (objs) => {\n const res = {};\n objs.forEach((obj) => {\n obj &&\n Object.getOwnPropertyNames(obj).forEach((name) =>\n defineDescriptor(obj, res, name),\n );\n });\n return res;\n};\n\nconst buildFromProps = (obj, props) => {\n const res = {};\n props.forEach((prop) => defineDescriptor(obj, res, prop));\n return res;\n};\n\nexport default {\n props: {\n template: String,\n parent: Object,\n templateProps: {\n type: Object,\n default: () => ({}),\n },\n },\n render() {\n if (this.template) {\n const parent = this.parent || this.$parent;\n const {\n $data: parentData = {},\n $props: parentProps = {},\n $options: parentOptions = {},\n } = parent;\n const {\n components: parentComponents = {},\n computed: parentComputed = {},\n methods: parentMethods = {},\n } = parentOptions;\n const {\n $data = {},\n $props = {},\n $options: {methods = {}, computed = {}, components = {}} = {},\n } = this;\n const passthrough = {\n $data: {},\n $props: {},\n $options: {},\n components: {},\n computed: {},\n methods: {},\n };\n\n // build new objects by removing keys if already exists (e.g. created by mixins)\n Object.keys(parentData).forEach((e) => {\n if (typeof $data[e] === 'undefined') {\n passthrough.$data[e] = parentData[e];\n }\n });\n Object.keys(parentProps).forEach((e) => {\n if (typeof $props[e] === 'undefined') {\n passthrough.$props[e] = parentProps[e];\n }\n });\n Object.keys(parentMethods).forEach((e) => {\n if (typeof methods[e] === 'undefined') {\n passthrough.methods[e] = parentMethods[e];\n }\n });\n Object.keys(parentComputed).forEach((e) => {\n if (typeof computed[e] === 'undefined') {\n passthrough.computed[e] = parentComputed[e];\n }\n });\n Object.keys(parentComponents).forEach((e) => {\n if (typeof components[e] === 'undefined') {\n passthrough.components[e] = parentComponents[e];\n }\n });\n\n const methodKeys = Object.keys(passthrough.methods || {});\n const dataKeys = Object.keys(passthrough.$data || {});\n const propKeys = Object.keys(passthrough.$props || {});\n const templatePropKeys = Object.keys(this.templateProps);\n const allKeys = dataKeys.concat(propKeys).concat(methodKeys).concat(templatePropKeys);\n const methodsFromProps = buildFromProps(parent, methodKeys);\n const finalProps = merge([\n passthrough.$data,\n passthrough.$props,\n methodsFromProps,\n this.templateProps,\n ]);\n\n const provide = this.$parent.$.provides ? this.$parent.$.provides : {}; // Avoids Vue warning\n\n const dynamic = {\n template: this.template || '
',\n props: allKeys,\n computed: passthrough.computed,\n components: passthrough.components,\n provide: provide,\n };\n // debugger;\n\n return h(dynamic, {...finalProps});\n }\n },\n};\n"],"names":["defineDescriptor","src","dest","name","hasOwnProperty","descriptor","Object","getOwnPropertyDescriptor","defineProperty","props","template","String","parent","templateProps","type","default","render","this","$parent","passthrough","$data","$props","$options","components","computed","methods","keys","parentData","forEach","e","parentProps","parentMethods","parentComputed","parentComponents","methodKeys","dataKeys","propKeys","templatePropKeys","allKeys","concat","methodsFromProps","obj","res","prop","finalProps","objs","getOwnPropertyNames","merge","h","provide","$","provides"],"mappings":"qBAEMA,WAAoBC,EAAKC,EAAMC,OAE9BD,EAAKE,eAAeD,GAAO,KACxBE,EAAaC,OAAOC,yBAAyBN,EAAKE,GACxDG,OAAOE,eAAeN,EAAMC,EAAME,OAqBvB,CACbI,MAAO,CACLC,SAAUC,OACVC,OAAQN,OACRO,cAAe,CACbC,KAAMR,OACNS,+BAGJC,qBACMC,KAAKP,SAAU,KACXE,EAASK,KAAKL,QAAUK,KAAKC,iCAEb,kCACE,oCACI,sCAGK,oCACJ,mCACF,UAMvBD,0BAHM,UAGNA,2BAFO,UAEPA,6BADyD,IAAjD,+BAAW,oCAAe,sCAAiB,QAEjDE,EAAc,CAClBC,MAAO,GACPC,OAAQ,GACRC,SAAU,GACVC,WAAY,GACZC,SAAU,GACVC,QAAS,IAIXnB,OAAOoB,KAAKC,GAAYC,iBAASC,QACP,IAAbT,EAAMS,KACfV,EAAYC,MAAMS,GAAKF,EAAWE,MAGtCvB,OAAOoB,KAAKI,GAAaF,iBAASC,QACP,IAAdR,EAAOQ,KAChBV,EAAYE,OAAOQ,GAAKC,EAAYD,MAGxCvB,OAAOoB,KAAKK,GAAeH,iBAASC,QACR,IAAfJ,EAAQI,KACjBV,EAAYM,QAAQI,GAAKE,EAAcF,MAG3CvB,OAAOoB,KAAKM,GAAgBJ,iBAASC,QACR,IAAhBL,EAASK,KAClBV,EAAYK,SAASK,GAAKG,EAAeH,MAG7CvB,OAAOoB,KAAKO,GAAkBL,iBAASC,QACR,IAAlBN,EAAWM,KACpBV,EAAYI,WAAWM,GAAKI,EAAiBJ,UAI3CK,EAAa5B,OAAOoB,KAAKP,EAAYM,SAAW,IAChDU,EAAW7B,OAAOoB,KAAKP,EAAYC,OAAS,IAC5CgB,EAAW9B,OAAOoB,KAAKP,EAAYE,QAAU,IAC7CgB,EAAmB/B,OAAOoB,KAAKT,KAAKJ,eACpCyB,EAAUH,EAASI,OAAOH,GAAUG,OAAOL,GAAYK,OAAOF,GAC9DG,GA1EYC,EA0EsB7B,EAzEtC8B,EAAM,GAyEwCR,EAxE9CN,iBAASe,UAAS3C,EAAiByC,EAAKC,EAAKC,KAC5CD,GAwEGE,WAtFGC,OACPH,EAAM,UACZG,EAAKjB,iBAASa,GACZA,GACEnC,OAAOwC,oBAAoBL,GAAKb,iBAASzB,UACvCH,EAAiByC,EAAKC,EAAKvC,OAG1BuC,EA8EgBK,CAAM,CACvB5B,EAAYC,MACZD,EAAYE,OACZmB,EACAvB,KAAKJ,uBAcAmC,IATS,CACdtC,SAAUO,KAAKP,UAAY,cAC3BD,MAAO6B,EACPd,SAAUL,EAAYK,SACtBD,WAAYJ,EAAYI,WACxB0B,QAPchC,KAAKC,QAAQgC,EAAEC,SAAWlC,KAAKC,QAAQgC,EAAEC,SAAW,IAWlD7C,iBAAIsC,QA7FJH,EAChBC"}
--------------------------------------------------------------------------------
/dist/vue3-runtime-template.umd.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("vue")):"function"==typeof define&&define.amd?define(["vue"],e):t.vue3RuntimeTemplate=e(t.vue)}(this,function(t){var e=function(t,e,o){if(!e.hasOwnProperty(o)){var r=Object.getOwnPropertyDescriptor(t,o);Object.defineProperty(e,o,r)}};return{props:{template:String,parent:Object,templateProps:{type:Object,default:function(){return{}}}},render:function(){if(this.template){var o=this.parent||this.$parent,r=o.$data;void 0===r&&(r={});var n=o.$props;void 0===n&&(n={});var i=o.$options;void 0===i&&(i={});var p=i.components;void 0===p&&(p={});var a=i.computed;void 0===a&&(a={});var c=i.methods;void 0===c&&(c={});var s=this.$data;void 0===s&&(s={});var d=this.$props;void 0===d&&(d={});var v=this.$options;void 0===v&&(v={});var u=v.methods;void 0===u&&(u={});var f=v.computed;void 0===f&&(f={});var m=v.components;void 0===m&&(m={});var h={$data:{},$props:{},$options:{},components:{},computed:{},methods:{}};Object.keys(r).forEach(function(t){void 0===s[t]&&(h.$data[t]=r[t])}),Object.keys(n).forEach(function(t){void 0===d[t]&&(h.$props[t]=n[t])}),Object.keys(c).forEach(function(t){void 0===u[t]&&(h.methods[t]=c[t])}),Object.keys(a).forEach(function(t){void 0===f[t]&&(h.computed[t]=a[t])}),Object.keys(p).forEach(function(t){void 0===m[t]&&(h.components[t]=p[t])});var $=Object.keys(h.methods||{}),O=Object.keys(h.$data||{}),y=Object.keys(h.$props||{}),b=Object.keys(this.templateProps),j=O.concat(y).concat($).concat(b),l=(E=o,P={},$.forEach(function(t){return e(E,P,t)}),P),k=function(t){var o={};return t.forEach(function(t){t&&Object.getOwnPropertyNames(t).forEach(function(r){return e(t,o,r)})}),o}([h.$data,h.$props,l,this.templateProps]);return t.h({template:this.template||"
",props:j,computed:h.computed,components:h.components,provide:this.$parent.$.provides?this.$parent.$.provides:{}},Object.assign({},k))}var E,P}}});
2 | //# sourceMappingURL=vue3-runtime-template.umd.js.map
3 |
--------------------------------------------------------------------------------
/dist/vue3-runtime-template.umd.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"vue3-runtime-template.umd.js","sources":["../index.js"],"sourcesContent":["import {h} from 'vue';\n\nconst defineDescriptor = (src, dest, name) => {\n // eslint-disable-next-line no-prototype-builtins\n if (!dest.hasOwnProperty(name)) {\n const descriptor = Object.getOwnPropertyDescriptor(src, name);\n Object.defineProperty(dest, name, descriptor);\n }\n};\n\nconst merge = (objs) => {\n const res = {};\n objs.forEach((obj) => {\n obj &&\n Object.getOwnPropertyNames(obj).forEach((name) =>\n defineDescriptor(obj, res, name),\n );\n });\n return res;\n};\n\nconst buildFromProps = (obj, props) => {\n const res = {};\n props.forEach((prop) => defineDescriptor(obj, res, prop));\n return res;\n};\n\nexport default {\n props: {\n template: String,\n parent: Object,\n templateProps: {\n type: Object,\n default: () => ({}),\n },\n },\n render() {\n if (this.template) {\n const parent = this.parent || this.$parent;\n const {\n $data: parentData = {},\n $props: parentProps = {},\n $options: parentOptions = {},\n } = parent;\n const {\n components: parentComponents = {},\n computed: parentComputed = {},\n methods: parentMethods = {},\n } = parentOptions;\n const {\n $data = {},\n $props = {},\n $options: {methods = {}, computed = {}, components = {}} = {},\n } = this;\n const passthrough = {\n $data: {},\n $props: {},\n $options: {},\n components: {},\n computed: {},\n methods: {},\n };\n\n // build new objects by removing keys if already exists (e.g. created by mixins)\n Object.keys(parentData).forEach((e) => {\n if (typeof $data[e] === 'undefined') {\n passthrough.$data[e] = parentData[e];\n }\n });\n Object.keys(parentProps).forEach((e) => {\n if (typeof $props[e] === 'undefined') {\n passthrough.$props[e] = parentProps[e];\n }\n });\n Object.keys(parentMethods).forEach((e) => {\n if (typeof methods[e] === 'undefined') {\n passthrough.methods[e] = parentMethods[e];\n }\n });\n Object.keys(parentComputed).forEach((e) => {\n if (typeof computed[e] === 'undefined') {\n passthrough.computed[e] = parentComputed[e];\n }\n });\n Object.keys(parentComponents).forEach((e) => {\n if (typeof components[e] === 'undefined') {\n passthrough.components[e] = parentComponents[e];\n }\n });\n\n const methodKeys = Object.keys(passthrough.methods || {});\n const dataKeys = Object.keys(passthrough.$data || {});\n const propKeys = Object.keys(passthrough.$props || {});\n const templatePropKeys = Object.keys(this.templateProps);\n const allKeys = dataKeys.concat(propKeys).concat(methodKeys).concat(templatePropKeys);\n const methodsFromProps = buildFromProps(parent, methodKeys);\n const finalProps = merge([\n passthrough.$data,\n passthrough.$props,\n methodsFromProps,\n this.templateProps,\n ]);\n\n const provide = this.$parent.$.provides ? this.$parent.$.provides : {}; // Avoids Vue warning\n\n const dynamic = {\n template: this.template || '
',\n props: allKeys,\n computed: passthrough.computed,\n components: passthrough.components,\n provide: provide,\n };\n // debugger;\n\n return h(dynamic, {...finalProps});\n }\n },\n};\n"],"names":["const","defineDescriptor","src","dest","name","hasOwnProperty","descriptor","Object","getOwnPropertyDescriptor","defineProperty","props","template","String","parent","templateProps","type","default","render","this","$parent","passthrough","$data","$props","$options","components","computed","methods","keys","parentData","forEach","e","parentProps","parentMethods","parentComputed","parentComponents","methodKeys","dataKeys","propKeys","templatePropKeys","allKeys","concat","methodsFromProps","obj","res","prop","finalProps","objs","getOwnPropertyNames","merge","h","provide","$","provides"],"mappings":"8MAEAA,IAAMC,WAAoBC,EAAKC,EAAMC,OAE9BD,EAAKE,eAAeD,GAAO,KACxBE,EAAaC,OAAOC,yBAAyBN,EAAKE,GACxDG,OAAOE,eAAeN,EAAMC,EAAME,WAqBvB,CACbI,MAAO,CACLC,SAAUC,OACVC,OAAQN,OACRO,cAAe,CACbC,KAAMR,OACNS,+BAGJC,qBACMC,KAAKP,SAAU,KACXE,EAASK,KAAKL,QAAUK,KAAKC,iCAEb,kCACE,oCACI,sCAGK,oCACJ,mCACF,UAMvBD,0BAHM,UAGNA,2BAFO,UAEPA,6BADyD,IAAjD,+BAAW,oCAAe,sCAAiB,QAEjDE,EAAc,CAClBC,MAAO,GACPC,OAAQ,GACRC,SAAU,GACVC,WAAY,GACZC,SAAU,GACVC,QAAS,IAIXnB,OAAOoB,KAAKC,GAAYC,iBAASC,QACP,IAAbT,EAAMS,KACfV,EAAYC,MAAMS,GAAKF,EAAWE,MAGtCvB,OAAOoB,KAAKI,GAAaF,iBAASC,QACP,IAAdR,EAAOQ,KAChBV,EAAYE,OAAOQ,GAAKC,EAAYD,MAGxCvB,OAAOoB,KAAKK,GAAeH,iBAASC,QACR,IAAfJ,EAAQI,KACjBV,EAAYM,QAAQI,GAAKE,EAAcF,MAG3CvB,OAAOoB,KAAKM,GAAgBJ,iBAASC,QACR,IAAhBL,EAASK,KAClBV,EAAYK,SAASK,GAAKG,EAAeH,MAG7CvB,OAAOoB,KAAKO,GAAkBL,iBAASC,QACR,IAAlBN,EAAWM,KACpBV,EAAYI,WAAWM,GAAKI,EAAiBJ,UAI3CK,EAAa5B,OAAOoB,KAAKP,EAAYM,SAAW,IAChDU,EAAW7B,OAAOoB,KAAKP,EAAYC,OAAS,IAC5CgB,EAAW9B,OAAOoB,KAAKP,EAAYE,QAAU,IAC7CgB,EAAmB/B,OAAOoB,KAAKT,KAAKJ,eACpCyB,EAAUH,EAASI,OAAOH,GAAUG,OAAOL,GAAYK,OAAOF,GAC9DG,GA1EYC,EA0EsB7B,EAzEtC8B,EAAM,GAyEwCR,EAxE9CN,iBAASe,UAAS3C,EAAiByC,EAAKC,EAAKC,KAC5CD,GAwEGE,WAtFGC,OACPH,EAAM,UACZG,EAAKjB,iBAASa,GACZA,GACEnC,OAAOwC,oBAAoBL,GAAKb,iBAASzB,UACvCH,EAAiByC,EAAKC,EAAKvC,OAG1BuC,EA8EgBK,CAAM,CACvB5B,EAAYC,MACZD,EAAYE,OACZmB,EACAvB,KAAKJ,uBAcAmC,IATS,CACdtC,SAAUO,KAAKP,UAAY,cAC3BD,MAAO6B,EACPd,SAAUL,EAAYK,SACtBD,WAAYJ,EAAYI,WACxB0B,QAPchC,KAAKC,QAAQgC,EAAEC,SAAWlC,KAAKC,QAAQgC,EAAEC,SAAW,IAWlD7C,iBAAIsC,QA7FJH,EAChBC"}
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import {h} from 'vue';
2 |
3 | const defineDescriptor = (src, dest, name) => {
4 | // eslint-disable-next-line no-prototype-builtins
5 | if (!dest.hasOwnProperty(name)) {
6 | const descriptor = Object.getOwnPropertyDescriptor(src, name);
7 | Object.defineProperty(dest, name, descriptor);
8 | }
9 | };
10 |
11 | const merge = (objs) => {
12 | const res = {};
13 | objs.forEach((obj) => {
14 | obj &&
15 | Object.getOwnPropertyNames(obj).forEach((name) =>
16 | defineDescriptor(obj, res, name),
17 | );
18 | });
19 | return res;
20 | };
21 |
22 | const buildFromProps = (obj, props) => {
23 | const res = {};
24 | props.forEach((prop) => defineDescriptor(obj, res, prop));
25 | return res;
26 | };
27 |
28 | export default {
29 | props: {
30 | template: String,
31 | parent: Object,
32 | templateProps: {
33 | type: Object,
34 | default: () => ({}),
35 | },
36 | },
37 | render() {
38 | if (this.template) {
39 | const parent = this.parent || this.$parent;
40 | const {
41 | $data: parentData = {},
42 | $props: parentProps = {},
43 | $options: parentOptions = {},
44 | } = parent;
45 | const {
46 | components: parentComponents = {},
47 | computed: parentComputed = {},
48 | methods: parentMethods = {},
49 | } = parentOptions;
50 | const {
51 | $data = {},
52 | $props = {},
53 | $options: {methods = {}, computed = {}, components = {}} = {},
54 | } = this;
55 | const passthrough = {
56 | $data: {},
57 | $props: {},
58 | $options: {},
59 | components: {},
60 | computed: {},
61 | methods: {},
62 | };
63 |
64 | // build new objects by removing keys if already exists (e.g. created by mixins)
65 | Object.keys(parentData).forEach((e) => {
66 | if (typeof $data[e] === 'undefined') {
67 | passthrough.$data[e] = parentData[e];
68 | }
69 | });
70 | Object.keys(parentProps).forEach((e) => {
71 | if (typeof $props[e] === 'undefined') {
72 | passthrough.$props[e] = parentProps[e];
73 | }
74 | });
75 | Object.keys(parentMethods).forEach((e) => {
76 | if (typeof methods[e] === 'undefined') {
77 | passthrough.methods[e] = parentMethods[e];
78 | }
79 | });
80 | Object.keys(parentComputed).forEach((e) => {
81 | if (typeof computed[e] === 'undefined') {
82 | passthrough.computed[e] = parentComputed[e];
83 | }
84 | });
85 | Object.keys(parentComponents).forEach((e) => {
86 | if (typeof components[e] === 'undefined') {
87 | passthrough.components[e] = parentComponents[e];
88 | }
89 | });
90 |
91 | const methodKeys = Object.keys(passthrough.methods || {});
92 | const dataKeys = Object.keys(passthrough.$data || {});
93 | const propKeys = Object.keys(passthrough.$props || {});
94 | const templatePropKeys = Object.keys(this.templateProps);
95 | const allKeys = dataKeys.concat(propKeys).concat(methodKeys).concat(templatePropKeys);
96 | const methodsFromProps = buildFromProps(parent, methodKeys);
97 | const finalProps = merge([
98 | passthrough.$data,
99 | passthrough.$props,
100 | methodsFromProps,
101 | this.templateProps,
102 | ]);
103 |
104 | const provide = this.$parent.$.provides ? this.$parent.$.provides : {}; // Avoids Vue warning
105 |
106 | const dynamic = {
107 | template: this.template || '
',
108 | props: allKeys,
109 | computed: passthrough.computed,
110 | components: passthrough.components,
111 | provide: provide,
112 | };
113 | // debugger;
114 |
115 | return h(dynamic, {...finalProps});
116 | }
117 | },
118 | };
119 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import App from "./App.vue";
3 |
4 | import testPlugin from "./test.plugin.js"; //testing mixins
5 |
6 | Vue.use(testPlugin);
7 |
8 | new Vue({
9 | render: h => h(App)
10 | }).$mount("#app");
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue3-runtime-template",
3 | "version": "1.0.2",
4 | "description": "Create Vue 3 components by compiling templates on the fly",
5 | "main": "dist/vue3-runtime-template.umd.js",
6 | "scripts": {
7 | "prepublishOnly": "npm run build",
8 | "build": "microbundle index.js",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/mattelen/vue3-runtime-template.git"
14 | },
15 | "keywords": [
16 | "vuejs",
17 | "vue3",
18 | "dynamic",
19 | "runtime",
20 | "template"
21 | ],
22 | "author": {
23 | "name": "Alex J",
24 | "email": "alexjovermorales@gmail.com"
25 | },
26 | "contributors": [
27 | {
28 | "name": "Matt Elen",
29 | "url": "https://github.com/mattelen"
30 | }
31 | ],
32 | "license": "MIT",
33 | "devDependencies": {
34 | "acorn": "^8.0.4",
35 | "microbundle": "^0.11.0"
36 | },
37 | "bugs": {
38 | "url": "https://github.com/mattelen/vue3-runtime-template/issues"
39 | },
40 | "homepage": "https://github.com/mattelen/vue3-runtime-template#readme",
41 | "module": "dist/vue3-runtime-template.es.js",
42 | "unpkg": "dist/vue3-runtime-template.umd.js",
43 | "browser": "dist/vue3-runtime-template.es.js",
44 | "types": "vue3-runtime-template.d.ts",
45 | "dependencies": {
46 | "vue": "^3.0.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/test.plugin.js:
--------------------------------------------------------------------------------
1 | //https://vuejs.org/v2/guide/plugins.html
2 | //https://dev.to/nkoik/writing-a-very-simple-plugin-in-vuejs---example-8g8
3 | // This exports the plugin object.
4 |
5 | import Test from "./Test.vue"
6 |
7 | export default {
8 | // The install method will be called with the Vue constructor as
9 | // the first argument, along with possible options
10 | install(Vue) {
11 | Vue.mixin({
12 | components:{Test},
13 | props: {
14 | testingProp: {
15 | default: "mixinTest: testingProp"
16 | }
17 | },
18 | data() {
19 | return {
20 | testingData: "mixinTest: testingData"
21 | };
22 | },
23 | computed: {
24 | testingComputed() {
25 | return "mixinTest: testingComputed";
26 | }
27 | },
28 | methods: {
29 | testingMethod() {
30 | return "mixinTest: testingMethod";
31 | }
32 | }
33 | }); //end mixin
34 |
35 | Vue.prototype.$testProto = function (str) {
36 | return "mixinTest: testingProto=" + str;
37 | }; //end $testProto
38 |
39 | }
40 | };
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | // vue.config.js
2 |
3 | module.exports = {
4 | runtimeCompiler: true,
5 | configureWebpack: {
6 | resolve: {
7 | alias: {
8 | vue$: "vue/dist/vue.common"
9 | }
10 | }
11 | }
12 | };
--------------------------------------------------------------------------------
/vue3-runtime-template.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'vue3-runtime-template'
2 |
--------------------------------------------------------------------------------