After laravel-mix upgrade app no longer sees global vars - vue.js

I'm upgrading a project from laravel-mix v2.0 to v4.0 and I'm seeing an issue now where at runtime my components can't see globally scoped variables like they did before. How can upgrading the build tool impact the runtime?
I see I can add instance properties to the vue prototype, but is that really the approach I need to take? Seems like it should still be able to read global variables like it did before.
html
<script type="text/javascript">
var games = [
// a bunch of objects
];
</script>
<script src="{{ mix('js/app.js') }}"></script>
app.js
import ChannelSubscriptionSlider from './components/guild-subscriptions/ChannelSubscriptionSlider.vue';
Vue.component('channel-subscription-slider', ChannelSubscriptionSlider);
ChannelSubscriptionSlider.vue
import Vue from 'vue';
import VueResource from 'vue-resource';
Vue.use(VueResource);
export default {
data: function () {
return {
games: games, // undefined when used within this component, but used to work before upgrade
}
},

Edit 2
Use `window.games, this would "register" your variables globally.
Although, what i do, is the following, consider a MPA not a SPA:
In app.js i just leave the following lines:
require('./bootstrap');
window.Vue = require('vue');
In a separate file, called main.js that i made, i put this, as an example:
import Sidebar from './components/layouts/Sidebar.vue'
import Topnav from './components/layouts/Topnav.vue'
new Vue({
el: '#sidebar',
render: h => h(Sidebar)
});
new Vue({
el: '#topnav',
render: h => h(Topnav)
});
at the end of app.blade.php i put:
<script src="{{ asset('js/app.js') }}"></script>
<script type="text/javascript">
const user_props = {
fullName : {!! json_encode(Auth::user()->fullName) !!},
username : {!! json_encode(Auth::user()->username) !!},
}
user_props.install = function(){
Object.defineProperty(Vue.prototype, '$userProps', {
get () { return user_props }
})
}
Vue.use(user_props);
</script>
<script src="{{ asset('js/main.js') }}"></script>
This works because i mount vue in app.js but the components that use user_props are loaded after i declare and install the prototype... Also, since vue is mounted in app.js i can use Vue.use(user_props); after loading it...
And forgot to mention that in webpack.mix.js you should add the main.js:
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.js('resources/js/main.js', 'public/js/')
Edit 1
Based on your comments, and the docs: https://v2.vuejs.org/v2/cookbook/adding-instance-properties.html#The-Importance-of-Scoping-Instance-Properties
The $ is just a convention:
... We scope instance properties with $ to avoid this. You can even use your own convention if you’d like, such as $_appName or ΩappName, to prevent even conflicts with plugins or future features.
So with that in mind you could set it up as:
Vue.prototype.games = games;
then you can access it on every component as this.games
As the documentation implies, when doing this you've got to be careful to not overwrite it. So if you have it declared on the data section of your Vue components i think you should delete those lines...

Related

defining global variables with vite development

Now I am using vite build tool for my vue SFC app. I read the documentation of vite with the link below:
vite config link
If I am not wrong, the define option in config could be used for defining global constants. What I want to do is to define for example the name of my App in a variable inside this option and then use it in my Vue components. But unfortunately there is no example of code in the documentation about this option.
I tried this code in my vite.config.js file:
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
define: {
global: {
appName: "my-custom-name"
}
},
plugins: [vue()]
})
I am not sure that the syntax and code is correct! And also if it is correct I don't know how to call (use) this constant in my vue app components (.vue files). For example I want to use it in template or script part of this component:
<template>
<div class="bgNow">
<p class="color1">
{{ use here }}
</p>
</template>
<script>
export default {
data() {
return {
name: use here
};
},
methods: {
nameMethod() {
console.log(use here);
}
} // end of method
} // end of export
</script>
<style scoped></style>
I declared the places that want with "use here" in the code. And also if there is any other way that I could define some global constants and variables in my vite vue app, I very much appreciate your help to tell me about that.
define is a config that tells Vite how to perform a search-and-replace. It can only replace one string for another (objects cannot be used as a replacement).
For example, to replace all instances of appName with "my-custom-name", use the following config. Note JSON.stringify() is used (per the recommendation in the docs) to ensure the literal string replacement is properly quoted.
export default defineConfig({
define: {
appName: JSON.stringify('my-custom-name')
}
})
If App.vue contained:
<script setup>
console.log('appName', appName)
</script>
It would be transformed to:
<script setup>
console.log("appName", "my-custom-name")
</script>
demo

How to make Vue 3 application without CLI / Webpack / Node

I am trying to make Vue 3 application but without CLI and Webpack.
There is no official documentation yet. On CDN are many versions (vue.cjs.js, vue.cjs.prod.js, vue.esm-browser.js, vue.esm-bundler.js, vue.global.js, vue.runtime.global.js...).
Which one to pick? And how to mount application, old way does not work. There are many online examples how works new Composition API but none how to start project without CLI / Webpack.
Link to Vue 3 CDN:
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
In body:
<div id="app">
</div>
<script type="module">
import app from './app.js'
const {createApp} = Vue;
createApp(app).mount('#app');
</script>
In app.js is simple component:
export default {
name: 'Test',
setup() {
const title = "Hello";
return {
title
};
},
template: `
<div>
<h1>{{title}}</h1>
</div>
`,
};
Instead of one component, app.js can be a container for other components.
I made simple Vue 3 QuickStart template so anyone can see how this works.
Template is in SPA-like style and contains 4 sample pages, 4 components, routing and store. It uses only Vue.js from CDN, everything else is hand made ;)
Note: This is not library, it's just demo code so anyone can see how to mount Vue 3 application and use Composition API in simple scenario.
Online demo: http://vue3quickstart.rf.gd/
GitHub: https://github.com/SaleCar/Vue3-QuickStart
Found in docs: https://vuejs.org/guide/quick-start.html#without-build-tools
Without Build Tools
To get started with Vue without a build step, simply copy the following code into an HTML file and open it in your browser:
<script src="https://unpkg.com/vue#3"></script>
<div id="app">{{ message }}</div>
<script>
Vue.createApp({
data() {
return {
message: 'Hello Vue!'
}
}
}).mount('#app')
</script>
The above example uses the global build of Vue where all APIs are exposed under the global Vue variable.
While the global build works, we will be primarily using ES modules syntax throughout the rest of the documentation for consistency. In order to use Vue over native ES modules, use the following HTML instead:
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue#3/dist/vue.esm-browser.js"
}
}
</script>
<div id="app">{{ message }}</div>
<script type="module">
import { createApp } from 'vue'
createApp({
data() {
return {
message: 'Hello Vue!'
}
}
}).mount('#app')
</script>
Notice how we can import directly from 'vue' in our code - this is made possible by the <script type="importmap"> block, leveraging a native browser feature called Import Maps. Import maps are currently only available in Chromium-based browsers, so we recommend using Chrome or Edge during the learning process. If your preferred browser does not support import maps yet, you can polyfill it with es-module-shims.
You can add entries for other dependencies to the import map - just make sure they point to the ES modules version of the library you intend to use.
Not for production
The import-maps-based setup is meant for learning only - if you intend to use Vue without build tools in production, make sure to check out the Production Deployment Guide.
In addition, as Evan You recommended, Vite(https://madewithvuejs.com/vite) is a good alternative to #vue/cli and webpack. It's still CLI like but more lightweight I think. Fast and supports SFC.

Expressing Vue dependencies w/Browserify & CommonJS

I am experimenting with Vue and would like to develop a node app with my usual setup which uses budo(browserify + watchify).
./index.html:
<div id="app">
{{ message }}
</div>
<!-- ===================== JavaScript Files Below This Line =============== -->
<script src="index.js"></script>
and ./src/js/main.js
const Vue = require('vue');
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
module.exports = app;
with ./index.js
// js includes
require('./src/js/main');
I cant see the message on the page. I see index.js in the console with main.js injected into it. When I use the Vue CDN with the vue code in index.html that works ok. I was hoping someone could shed some light on how one uses CommonJS modules to import vue code into their app when bundling w/browserify. Thanks in advance...
As explained here Vue.js not rendering you need to add this to your
package.json file:
"browser": {
"vue": "vue/dist/vue.common.js"
}

Message Vue is not defined

I'm new to studying vue so my question may be kind of silly, but why am I getting the message "vue is not defined"? in this code:
<template>
<div id="app">
<input></input>
<button>{{ textoBotao }}</button>
</div>
</template>
<script>
new Vue({
data: {
a: 1
},
created: function () {
console.log('a é: ' + this.a)
}
})
export default ({
data() {
return{
textoBotao: 'Clique aqui'
}
}
})
</script>
In your code, you don't need to create another instance of Vue. I can't imagine a situation where you need to create a new Vue instance in a single file component. Uou can use components if you need to encapsulate some functionality
If you do need to do this, you can use the following code:
import Vue from 'vue'
new Vue({
...
})
please see vue's official documentation and sample projects
Old question, but if someone needs it
If you have new Vue({}) in a js file and you load that js file before loading vuejs javascript file, you will get this error. This was the reason for my error.
Basically add /vue.min.js"> before you add other js files using vuejs
Hope it helps
I think You miss to add vue.js file, example:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.min.js"></script>

Add components to Vue instance after instance is created

If you've created a VueJS instance like this...
var app = new Vue({
el: '#app',
components: {...}
})
Is it possible to add components to this instance it's instantiated?
The reason I ask is that we have a multi-page app which stares a template. We want the instantiation of the Vue app to be in the shared template code but we want each page to use different components so for example the code on the contact page would be split between two files...
Master.js
Contact.js
The contact.js file would need to tell the main app that it wanted to use the conract-form component, but that component is not used on other pages so we don't want to add it to the initial app declaration in the master.js
Any help would really be appreciated.
Thanks to #thanksd
It seems as though components only have to be registered when instantiating Vue if you want the registered "locally", which means you don't have to register them at all as long as the component code comes before Vue is instantiated.
So, my master template and master.js can contain this...
<div id="app">
<header>Master header</header>
<contact-page inline-template>
Contents of contact page
</contact-page>
<footer>Master Footer</footer>
</div>
var app = new Vue({
el: '#app'
})
Then, my contact.js can contain this....
Vue.component('contact-page', {
... Contact page specific code here...
});
We had a similar trouble, with multiple pages, a layout et multiple components. Our system isn't a SPA. Each page reload. The page content is insert in a global layout with some global options by server code.
We have global components and some more especific by page, our solution is use window to catch Vue and initialize vue after charge the components by page.
IMPORTANT: follow this order declarations: windowVue / code specific for the page / startVue
EX:
layout file:
<!doctype html>
<html>
<head>
<script type="text/javascript" src="../js/windowVue.js"></script>
<!-- all header content -->
<!-- depend your system here call your js specific by page ex: productPage.js -->
<script type="text/javascript" src="../js/productPage.js"></script>
</head>
<body>
<div id="vueApp">
<!-- Your page content-->
</div>
<script type="text/javascript" src="../js/startVue.js"></script>
</body>
</html>
windowVue.js
import Vue from 'vue';
window.Vue = Vue;
productPage.js
// Here two options declare the external components only
import ComponentA from '../js/components/component-a.js';
import ComponentB from '../js/components/component-b.vue';
window.Vue.component('component-a', ComponentA)
window.Vue.component('component-b', ComponentB)
// Or if you use a page component with more logic and options you can declare here
// and include the other components as usual
window.Vue.component('product-page', {
components: {
ComponentA,
ComponentB
},
// rest of the code as usual
})
startVue.js
import GlobalA from '../js/components/global-a.js';
import GlobalB from '../js/components/global-B.js';
new window.Vue({
el:"#vueApp",
delimiters: ['${', '}'],
components: {
GlobalA,
GlobalB
}
})
That's all now each page has their owns components and we have some shared components too.
some remarks:
build the 3 js part separately
Only windowVue.js use import Vue from 'vue' the rest use window.Vue.
.js files components are declared as an object.
component-a.js
import ComponentB from '../js/components/component-b.vue';
import ComponentC from '../js/components/component-c.vue';
import ComponentD from '../js/components/component-d.vue';
export default {
name:'component-a',
components: {
ComponentB,
ComponentC,
ComponentD
},
data() {
return {
variableExample: 'example'
}
} // more of your Vue code
}