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.
Related
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>
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.
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 {
//
}
}
});
I've been working on porting a vue.js component from vue 1.0 to Vue 2.0 using Vueify. In the Starter resources it states:
When you use vue-loader or vueify to import *.vue files, their parts are automatically compiled into render functions. It is therefore recommended to use the runtime-only build with *.vue files.
However, this does not appear to be the case. If I have a simple component like:
<template>
<div>
{{ msg }}
</div>
</template>
<script type="text/javascript">
export default {
props: {
msg: {
default: "Child Message"
}
}
}
</script>
And in my main.js file I do:
import Vue from 'vue'
import MyComponent from './my-component.vue';
Vue.component('my-component', MyComponent);
new Vue({
el: '#app',
render: function(createElement) {
return createElement(MyComponent)
}
});
Then compile with Gulp using:
browserify('./main.js')
.transform(vueify)
.bundle()
.pipe(fs.createWriteStream("bundle.js"))
I cannot do anything at all with the component except get it to render. In fact, it will actually render the component as soon as it finds the div with the id "app":
<div id="app">
<!-- my-component renders even though I didn't ask it to -->
</div>
And any props added to the component are not received, so:
<div id="app">
<!--
Message displays as default "Child Message" rather than "Parent Message". The prop wasn't passed
-->
<my-component msg="Parent Message"></my-component>
</div>
Similarly, if I add data to main.js, it's not accessible from the web page:
import Vue from 'vue'
import MyComponent from './my-component.vue';
Vue.component('my-component', MyComponent);
new Vue({
el: '#app',
render: function(createElement) {
return createElement(MyComponent)
},
data() {
return {
msg: "Parent Message"
}
}
});
in HTML:
<div id="app">
{{ msg }} // This will not print
</div>
And anything inside "#app" doesn't render at all (remember "my-component" is rendered even if I don't add it):
<div id="app">
<!-- This doesn't render-->
<strong>A component </strong>
<my-component></my-component>
</div>
So it looks to me like you can render a component, without any control over it, and you cant do anything further with the view model, so is it really the case that I should be using the runtime-only build as suggested?
In the end I've used the standalone build using aliasify and everything works fine, but I'd really like to know what it is I am missing when using vueify with the runtime build. Surely the behavior I'm describing isn't what is supposed to happen, so I can only assume I have misunderstood something somewhere.
Doing some tests the problem is in your default render function:
render: function(createElement) {
return createElement(MyComponent)
}
It's overriding the main Vue file's render function and creating a base MyComponent inserting it into the body.
When I removed the render function the prop fired.
jsFiddle Try that, just uncomment the render function to see what I mean.
The render function is meant to replace html templating by allowing you to have more control and utilize other template options.
Using Vue (^2.0.0-rc.6) + Browserify, entry point is index.js:
import Vue from 'vue'
import App from './containers/App.vue'
new Vue({ // eslint-disable-line no-new
el: '#root',
render: (h) => h(App)
})
App.vue:
<template>
<div id="root">
<hello></hello>
</div>
</template>
<script>
import Hello from '../components/Hello.vue'
export default {
components: {
Hello
}
}
</script>
<style>
body {
font-family: Helvetica, sans-serif;
}
</style>
Hello.vue:
<template>
<div class="hello">
<h1>\{{ msg }}</h1>
</div>
</template>
<script>
export default {
data () {
return {
msg: 'Hello Vue!'
}
}
}
</script>
Blank white screen, did I miss something?
EDIT:
The entry html is just <div id="root"></div>, no errors on console logs, and I'm pretty sure Hello.vue is loaded since console.log('test') that file appears on console.
EDIT 2:
Found the error:
[Vue warn]: You are using the runtime-only build of Vue where the
template option is not available. Either pre-compile the templates
into render functions, or use the compiler-included build. (found in
anonymous component - use the "name" option for better debugging
messages.)
Does this mean I have to use webpack solution? Cannot use standard HTML?
SOLUTION:
Import Vue from 'vue/dist/vue.js'
Just to make life easier for folks looking for the answer:
import Vue from 'vue/dist/vue.js'
import App from './App.vue'
new Vue({
el: '#app',
render: h => h(App)
})
From the author -- 2.0 standalone build means (compiler + runtime). The default export of the NPM package will be runtime only, because if installing from NPM, you will likely pre-compile the templates with a build tool.
If you are using a build tool like browserify or Webpack, you can most probably use single file components to avoid such errors (in single file components the templates are automatically compiled to render functions by vueify). You definitely should try to avoid templates anywhere else. Check the forum and documentation for answers about how to avoid them.
But I know from my own experience that it is not always easy to find the templates in your project, that are causing the error message. If you are having the same problem, as a temporary workaround, the following should help:
You should not import 'vue/dist/vue.js' (check the documentation: https://github.com/vuejs/vue/wiki/Vue-2.0-RC-Starter-Resources#standalone-vs-runtime-builds why not)
Instead you should handle that in the build tool you are using.
In my case, I'm using browserify where you can use aliasify for creating the alias. Add the following to your package.json file:
{
// ...
"browser": {
"vue": "vue/dist/vue.common.js"
}
}
for Webpack users it seems you have to add the following to your config:
resolve: {
alias: {vue: 'vue/dist/vue.js'}
},
More information can be found in the documentation: https://v2.vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
For Vue 3.4.0 You can add a new file at the root directory of the project named
vue.config.js and add the following into it.
module.exports = {
runtimeCompiler: true
}
Next time when you start the app you can see
Compiled successfully in 204ms
20:46:46
App running at:
With Brunch I resolved this by adding this rule in brunch-config.js:
npm: {
aliases: {
vue: "vue/dist/vue.js"
}
}
see http://brunch.io/docs/config#npm
It was to build a Vue component with an inner <template>:
<template>
<div> hello </div>
</template>
<script>
export default {
name: 'Hello',
props: {
title: String,
},
}
</script>