Vuejs different kinds of entry points are confusing - vue.js

I created two Vuejs project.
The 1st one main.js looks like this:
import Vue from 'vue'
import App from './App.vue'
import BootstrapVue from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
The second one looks like this:
import Vue from "vue";
import App from "./App";
import router from "./router";
import BootstrapVue from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
Vue.use(BootstrapVue);
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: "#app",
router,
components: { App },
template: "<App/>"
});
please someone explain me the difference between this codes espacially the the new vue instance creation in two differnt ways?

For The 1st one main.js:
First you must understand all the render:
The render: h => h(App) is shorthand for:
render: function (createElement) {
return createElement(App);
}
Which can be shortened to:
render: (createElement) => {
return createElement(App);
}
Which can again be shortened to (with h being an alias to createElement as noted above):
render: (h) => {
return h(App);
}
Which is then shortened further to (using ES6 "fat arrow" syntax):
render: h => h(App);
The H, It comes from the term "hyperscript", which is commonly used in many virtual-dom implementations. "Hyperscript" itself stands for "script that generates HTML structures" because HTML is the acronym for "hyper-text markup language".
And the $mount allows you to explicitly mount the Vue instance when you need to. This means that you can delay the mounting of your vue instance until a particular element exists in your page or some async process has finished, which can be particularly useful when adding vue to legacy apps which inject elements into the DOM, I've also used this frequently in testing when I've wanted to use the same vue instance across multiple tests:
// Create the vue instance but don't mount it
const vm = new Vue({
template: '<div>I\'m mounted</div>',
created(){
console.log('Created');
},
mounted(){
console.log('Mounted');
}
});
// Some async task that creates a new element on the page which we can mount our instance to.
setTimeout(() => {
// Inject Div into DOM
var div = document.createElement('div');
div.id = 'async-div';
document.body.appendChild(div);
vm.$mount('#async-div');
},1000)
For The second one, I strongly recommend you to look over the current Vue documentation:
https://v2.vuejs.org/v2/guide/instance.html
Having all of your template code in an App.vue (and none in your index.html’s #app div) allows us to use the runtime-only version of Vue which is smaller than the full version.
but lets break it up:
el: '#app', will look in your index.html file for a div <div id="app"></div>;
the router, will allow you to use globally the router;
components: { App }, import your App.vue, and all component you have imported there, generally you put in this file people often put: side bar components, headers components, navigable stuff;
4.template: "<App/>", will create a div in you HTML with the id="app" only after it import you App.vue components imported there or HTML created in this file, all the content from you files will be wrapped by this div. People often use <router-view> to load the router pages components.
This second instance have the purpose of Having a cleaner index.html and having all the stuff in the App.vue

Related

Created Lifecycle Hook of global vue instance

I want to be able to use the AOS library globally on my vue project.
This is for Vue 2.
new Vue({
created () {
AOS.init()
},
render: h => h(App),
}).$mount('#app');
The Vue 3 sets up the app a little bit different.
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
I dont have that created option with the Vue 3 setup. I tried this, but it´s more of a guessing game...
createApp({App, AOS.init()})
But do I make this work in Vue 3?
You can still do that in Vue 3. Note h() is now imported as a global function from vue instead of being an argument of render().
Here's the equivalent Vue 3 code:
import { createApp, h } from 'vue'
import App from './App.vue'
createApp({
created() {
AOS.init()
},
render: () => h(App),
}).mount('#app')
You could use the created hook of the root component. To me that has always seemed like an appropriate place to initialize application-wide libraries.

How to add name attribute in vue component with an error?

I get an error on the screenshot.
How can I provide the name attribute on this code in my app.js?
app.js
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('table-logs', require('./components/TableLogs.vue').default);
const app = new Vue({
el: '#app'
});
TableLogs.vue
<template>
<vuetable ref="vuetable"
api-url="https://vuetable.ratiw.net/api/users"
:fields="['name', 'nickname', 'email', 'gender']"
data-path=""
pagination-path="">
</vuetable>
</template>
<script>
import Vuetable from 'vuetable-2'
export default {
components: {
Vuetable
}
}
</script>
Provide the "name" attribute in your component.
`
import Vuetable from 'vuetable-2'
export default {
name: 'myTestComponent',
components: {
Vuetable
}
}
`
I'm not familiar with how Laravel and Vue work together but in a typical Vue CLI generated project, you add your root component using a render function. For example
<div id="app"></div>
// app.js
require('./bootstrap'); // I imagine this is required
import TableLogs from './components/TableLogs.vue'
new Vue({
render: h => h(TableLogs),
}).$mount('#app')

How to properly inject app element in webpack? - Receiving [Vue warn]: Cannot find element: #app

Here is my code code example
I am trying to learn webpack 4 and am setting up a test project.
Traditionally I have built vuejs app inside Asp.net websites. So I always know the entry html point and can put the element on the page.
From all the blog post I have seen for vue this seems to be all they do to setup their app.
App.Vue
<template>
<div id='app'>
<router-view></router-view>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
#Component
export default class App extends Vue {
}
</script>
index.ts
import Vue from 'vue';
import App from './App.vue';
import router from './router';
Vue.config.productionTip = false;
new Vue({
el: '#app',
render: (h) => h(App),
router
}).$mount('#app');
When I run this I get [Vue warn]: Cannot find element: #app. If I add
document.write('<div id="app"><router-view></router-view></div>');
The code runs fine. Since I am using vue-router, I don't think I actually need the App.vue file, but I still need someplace to mount the vue object too.
So looking at my github link, what would be the correct way to get this working?
This is a chicken-and-egg problem. You're trying to amount the root component to the #app div, but the #app div exists inside the App component. At the time when you call new Vue the #app div doesn't exist because the App component hasn't mounted!
Most Vue apps have an empty <div id="app"></div> in the index.html file so that the root Vue component has somewhere to mount to when the page has loaded.
If you don't want to do it that way then you can mount it manually instead:
const root = new Vue({
render: (h) => h(App),
router
}).$mount()
document.body.appendChild(root.$el)

When should I use a render function?

By the docs I do not fully understand when I should use render: h => h(App) function.
For example I have very simple Vue app:
import Vue from 'vue'
import App from './App.vue'
new Vue({
el: '#app',
components: { App }
})
What is the case when I need add to code: render: h => h(App)?
In the example you posted, App.vue represents the main app wrapper - all related .vue component files would be imported there.
So in your Vue instance you defined the components object, and added the App component, but how would you exactly mount that component to the instance and display it?
A couple of things to keep in mind:
This is not a .vue file, so you don't have a template tag option. This is a pure .js file
You can't put <App></App> into the template property because you are using runtime only build so the template option is not available
One option is using render functions. It's what Vue.js does under the hood. It takes your template and then template compiler converts it to render functions.
Alternatively, instead of a render function, you can the use spread operator:
import Vue from 'vue'
import App from './App.vue'
new Vue({
el: '#app',
...App
})
From the docs:
Vue recommends using templates to build your HTML in the vast majority
of cases. There are situations however, where you really need the full
programmatic power of JavaScript. That’s where you can use the render
function
You can simply do this:
import Vue from 'vue'
import App from './App.vue'
new Vue({
el: '#app',
components: { App },
template: '<App/>'
})

Need an example vue-router (vue 2.x) for a Layout.vue with other route based components

I cannot figure out how to set this up properly using vue-router with vue.js 2.x
I want App.vue to be a main site layout module which contains basic site level things like footer, logo, main nav, etc.
A route based architecture which will load components based on the route inside this App.vue
ie: /things to show list and /things/:id to show individual item
I'm using the webpack template from vue-cli
I'm confused about main.js vs. App.vue should I be moving the routes out of main.js into App.vue?
Can someone link to a simple hello world using layouts in vue-router?
import Vue from 'vue'
import App from './App'
import Items from './components/Items'
import Item from './components/Item'
import Axios from 'axios'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
Vue.prototype.$http = Axios
const routers = new VueRouter([
{ path: '/items/:id', component: Item },
{ path: '/', component: Items }
])
// how to specify App.vue as a layout?
new Vue({
routes
}).$mount('#app')
I think this should work for you
const app = new Vue({
router,
render: (h) => h(App)
}).$mount('#app')
or spread operator
const app = new Vue({
router,
...App
}).$mount('#app')
As I mentioned in comment, take look at the repo that I created https://github.com/bedakb/vuewp/tree/master/public/app/themes/vuewp/app
I had wrong property name:
new Vue({
router,
...App
}).$mount('#app')
This fixes it. I had imported it as routes not router. Another way to fix would have been { router: routes } but I renamed the file to router and now everything works.
Big thanks to #belmin for hoping on screenhero to try and help me fix it!