I'm migrating from Vue 2 to Vue 3. In Vue 2, it's possible to register a component globally like this: main.js
new Vue({
el: '#app'
})
A global registration of a component: my-component.js
Vue.component('my-component', {
template: '<div>Hi!</div>'
})
I'm using Webpack for import Single File Components in other components, and then i'm bundling it in one file. With Vue 2, that was easy because Vue instance was globally registered. Now with Vue 3, that doesn't work any more because of Vue.createApp({}).mount('#app'). I was trying to do something like this: main.js
const app = createApp({});
export const app;
And in: my-component.js
import { app } from './main.js';
app.component('my-component', {
template: '<div>Hi!</div>'
})
And at the end: close-app.js
import { app } from './main.js';
app.mount('#app');
And in: index.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.5/vue.global.js"></script>
<script type="application/javascript" src="my-component.js"></script>
<div id="app">
<my-component></my-component>
</div>
<script type="application/javascript" src="close-app.js"></script>
I'm importing the app because of Webpack. Webpack is bundling it in self-invoking functions, but that doesn't work. I know there is a way to declare it globally like this: window.app = app;, but that's not a good idea. Can someone help me with that?
Components Webpacks
Since Vue 3 component registration has to be invoked on an app instance, and you're importing each component Webpack individually, I don't think you can avoid globals. Using a global app instance (window.app) in your components might be the easiest solution, especially if you want to minimize the changes.
Alternatively, you could build the components as UMD modules, where the component definition is exported as a global, import the UMD module with the <script> tag (as you're already doing), and call app.component() for each of them:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.5/vue.global.js"></script>
<!-- sets MyComponent global -->
<script type="application/javascript" src="./my-component.umd.js"></script>
<div id="app">
<my-component></my-component>
</div>
<script>
const app = Vue.createApp({})
app.component(MyComponent.name, MyComponent)
app.mount('#app')
</script>
Component Module Scripts
In main.js, use createApp from the global Vue that you've imported in the <script> tag:
export const app = Vue.createApp({})
Then import your scripts as modules with <script type="module">:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.5/vue.global.js"></script>
<script type="module" src="./my-component.js"></script>
<div id="app">
<my-component></my-component>
</div>
<script type="module" src="./close-app.js"></script>
demo
I have been using "element-ui" and now moving forward to new version of Vue3.
Seems they published a new version called "element-plus" but the tutorial is not updated.
import Vue from 'vue'; // not working in Vue3
import ElementUI from 'element-plus';
import 'element-ui/lib/theme-chalk/index.css';
...
Vue.use(ElementUI); // no "Vue" in Vue3 anymore
...
createApp(App).mount('#app') // the new project creation
https://element-plus.org/#/en-US/component/quickstart
Anyone manged to do it right and it works?
If you are using vue 3 you need to import createApp as well as css from 'element-plus/...' folder. Then you instance your app using the vue function imported, basically you pass your main app component to the function as an argument:
import { createApp } from 'vue'
import App from './YourMainApp.vue'
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
let app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
You can also do it very easy without any js bundler.
Here is a sample:
var Main = {
data() {
return {
message: 'Hello World!'
}
},
methods: {
click() {
console.log('click()');
}
}
};
const app = Vue.createApp(Main);
app.use(ElementPlus);
app.mount("#app")
<html>
<head>
<link rel="stylesheet" href="//unpkg.com/element-plus/theme-chalk/index.css">
</head>
<body>
<script src="//unpkg.com/vue#next"></script>
<script src="//unpkg.com/element-plus/dist/index.full.js"></script>
<div id="app">
<el-button type="primary" size="medium" #click="click">{{message}}</el-button>
</div>
</body>
</html>
Note: Can we write vue.js large application without using any compiler for code like currently i see all example use webpack now to make vue.js code compatible for browser .
I want make vue.js application without webpack and without using .vue extension. Is it possible? if it is possible, can you provide a link or give sample how to use routing in that case.
As we make component in .vue extension can be make component in .js extension and use application as we do in angular 1 where we can make whole app without any trans-compiler to convert the code.
Can be done that in html , css , js file only and no webpack sort of thing.
What i have done .
index.js
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>vueapp01</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
main.js this file added in webpack load time
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
Hello route
Helloworld route
{{route}}
<router-view/>
<!-- <hello></hello> -->
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
route : "This is main page"
}
}
}
</script>
router
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '#/components/HelloWorld'
import Hello from '../components/Hello'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/hello',
name: 'Hello',
component: Hello
}
]
})
I have done something like this . Can we do this by just html , css , js file only with not webpack to compile code . Like we do in angular 1 .
Thanks
As stated in this jsFiddle: http://jsfiddle.net/posva/wtpuevc6/ , you have no obligation to use webpack or .vue files.
The code below is not from me and all credit goes to this jsFiddle creator:
Create an index.html file:
<script src="https://npmcdn.com/vue/dist/vue.js"></script>
<script src="https://npmcdn.com/vue-router/dist/vue-router.js"></script>
<script src="/js/Home.js"></script>
<script src="/js/Foo.js"></script>
<script src="/js/router.js"></script>
<script src="/js/index.js"></script>
<div id="app">
<router-link to="/">/home</router-link>
<router-link to="/foo">/foo</router-link>
<router-view></router-view>
</div>
Home.js
const Home = { template: '<div>Home</div>' }
Foo.js
const Foo = { template: '<div>Foo</div>' }
router.js
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: Home },
{ path: '/foo', component: Foo }
]
})
index.js
new Vue({
router,
el: '#app',
data: {
msg: 'Hello World'
}
})
Appreciate the framework...
Just a sidenote: .vue files are really awesome, you should definitely try them if not using them is not a requirement
I have started learning vue.js also and I am not familiar with webpack and stuff and I also wanted to still separate and use .vue files as it makes management and code cleaner.
I have found this library:
https://github.com/FranckFreiburger/http-vue-loader
and a sample project using it:
https://github.com/kafkaca/vue-without-webpack
I am using it and it seems to work fine.
You perfectly can, but with a lot of disadvantages. For example: you cannot easily use any preprocessor, like Sass or Less; or TypeScript or transpile source code with Babel.
If you don't need support for older browser, you can use ES6 modules today. Almost all browsers support it. See: ES6-Module.
But Firefox doesn't support dynamic import(). Only Firefox 66 (Nightly) support it and need to be enabled.
And if that wasn't enough, your web application will not be indexed. It's bad for SEO.
For example, Googlebot can craw and index Javascript code but still uses older Chrome 41 for rendering, and it's version don't support ES6 modules.
If that are not disadvantages for you, then you can do this:
Remove any thirty party library import like Vue, VueRouter, etc. And include those in the index.html file using script tags. All global variables are accesible in all es6 modules. For example, remove this line from main.js and all .vue files:
import Vue from 'vue';
And add this line in your index.html:
<script src="https://npmcdn.com/vue/dist/vue.js"></script>
Rewrite all .vue files and change file extension to .js. For example, rewrite something like this:
<template>
<div id="home-page">
{{msg}}
</div>
</template>
<script>
export default {
data: function() {
return { msg: 'Put home page content here' };
}
}
</script>
<style>
#home-page {
color: blue;
}
</style>
to something like this:
let isMounted = false; /* Prevent duplicated styles in head tag */
export default {
template: `
<div id="home-page"> /* Put an "id" or "class" attribute to the root element of the component. Its important for styling. You can not use "scoped" attribute because there isn't a style tag. */
{{msg}}
</div>`,
mounted: function () {
if (!isMounted) {
let styleElem = document.createElement('style');
styleElem.textContent = `
#home-page {
color: blue;
}
`;
document.head.appendChild(styleElem);
isMounted = true;
}
},
data: function () {
return {
msg: 'Put home page content here'
};
}
}
It is all. I put an example in this link
P.S. Text editing without syntax highlighting can be frustrating. If you use Visual Studio Code you can install Template Literal Editor extension. It allows editing literal strings with syntax highlight. For styles select CSS syntax, and for templates HTML syntax. Unknown tag in HTML are highlighted differently. For solve this, change the color theme. For example, install Brackets Dark Pro color theme or any theme do you like.
Regards!
For sure you can. We did a project with Vue, and we had couple of problems during compiling .vue files.
So we switched to structure with three separate files.
But be aware that you need webpack anyway. The idea of Vue was to split huge projects into components, so using template inside .js file it's pretty normal.
So take a look at
html-loader
And
css-loader
Using these modules you can write something like this:
component.js
// For importing `css`. Read more in documentation above
import './component.css'
// For importing `html`. Read more in documentation above
const templateHtml = require('./component.html')
export default {
name: 'ComponentName',
components: { /* your components */ },
mixins: [/* your mixins */ ],
template: templateHtml,
computed: .....
}
component.css
#header {
color: red
}
component.html
<div id="header"></div>
BUT
You need to know that HTML file should be written in the same way as I you will have it in template property.
Also, take a look at this repo, maybe you will find something useful here
Vue-html-loader. It is a fork from html-loader by Vue core team.
In vuejs 3 you you can do it in an ES6 modular fashion (no webpack or other tools required):
index.html
<!DOCTYPE html>
<html>
<head>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue#3.0.11/dist/vue.esm-browser.js",
"vue-router": "https://unpkg.com/vue-router#4.0.5/dist/vue-router.esm-browser.js",
"html" : "/utils/html.js"
}
}
</script>
<script src="/main.js" type="module"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
main.js
import { createApp, h } from 'vue';
import {createRouter, createWebHashHistory} from 'vue-router';
import App from './components/App.js';
const routes = [//each import will be loaded when route is active
{ path: '/', component: ()=>import('./components/Home.js') },
{ path: '/about', component: ()=>import('./components/About.js') },
]
const router = createRouter({
history: createWebHashHistory(),
routes,
})
const app = createApp({
render: () => h(App),
});
app.use(router);
app.mount(`#app`);
components/App.js
import html from 'html';
export default {
name: `App`,
template: html`
<router-link to="/">Go to Home</router-link>
<router-link to="/about">Go to About</router-link>
<router-view></router-view>
`};
components/Home.js
import html from 'html';
export default {
template: html`
<div>Home</div>
`};
components/About.js
import html from 'html';
export default {
template: html`
<div>About</div>
`};
utils/html.js
// html`..` will render the same as `..`
// We just want to be able to add html in front of string literals to enable
// highlighting using lit-html vscode plugin.
export default function () {
arguments[0] = { raw: arguments[0] };
return String.raw(...arguments);
}
Notes:
Currently (04/2021) importmap works only on chrome (firefox in progress). To make the code compatible with other browsers also, just import (on each .js file) the dependencies directly from the urls. In this case though vue-router.esm-browser.js still imports 'vue', so you should serve an updated version of it, replacing import { .... } from 'vue' with import { .... } from 'https://unpkg.com/vue#3.0.11/dist/vue.esm-browser.js'
To avoid waterfall loading effect, you can add <link rel="modulepreload" href="[module-name]"> entries to index.html to start preloading some or all modules asynchronously before you need them.
A Related article
Vue can be included on a single html page quite simply:
Vue 3 minimal example:
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<div id="app">{{ message }}</div>
<script>
const { createApp } = Vue
createApp({
data() {
return {
message: 'Hello Vue!'
}
}
}).mount('#app')
</script>
Vue 2 minimal example, with Vuetify
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#6.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<div id="app">
<v-app>
<v-main>
<v-container>Hello world</v-container>
</v-main>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<script>
new Vue({
el: '#app',
vuetify: new Vuetify(),
})
</script>
</body>
</html>
vue 2 guides:
https://v2.vuejs.org/v2/guide/installation.html#CDN
https://vuetifyjs.com/en/getting-started/installation/#usage-with-cdn
vue 3 guide: https://v2.vuejs.org/v2/guide/installation.html#CDN
I have the following code in my .vue file:
<template>
<p>hello search</p>
</template>
<script>
import Vue from 'vue';
var vm = new Vue({
el: '#js-quick-search'
})
</script>
and in my .html I have a the element for Vue instance
<div id="js-quick-search"></div>
However, the template part is completely ignored. How can I attach it to the instance without adding it inside the script tag?
Basically I want to achieve the same as this:
<script>
import Vue from 'vue';
var vm = new Vue({
el: '#js-quick-search',
template: '<p>whatever</p>'
})
</script>
but without hard-coding template inside the script.
Your markup inside the script tag is wrong. To create a template, you'd have to export the script, like so:
<template>
<div class="MyTemplate">
Your template
</div>
</template>
<script>
export default {
name: "MyTemplate"
}
</script>
To then use the template, just import it (import MyTemplate from './MyTemplate.vue') and add it to your components (components: { MyTemplate }) then place it in as <myTemplate>)
I created a hello.vue file, now how to use this in a html file? I already setup a webpack,
<template>
<p>Hello</p>
<p>{{message}}</p>
</template>
<script>
module.exports = {
data: {
message: 'hello'
}
}
</script>
<style>
p {
font-size: 14px
}
</style>
How do you want to use it?
Taking demonstation from official example: vue-hackernews-2.0. This is a component, so you import the component in another vue file like this:
import Comment from '../components/Comment.vue'
and you add in the list of components in that vue instance:
components: { Spinner, Comment },
Than you can use it in HTML like this:
<comment v-for="id in item.kids" :key="id" :id="id"></comment>
You just have to include your bundled .js file in your HTML file and include mounter div - so Vue could know where to execute the app.
Your index file could looks something like this (showing only body section)
...
<body>
<div id="app"></div>
<script src="bundle.js">
</body>
...
Your main Vue file could looks like this:
import Vue from 'vue'
import Hello from 'hello.vue'
const app = new Vue({
render: (h) => h(Hello)
}).$mount('#app')
And in this way you can store all other components into the hello.vue.
This is probably way that you should use when you are building SPA.