What is the purpose of 'main.js' and 'App.vue' in a Vue.js application? - vue.js

I don't understand the exact purpose of each file.
Suppose I want to add authentication code. Where should I place it, in main.js or App.vue?

I believe you might be missing on some of the basics behind the structure of Vue.js and where and/or how to put in functionality like authentication. It might be worth going through their introduction again to solidify your knowledge.
To answer more directly, when you run a Vue.js application you need to have a basic HTML page (like index.html) as an entry point and the initialisation for your Vue.js application loaded in a <script> in that page.
When you write a Vue.js application you can choose to do it in pure JavaScript, in TypeScript or in the .vue component format which combines the HTML, CSS and JavaScript you need to define components.
The vue format is not run directly. It has to be transpiled into plain JavaScript by the Vue-CLI/builder and packed using a packager like Webpack first and then loaded by your entry point. Luckily, the Vue.js CLI handles nearly all of this process so you can get on with building.
File App.vue
This is typically the root of your application defined in Vue.js Component file format. It's usually something that defines the template for your page:
<template>
<div id="app">
<SideBar />
<router-view v-if="loaded" />
</div>
</template>
<script>
import SideBar from "./pages/SideBar";
export default {
components: { SideBar },
computed: {
loaded() {
return this.$store.state.loadState == "loaded";
}
}
};
</script>
File main.js
This is usually the JavaScript file that will initialise this root component into a element on your page. It is also responsible for setting up plugins and third-party components you may want to use in your app:
import Vue from "vue";
import { store } from "./store/store";
import router from "./router";
import App from "./App.vue";
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
File index.html
The index page provides your entry point in HTML providing an element for Vue.js to load into and imports file main.js to initialise your application.
<!-- The HTML element that hosts the App.vue component -->
<div id="app"></div>
<!-- Built files will be auto injected -->
<script type="text/javascript" src="main.js"></script>
On another note, a decent place to put your authentication logic is in the router where you can add navigation guards to restrict access to pages based on the current authentication state and send your users to a login page:
// GOOD
router.beforeEach((to, from, next) => {
if (!isAuthenticated) next('/login')
else next()
})

I don't think you specifically need an index.html in your project. Provided your main.js has an import that references you main Vue page, e.g.:
import App from "./App.vue";
and then renders it.
new Vue({
...
render: (h) => h(App),
...

The .vue file is a special Vue.js CLI project feature allowing you to write Vue.js apps or Vue.js components in more convenient way. You write your app/component in the .vue file and Vue.js CLI transforms it into code that works in a browser.
The main.js in Vue.js CLI project is starting the instance of the app. The index.html file in Vue.js CLI project is handled automatically (it's located in the 'public' folder).
The right place to start with Vue.js CLI is: Instant Prototyping

Related

Vue Js not displaying

This is my very beginning with Vue with Symfony. Problem is nothing is displayed in my page, I was expecting Hello to be print. I did all my configurations. I have created folder vue
Inside vue I have following 2 files.
App.vue
<template>
<div id="app">
<h1>Hello</h1>
</div>
</template>
index.js
import Vue from "vue";
import App from "./App";
new Vue({
components: { App },
template: "<App/>"
}).$mount("#app");
I have in my webpack.config.js
.addEntry('app', './assets/vue/index.js')
I did anything wrong here ?
You are mounting the Vue instance to something existing in the DOM with id app. But the component inside App.vue also contains a div with id app. Try to mount to anything else on the page that Symfony creates (you can't mount on body or html). I'm sure that page does not contain anything with id app.

Where to put VueJS components common across the application

In my nuxtjs application, I have few features that are used across the application viz Login/Signup dialog, a snackbar to show alerts etc. Since, I want these features on every page and v-app-bar component is already added to all the pages. I have included the components for these features inside v-app-bar component.
<template>
<v-app-bar app id="app-bar">
<LoginJoinDialog />
<AlertSnackbar />
<!-- Code for App bar -->
</v-app-bar>
</template>
But I am not happy with this approach for following reasons
I know these common components does not belong to the v-app-bar component. And just for the sake of DRY and maintenance headaches I have included them. So from design perspective this is not very intuitive.
Secondly, What if in future I have pages that do not have a v-app-bar component. In that case I will be repeating code for these common components anyway. So, the pain of maintaining the code at multiple places will still be there.
Considering the above points, I am looking for a more elegant approach than what I have implemented. If there is a vuejs recommendation on this, even better. What suggestions do you have for component structuring for these common features?
You can acheive what you are looking for using layouts. What you need to do is make layouts folder inside src directory. And then you can create as many
layout components(*.vue files) and use them as you like.
For an example, this is default.vue component inside layouts folder:
<template>
<main>
<!-- Your app bar component -->
<v-app-bar app id="app-bar">
<LoginJoinDialog />
<AlertSnackbar />
<!-- Code for App bar -->
</v-app-bar>
<!-- Page Content (This tag will automatically embed the page content into layouts)-->
<nuxt />
</main>
</template>
<script>
export default {};
</script>
Now, on your pages folder, you can add index.vue file where you can reference the default layout, as a property in this manner: layout: 'default'
The index.vue file should look something like this:
<template>
<!-- page content goes here -->
</template>
<script>
export default {
name: 'HomePage',
layout: 'default',
};
</script>
I also have created an example project in nuxt with layouts.
For a working prototype of the project: Visit this link.
I hope it helps to solve your issue.
You can use global component registration trick by Chris Fritz. You just to need to modify it a bit so it's more fitting for a nuxt.js app. So you can create a base folder under your components folder and keep all these shared components there. Then create a new plugin and change the path to your #/components/base folder and modify the regex so it grabs all the files, no matter what the name is:
globalComponents.js
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
export default () => {
const requireComponent = require.context(
'#/components/base', false, /[\w-]+\.vue$/
)
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName)
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\/(.*)\.\w+$/, '$1'))
)
Vue.component(componentName, componentConfig.default || componentConfig)
})
}
nuxt.config.js
plugins: [
'~/plugins/globalComponents.js'
],

Importing Vanilla js file to Vue.js component

I have previously made some drag and drop functionality in vanilla JS which I have used in other projects. Now I have started a Vue.js project and I would like to use the same drag and drop functionality.
Is it possible to include a vanilla JS file in a Vue.js component? And how can it be done?
So far I have only tried to add a <script> tag in the head element in the index.html but it throws an error.
<script src="../src/js/drag-and-drop.js"></script>
You can import the script within your vue component with either
import
import '../src/js/drag-and-drop.js';
require
require('../src/js/drag-and-drop.js');
in the script section of your component.
e.g.
<template>
<!-- vue component markup -->
</template>
<script>
import drag from '../src/js/drag-and-drop';
export default {
name: 'you-vue-component',
}
</script>

Can i import single file component using Vue and Vue Router CDN?

I'm currently using Vue and Vue Router CDN. I want to import a single file component (user.html) to my index.html with Vue router. But when I click on "Go to user" the data didn't display. I read a few guides about Vue router but they used NPM or CIL instead of Vue CDN.
Index.html
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- use router-link component for navigation. -->
<!-- specify the link by passing the `to` prop. -->
<!-- `<router-link>` will be rendered as an `<a>` tag by default -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
<router-link to='/User.html'>Go to User</router-link>
</p>
<!-- route outlet -->
<!-- component matched by the route will render here -->
<router-view></router-view>
</div>
<script>
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const User = { template: '#test'}
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar },
{
path:'/User.html', component: User
}
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
</script>
User.html
<template id = "test">
fsjdfjdfldskjflkd
</template>
I think there's been a misunderstanding. As far as I can tell you're trying to load User.html in the way you would load a .vue file, but that doesn't work unless you're using Webpack to build your project since the .vue filetype is something that the vue-loader project is responsible for parsing.
Vue Router CDN means you're not building with Webpack, so loading a component like you're doing is impossible. You can configure Vue Router to serve a User.html file, but that file can't be a template component since in CDN mode Vue Router has no idea what files are on your server, nor can it simply retreive them.
So you need to do one of the following three options:
Option 1: Start using Webpack for your project
This is what I recommend you doing. You'll find that your project will perform better and will be easier to develop using it.
Option 2: Use the proper template syntax for CDN
This is for example:
var mytemplate = `<div>
<h1>This is my template</h1>
</div>`
Vue.component('mycomp1', {
template: mytemplate
});
Vue.component('mycomp2', {
template: `
<div>
Hello, {{ name }}!
</div>
`,
props: ['name'],
});
You can't load other files as templates when you're not building using Webpack. Webpack puts them into your single page application for you, Vue Router has no idea what's inside User.html nor can Vue use it as a template. Vue Router can be told to redirect to a fully functional User.html website page, but not to just use it as a template.
Option 3: Use Ajax requests to fetch the template file
This is something I STRONGLY URGE YOU NOT TO DO, but for the sake of completeness, you can use the CDN version if you fetch the contents of User.html file using an Ajax request and create a component from that.
I really, really recommend that you stop using the CDN version and instead go for a Webpack based solution, give in to the dark side! Or make it even simpler and use Nuxt.js instead since it's easier for beginners to use.

Header and footer component in Vue.js

I am learning Vue.js, I am not using cli for Vue.js installation, I just downloaded Vue.js file and trying to learn it.
My issue is to externalize components like header.vue and footer.vue and add them to main component.
I used Vue.component('MyHeader', require('./components/Header.vue')); to load component but I was getting error like "Uncaught ReferenceError: require is not defined".
To resolve this error I downloaded require.js file from here but I am still unable to load component files.
Folder Structure
index.html
<!DOCTYPE html>
<html>
<head>
<title>this is example of header and footer</title>
</head>
<body>
<div id='root'>
<testcomponent></testcomponent>
<MyHeader></MyHeader>
<div>I am Content</div>
<MyFooter></MyFooter>
</div>
<!-- we need this two files for vue js -->
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="require.js"></script>
<!-- End of we need this two files for vue js -->
<script type="text/javascript" src="indexController.js"></script>
</body>
</html>
indexController.js
//rout file for vue js
Vue.component("testcomponent",{
template:'<p>I am Test Component</p>'
});
Vue.component('MyHeader', require('./components/Header.vue'));
Vue.component('MyFooter', require('./components/Footer.vue'));
//import MyHeader from './components/Header.vue'
//import MyFooter from './components/Footer.vue'
var app = new Vue({
el: "#root",
components: {
MyHeader,
MyFooter
},
data: {
},
methods:{
}
});
Header.vue
<template>
<h1>I am Header</h1>
</template>
Footer.vue
<template>
<h1>I am Footer</h1>
</template>
Single file component (.vue)
You need vue-loader to convert .vue files to normal js format.
If you will read the documentation at https://v2.vuejs.org/v2/guide/single-file-components.html, you basically need to use webpack or browserify to use .vue files extensions.
As it says in the comments, you need a build tool to use .vue files. But you can get all the goodness of components, except scoped css, by using plain .js files.
Put your templates in .js template strings, then call your components the old way, with <script src="urlOfFile.js">, or call them with requirejs, but they need to be plain .js files, not .vue.
CommonJS using require (not to be confused with require.js which is using AMD):
Instead of Header.vue create Header.js which you then can require just like you do:
module.exports = {
template: `<template>
<h1>I am Header</h1>
</template>`
}
ES6 export / import
If you want to use ES6 import instead of require, this would be the content of Header.js:
export default {
template: `<template>
<h1>I am Header</h1>
</template>`
}
To work with .vue component files and structuring, you need vue-webpack-loader and a build stack involving something like webpack or browserify.
See
https://v2.vuejs.org/v2/guide/single-file-components.html#For-Users-New-to-Module-Build-Systems-in-JavaScript
If you are just starting with Vue and all the JS magic I would look into the vue cli install approach link. It should install webpack and all the things needed for single page components then you can work backward to deconstruct the pieces of that setup.
You can also look at the examples in the vue GitHub repos. link
That example is using vuex along with single file components but it is solid.