How to convert component string as real component in vue - javascript

Hi i have a requirement for plugin store where i need to load component from core into plugins and inside plugin i need to convert that string into real component so that i can use it.
Note: better approach is most welcome in the view of plugin store inside core
my pseudo logic
get component from specified path through http
convert loaded string into real vue component and store it in a variable
render it in dom
let componentAsString =
`<template>
<div>
<h class="red">{{title}}</h>
<!--<A></A> -->
</div>
</template>
<script>
//import A from './components/A'
export default {
name: 'App',
data(){
return {
title:'Hello World'
}
},
/*components: {
A
}*/
}
</script>
<style lang="scss" scoped>
.red{color:red;}
</style>`;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
</div>

You have chosen very difficult approach to solve the requirement. Main problem is the content of the string - it is essentially a Vue SFC (.vue file). In order to turn this SFC into a Vue component usable in the browser a lot must be done. You must use Webpack (or Rollup or any other bundler), use vue-loader inside to parse the SFC and use different Webpack loaders to process each section of SFC (Babel to transpile the <scipt> block, sass-loader and sass compiler to turn <style lang="scss"> into CSS)
There are tools for doing most of this (with limitations) in the browser like for example vue3-sfc-loader but the cost is huge - vue3-sfc-loader weights around 1.4MB of minified javascript (add Vue itself or potential CSS preprocessor on top of that) and I bet performance of such solution will not be great either
Much easier approach is to use this standard tooling at build time
Just create your components as you normally do - in .vue files
Use your components as Async Components and build a "dictionary" of available components. Those components will be build at build time into separate js files and loaded into a browser on demand (when used)
// ComponentStore.js
export default {
component1: () => import('./components/component1'),
component2: () => import('./components/component2'),
}
Note: process of creating this dictionary can be automated too (inspiration)
Use the component as dynamic component
// DynamicComponent.vue
<template>
<component :is="comp" />
</template>
<script>
import ComponentStore from "ComponentStore.js"
export default {
props: ['componentName'],
computed: {
comp() {
return ComponentStore[this.componentName]
}
}
}
</script>

Related

component structure in Vue

First: I'm using Vue since last night, so the answer is probably obvious.
I find components with that layout:
<template>
<Slider v-model="value"/>
</template>
<script>
import Slider from '#vueform/slider'
export default {
components: { Slider },
}
</script>
<style src="#vueform/slider/themes/default.css" />
but at the same time, I also find components that are structured like a JS object:
app.component('button-counter', {
data() {
return {
count: 0
}
},
template: `
<button #click="count++">
You clicked me {{ count }} times.
</button>`
})
Is there a practical difference? is one preferred? is one more Vue2 vs. Vue3?
The following syntax called SFC single file component :
<template>
...
</template>
<script>
...
</script>
<style src="#vueform/slider/themes/default.css" />
which requires a bundler like webpack or vue cli to be transpiled, the second syntax (your example is based on vue 3) is used to define global component which could work if you're using Vue via CDN,
the first syntax is preferred when you setup a medium/large projects.

VueJs 3 - Use bundled sfc combined with Client Side Rendering

Greetings
Hello fellow Vuers!
So I've got the following situation:
I use ASP.Net Core 3.1 as my server and I would like to use the Vue SFC setup including Typescript support and bind the resulting components into my .cshtml.
Example Usage
Example.vue
<template>
<label :for="name">{{ content }}</label>
<input :id="name" :placeholder="content"/>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
someCode
}),
</script>
<style scoped>
/*some styling*/
</style>
Index.cshtml.cs
public class IndexModel: PageModel{
public string Name { get; set; }
public string Content { get; set; }
}
Index.cshtml
#page
#model Namespace.To.IndexModel
<example :name="#Model.Name" :content="#Model.Content" />
The Question
Is there a way to bundle the Single File Components and then use the Components as needed inside of a .(cs)html?
Preferably I'd like to have each component inside of it's own .js file to load them on demand, but it's not a must have.
Thanks in advance
It is possible. But to clarify, it seems like you want to use the components individually. That means that what you're calling a SFC/component, will need to be treated as its own Vue app.
Assuming that's the case, instead of making the components bundled separately you'll need to create a vue app for each one, and individually export them.
You will need to decide how/when to mount them. I've relied on a more manual way of mounting, which requires a line of js to link the DOM element with the widget and pass the attributes. Alternatively you can rely on the DOM tag only. Admittedly, the js way is a bit more verbose, but less prone to edge cases.
Here is the example for the js way
components/example/index.js:
import Example from './Example.vue';
export const mountExample = (el, props) =>
Vue.createApp(el, props);
Then will wrap the component in a function that allows you to pass the DOM element to use and the props.
You would need
<script src="vue.js"/><!-- if it's not bundled in there -->
<script src="example.js"/>
<div id="example" />
<script>
mountExample('#example', {name:"#Model.Name", content="#Model.Content});
</script>
The other way (without the js instantiation) would be to wrap it in a function (IIFE) that looks for <example> tags, parses the content and then mounts the app with the provided parameters. It's quite a bit more work than the other example, but shouldn't be terribly complex.
So for the Example example, I'd organize it something like this: example
/components/example/
|-- Example.vue
|-- index.js
and then use webpack chaining via vue.config.js to do multiple of these
module.exports = {
// tweak internal webpack configuration.
// see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
chainWebpack: config => {
// remove the standard entry point
config.entryPoints.delete('app')
// then add your own
config.entry('example')
.add('./src/components/example/index.js')
.end()
.entry('menu')
.add('./src/components/menu/index.js')
.end()
}
}
A caveat; I've used rollup to generate these and I haven't tested this, but webpack should work too
resources for the webpack config:
https://cli.vuejs.org/guide/webpack.html#simple-configuration
https://github.com/neutrinojs/webpack-chain

Nuxtjs plugin registration

I am curious as to the methodology Nuxt.js uses to register a plugin. I have been reading the documentation for Nuxt.js and I am slightly confused as to the registration methodology.
I do not want to register plugins such as vue-flag-icon globally.
My understanding is when we register the plugin we use the plugin folder as such:
import Vue from 'vue'
import FlagIcon from 'vue-flag-icon'
Vue.use(FlagIcon)
I can now use the flag component anywhere in my app - I dont want this!!!
I want to be able to load plugins into the components that need them ONLY.
I have tried loading them as a component like:
components:{
'flag': ()=> import('path to plugin') // #/plugins/vue-flag-icon
}
This does not work.
I changed my plugins script to:
import Vue from 'vue'
import FlagIcon from 'vue-flag-icon'
export default () => {
Vue.use(FlagIcon)
}
And then tried to register the plugin within the components like so:
import flag from '#/plugins/vue-flag-icon';
created(){
flag()
}
My questions really are:
How can I register a plugin within the component without importing the vue instance? (I think is called a bus)
Is it bad practice to import the plugins directly into components?
Is registering all the plugins within nuxt.config.js creating a larger download file for users to download (example: registering vue-twix is not necessary on pages that do not have textareas) or will nuxt/webpack handle the removal of unnecessary plugins on a page by page or component by component basis (so I don't have to even worry about this)?. If this is the case than I dig nuxt.
Thanks
If you want to use FlagIcon only on certain components, you have to import it and use it on every component you want to use.
<template>
<flag iso="ca" />
</template>
<script>
import FlagIcon from 'vue-flag-icon'
export default () => {
components: {
FlagIcon
}
</script>
This should work.
For other components, remember to import any style sheets the component might require:
<style lang="scss" scoped>
#import 'path/to/plugin/style.css';
</style>

Using Vue Components in Angular

I have a project that is built in Vue and I want to reuse the components from the Vue application in an Angular application so I don't have to go and rebuild every single component from scratch.
I saw this tutorial on medium: How to use Vue 2.0 components in an angular application, but that tutorial is for AngularJS.
I'm wondering if anyone has done this before, if it's worth it and if anyone knows of any tutorials or reference material.
Wrap your Vue components as native Web Components.
Since Angular supports using custom Web Components, you'll be able to use the Vue components (wrapped as Web Components).
To Angular it doesn't make a difference if the custom Web Components were generated by Vue or not (for all Angular knows, they could be native HTML elements).
Demo
Runnable DEMO here.
The demo is an Angular 5 app. The Vue custom component is defined in index.html. Notice how in app/app.component.html it is used directly in the template, as if it were a native element.
Step by step below.
In Vue
Use vue-custom-element to wrap your Vue components as Web Components:
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vue-custom-element#3.0.0/dist/vue-custom-element.js"></script>
<script>
const MyVueWebComp = {
props: ['msg'],
template:`
<div style="border: 3px dashed green; padding: 5px">
I am my-vue-web-comp.<br>
Value of "msg" prop: {{ msg }}<br>
<input v-model="text"><button #click="addText">Click me</button>
<div v-for="t in texts">
Text: {{ t }}
</div>
</div>
`,
data() {
return {
text: '',
texts: []
};
},
methods: {
addText() {
this.texts.push(this.text);
this.text = '';
}
}
};
Vue.customElement('my-vue-web-comp', MyVueWebComp);
</script>
That will create a <my-vue-web-comp> web component that can be used directly in the DOM, without the need to have a working Vue instance.
The above is just a demo runnable directly in the browser. If you have .vue files and a vue-cli app, you'll need to do npm install vue-custom-element --save and then create a .js file like:
import Vue from 'vue';
import vueCustomElement from 'vue-custom-element';
import MyElement from './MyElement.vue';
Vue.use(vueCustomElement);
Vue.customElement('my-element', MyElement);
And then this, when bundled, will generate a .js file that can be imported directly as a single <script> tag, instead of the whole code and script tags above.
For more details, check vue-custom-element's docs.
In Angular
Now, in the Angular app, after importing the Web Components (being them Vue-generated or not), configure them to be used by Angular by adding schemas: [CUSTOM_ELEMENTS_SCHEMA] in your #NgModule:
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';
//...
#NgModule({
// ...
schemas: [
CUSTOM_ELEMENTS_SCHEMA // added this
]
})
export class AppModule {
Now use the Web Components (generated from Vue or not) directly in Angular templates. E.g. the component defined in the code above could be used like:
<my-vue-web-comp [msg]="name"></my-vue-web-comp>
In fact, the runnable demo shows an example of that usage.
Limitations
You may need polyfills for older browser support. Please check vue-custom-element's docs for more details.

How to import vuejs component dependencies in a MPA?

In a single page app, I can do this to include a component inside a component.
$ npm install sagalbot/vue-select
<template>
<div id="myApp">
<v-select :value.sync="selected" :options="options"></v-select>
</div>
</template>
<script>
import vSelect from "vue-select"
export default {
components: {vSelect},
data() {
return {
selected: null,
options: ['foo','bar','baz']
}
}
}
</script>
How can I do this in a MPA, where I have bunch of js files or sometimes inline javascript in different pages?
I am not using any build system.
I would highly recommend using vue-cli, but if for some reason that is not possible, then I believe,though I have never tried it, you would basically need to add all your components and code into a single long js file, or include them in the right order in your html documents.
Certain component libraries can work this way, like vuetify. You simply include the whole vuetify.js file after vue.js and then you can use all the components available.
I think it would be quite a lot of work to do anything of much size, but if it is something really small you could add components in the following manner, one after another.
var componentTemplate =
`
// Template code..
`;
Vue.component('my-cool-component', {
template: componentTemplate,
data: function() {
return {
//
}
}
});

Categories

Resources