Reputation: 457
I am currently working on upgrading a project to Vue3. Inside the project we have several files that create global variables inside a boot directory:
src/boot/auth.js
src/boot/axios.js
src/boot/cranky.js
....
Each of these files creates global variables that I am using throughout the project. For example my auth.js file:
import auth from '../app/auth';
import { createApp } from 'vue';
export default async ({
router,
Vue
}) => {
const app = createApp({});
app.config.globalProperties.$auth = auth;
// Vue.prototype.$auth = auth;
//This works with logic in MainLayout to permit users to see particular screens
//after they are logged in.
router.beforeResolve((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// eslint-disable-next-line no-unused-vars
let user;
if (app.config.globalProperties.$auth.isAuthenticated()) {
// TODO: record screens viewed by router url
next();
} else {
next({
path: '/home'
});
}
}
next();
});
};
After research and reading I understand that global variables are created like this:
app.config.globalProperties.$auth = auth;
, Which then should be called from other component files using this.$auth
. In my case, however, this returns as undefined.
My theory is that there is an issue with my createapp. Am I calling that correctly, or am I missing something else?
Thanks.
EDIT
added code requested by @tony19
The following the full script tag. My understanding and I probably am wrong, is that the this
works as a global in vue3.
<script>
import HeaderScoreIndicator from '../components/HeaderScoreIndicator.vue';
import ExitResearchControl from '../components/ExitResearchControl.vue';
import {mq} from 'src/boot/mq'
export default {
components: {
HeaderScoreIndicator,
ExitResearchControl
},
data: function () {
return {
tab: 'denial',
signedIn: false,
username: null,
user: null
};
},
computed: {
/*
These 4 functions bind the colors to the background elements
*/
title: function () {
return this.$store.state.globals.title;
},
toolbarStyle: function () {
return 'padding-top: 10px; background-color: ' + this.$store.state.globals.toolbarColor;
},
footerStyle: function () {
return `background-color: ${this.$store.state.globals.toolbarColor};`;
},
backgroundStyle: function () {
if(!this.$mq.phone){
return `background: linear-gradient(180deg, ${this.$store.state.globals.backgroundGradientTop} 0%, ${this.$store.state.globals.backgroundGradientBottom} 100%);
display: flex;
justify-content: center;`;
} else{
return `background: linear-gradient(180deg, ${this.$store.state.globals.backgroundGradientTop} 0%, ${this.$store.state.globals.backgroundGradientBottom} 100%);`;
};
},
limitSize: function(){
if(!this.$mq.phone){
return 'max-width: 1023px; width: 100%;'
} else{
return
};
}
},
/*
In the beforeCreate function, we're setting up an event listener to detect
when we've logged in. At the successful login we can push the user to
the correct screen.
*/
beforeCreate: function () {
console.log(this.$auth);
return this.$auth.getState().then(data => {
if (this.$auth.isAuthenticated()) {
this.username = this.$auth.getEmail();
return this.initialize(data).then(() => this.signedIn = true);
} else {
this.signedIn = false;
return newUserLanguageSelection()
}
}).catch(e => {
this.signedIn = false;
console.error(e);
});
},
methods: {
newUserLanguageSelection: function(){
if(localStorage.getItem('languageSet') != 'true'){
return this.$router.push('/language');
}
},
initialize: function (data) {
this.$store.commit('globals/dataLoaded');
this.$store.commit('scoring/setUsername', this.username);
return this.$store.dispatch('scoring/initializeScoring', { points: data.score | 0 })
.then(() => {
if(this.$store.state.globals.testQuiz){
return;
} else if(localStorage.getItem('languageSet') != 'true'){
return this.$router.push('/language');
}else if (data.seenAnalyticsDialog == true) {
return this.$router.push('/home');
} else {
return this.$router.push('/consent');
}
})
.catch(e => {
//silence NavigationDuplicated errors
if (e.name != "NavigationDuplicated")
throw e;
});
}
}
};
</script>
Upvotes: 0
Views: 4495
Reputation: 138276
In the previous Vue 2 project, it looks like Vue
was passed to the auth.js
module so that it could attach $auth
to the Vue prototype.
However, in an attempt to upgrade that particular code in the auth.js
module to Vue 3, you ignore the Vue
argument, and create a throwaway application instance to create the $auth
global property:
// src/boot/auth.js
export default async ({
router,
Vue,
}) => {
const app = createApp({}); ā local app instance
app.config.globalProperties.$auth = auth;
ā®
}
But that won't work because the app
instance is not somehow hooked into the application instance you'll eventually mount in main.js
.
Your main.js
probably looks similar to this:
// src/main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import auth from './boot/auth';
auth({ router, Vue });
ā®
Vue.createApp(App).mount('#app');
To correctly upgrade the original code, you should pass the app
instance from main.js
to auth.js
:
// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import auth from './boot/auth';
const app = createApp(App);
auth({ router, app });
ā®
app.mount('#app');
And use that app
in the auth.js
module:
// src/boot/auth.js
export default async ({
router,
app, š
}) => {
š
app.config.globalProperties.$auth = auth;
ā®
}
Assuming you don't need to await the return of the auth.js
module, you could make that module a Vue plugin instead, which automatically receives the app
instance as the first argument. The second argument receives the options passed in from app.use()
:
// src/boot/auth.js
export default {
install(app, { router }) {
app.config.globalProperties.$auth = auth;
router.beforeResolve(āÆ);
}
}
// src/main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import auth from './boot/auth';
const app = createApp(App);
app.use(auth, { router });
ā®
app.mount('#app');
Upvotes: 2