Can we make vue.js application without .vue extension component and webpack? - vue.js

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

Related

How import components?

i'm developing my first vue app.
I decided to add it to my project using the html <script> tag (so not using the CLI).
Can I use the import statement for importing componente stored in .vue file?
You can't import .vue files unless you are using a module bundler like webpack.
However, there are multiple ways of defining a vue component which don't require you to use .vue files.
For example you can define a component in a file like this:
helloWorld.js
export default {
template : `<div>{{ message }}</div>`
data : () => ({
message : 'Hello World'
})
}
and then import it like this:
app.js
import HelloWorld from 'helloWorld.js';
new Vue({
el: '#app',
components: {
HelloWorld
}
});
Just remember to add type="module" when you import your js files into your html:
<body>
<div id="app">
<hello-world></hello-world>
</div>
<script type="module" src="helloWorld.js"></script>
<script type="module" src="app.js"></script>
</body>

Laravel Mix Vue, Lazy loading component returns error as unknown custom element when using Vue Router

I have got a fresh install of Laravel Mix and I am trying to setup lazy loading components in the project. I have got the correct setup with the babel plugin 'syntax-dynamic-import' so the import statement in app.js works as expected. The issue occurs when I attempt to use the lazy loaded component with vue-router.
My app.js file looks like this:
require('./bootstrap');
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const EC = () => import(/* webpackChunkName: "example-component" */ './components/ExampleComponent.vue');
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: EC }
]
});
const app = new Vue({
router,
el: '#app'
});
and my welcome.blade.php file looks like this:
<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Laravel</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<base href="/" />
</head>
<body>
<div id="app">
<h1>Base title</h1>
<example-component></example-component>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
So I just trying to land on the root route and display the Example Component. The example component is included in the welcome.blade.php file.
I am receiving this error in the console:
[Vue warn]: Unknown custom element: <example-component> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
(found in <Root>)
I think I am missing something simple, any advice is appreciated.
First, i think you are mixing routes concepts with core components vue concepts...
Try loading the component directly in your vue app...
const app = new Vue({
router,
el: '#app',
components: {
'example-component': () => import('./components/ExampleComponent.vue')
}
});
Component loading is done with <component>
<component v-bind:is="currentTabComponent"></component>
Check the docs, for more info on dynamic components: https://v2.vuejs.org/v2/guide/components-dynamic-async.html
#Erubiel answer did work but it still quite wasn't the setup I wanted. As I am trying to use vue-router I needed to update the view by removing the explicit call to the component and adding the tag in the welcome.blade.php file. This now means my routes are injected into that space. The updated area is:
...
<body>
<div id="app">
<router-view></router-view>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
...
The problem is in the scss splitting in Vue and using mix.scss() both. Laravel mix when having both creates a css file with manifest js file content in it. which is definitely a bug. which the community mentions a bug from Webpack and will be resolved in webpack 5. But If you use only code splitting in Vue and have the default app.scss file imported to main Vue component like this(not in scope), so each other component will get the styling properly
// resources/js/components/app.vue
<template>
<!-- Main Vue Component -->
</template>
<script>
// Main Script
</script>
<style lang="scss">
#import '~#/sass/app.scss';
</style>
and the webpack.mix.js file will have no mix.scss function to run only a single app.js file. here is my file.
// webpack.mix.js
const mix = require('laravel-mix')
mix.babelConfig({
plugins: ['#babel/plugin-syntax-dynamic-import'] // important to install -D
})
mix.config.webpackConfig.output = {
chunkFilename: 'js/[name].bundle.js',
publicPath: '/'
}
mix
.js('resources/js/app.js', 'public/js')
.extract(['vue'])
.webpackConfig({
resolve: {
alias: {
'#': path.resolve('resources/') // just to use relative path properly
}
}
})
Hope this solves everyone's question

Vuejs single file components mixed with normal components

I am trying to mix vuejs single file components with the normal style of components (not sure what they are called) which I have existing code developed for already.
main.js
import Vue from 'vue'
import test from './test.vue'
import VueMaterial from 'vue-material'
Vue.use(VueMaterial)
new Vue({
el: '#app',
render: h => h(test,
{props: {
testprop: 'ttttt'
}
}),
data:{
// /testprop: 'tytytytyty'
}
})
test.vue
<template>
<div>
<my-component></my-component>
<div>This is the first single page component</div>
</div>
</template>
<script>
import MyComponent from '../src/components/MyComponent.js'
import TestTest from '../src/components/TestTest.vue'
export default {
name: 'MainApp',
props: ['testprop'],
components: {
TestTest,
MyComponent
},
mounted: function(){
},
computed:{
returnProp: function(){
return this.testprop
}
}
}
</script>
<style lang="scss" scoped>
.md-menu {
margin: 24px;
}
</style>
MyComponent.js Normal style component
window.Vue = require('Vue') //would give errors vue undefined if i dont't add this line
Vue.component('my-component', {
name: 'my-component',
template: '<div>Normal component</div>'
})
index.html
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width,initial-scale=1,minimal-ui" name="viewport">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic|Material+Icons">
<link rel="stylesheet" href="https://unpkg.com/vue-material#beta/dist/vue-material.min.css">
<link rel="stylesheet" href="https://unpkg.com/vue-material#beta/dist/theme/default.css">
<title>vuematerial</title>
</head>
<body>
<div id="app">
<main-app :testprop="testprop"></main-app>
</div>
<script src="dist/build.js"></script>
</body>
</html>
The single file component and a child single file component (not showed here) display fine. The normal type will show up as
<!--function (t,n,r,i){return Mt(e,t,n,r,i,!0)}-->
In the generated html.
Iv'e also tried doing the MyComponent import in the main.js file.
Any ideas?
I don't really want to convert all my existing components into single file ones :(
According to the docs, a child component is an object, not something attached to the Vue instance (i.e Vue.component()) so declare your component like this:
MyComponent.js
export default {
name: 'my-component',
template: '<div>Normal component</div>'
}
If you want to keep the format of MyComponent as is then you'll need to register the component before the new Vue call.

Vue Router Error

Trying set up Vue Router. Not sure what I am doing wrong. Getting the error
Failed to mount component: template or render function not defined. (found in root instance)
Again, I'm coming to Vue from React and while they are pretty similar there are small things that are different and there aren't as many Vue resources out there yet.
I'm using the Webpack template and using single file components. One thing I didn't completely understand was this part in the documentation
// 1. Define route components.
// These can be imported from other files
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
Is this just he same as me doing import Foo from 'path/to/component/ ?
Anyway, thanks for any and all help!
Here is my main.js file
import Vue from 'vue'
import App from './App'
import QuizBuilder from '../src/components/QuizBuilder.vue'
import ResourceInfo from '../src/components/ResourceInfo.vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{ path: '/info', component: ResourceInfo },
{ path: '/quiz-builder', component: QuizBuilder }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
My index.html looks like this
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<title>Digestible</title>
</head>
<body>
<div id="app">
<router-view></router-view>
</div>
<!-- built files will be auto injected -->
</body>
</html>
Assuming you have the components properly, you still need a small update.
When loading vue router as module system, the application should be initialized with the following way:
new Vue({
el: '#app',
router,
render: h => h(App)
});

Install VueRouter with Vue-Cli Webpack

I created a fresh project using the vue-cli command:
vue init webpack myapp
I am trying to add the vue-router to handle routes but I am having trouble.
Here is my main.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
var Foo = Vue.extend({
template: '<p>This is foo!</p>'
})
var Bar = Vue.extend({
template: '<p>This is bar!</p>'
})
Vue.use(VueRouter)
const router = new VueRouter()
router.map({
'/foo': {
component: Foo
},
'/bar': {
component: Bar
}
})
router.start(App, '#app')
/* eslint-disable no-new */
new Vue({
el: 'body',
components: { App }
}).$mount('#app')
Here is my index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>shivaminyanim.com</title>
</head>
<body>
<app></app>
<!-- built files will be auto injected -->
</body>
</html>
And here is my App.vue:
<template>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- use v-link directive for navigation. -->
<a v-link="{ path: '/foo' }">Go to Foo</a>
<a v-link="{ path: '/bar' }">Go to Bar</a>
</p>
<!-- route outlet -->
<router-view></router-view>
</div>
</template>
Whatever I do I can't seem to figure out how to get it to work. Right now I don't get any console errors but the browser just displays
Cannot GET /foo
for every route respectively.
I am currently using
"vue": "^1.0.21"
"vue-router": "^0.7.13",
How can I get started with vue-router?
You need to add router to your bootstrapped Vue instance in main.js. For example like this:
Vue 2.0 and Vue-router 2.0
new Vue({
router,
el: '#app',
render: h => h(App)
})
Vue 1.0 and Vue-router < 2.0
router.start({
components: { App }
}, '#app')