I'm using Vue.js 2.3.3, Vue Resource 1.3.3, Vue Router 2.5.3, and I'm trying to set up Vue-Auth. I keep getting a console error, however, that says auth.js?b7de:487 Error (#websanova/vue-auth): vue-resource.1.x.js : Vue.http must be set.. I'm setting Vue.http in main.js, but vue-resource is not picking it up for some reason.
main.js:
import Vue from 'vue'
import Actions from 'actions'
import App from './App'
Vue.use(Actions, {
locales: ['en', 'zh', 'fr']
})
Vue.http.options.root = 'https://api.example.com'
new Vue({
render: h => h(App),
watch: {
lang: function (val) {
Vue.config.lang = val
}
}
}).$mount('#app')
actions/index.js
import VueResource from 'vue-resource'
import Router from 'actions/router'
import I18n from 'actions/i18n'
export default {
install (Vue, options) {
Vue.use(Router)
Vue.use(I18n, options.locales)
Vue.use(require('#websanova/vue-auth'), {
router: require('#websanova/vue-auth/drivers/router/vue-router.2.x'),
auth: require('#websanova/vue-auth/drivers/auth/bearer'),
http: require('#websanova/vue-auth/drivers/http/vue-resource.1.x')
})
}
}
And if I add Vue.use(VueResource) to actions/index.js right below Vue.use(Router), I get a new error: Error (#websanova/vue-auth): vue-router.2.x.js : Vue.router must be set.
On the other hand, if I move Vue.http.options.root = 'https://api.example.com' to right below the import statements, I get yet another error: Uncaught TypeError: Cannot read property 'options' of undefined
You need to import 'vue-resource' in to your main.js file to get ride of this errors:
import Vue from 'vue'
import VueResource from 'vue-resource';
import Actions from 'actions'
import App from './App'
Vue.use(Actions, {
locales: ['en', 'zh', 'fr']
})
Vue.use(VueResource)
Vue.http.options.root = 'https://api.example.com'
new Vue({
render: h => h(App),
watch: {
lang: function (val) {
Vue.config.lang = val
}
}
}).$mount('#app')
Using axios and not vue-resource this is a working setup for me:
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueRouter)
Vue.use(VueAxios, axios)
Vue.router = new VueRouter({
// Your routes.
})
Vue.use(require('#websanova/vue-auth'), {
auth: require('#websanova/vue-auth/drivers/auth/bearer.js'),
http: require('#websanova/vue-auth/drivers/http/axios.1.x.js'),
router: require('#websanova/vue-auth/drivers/router/vue-router.2.x.js'),
})
App.router = Vue.router
new Vue(App).$mount('#app')
For more guidance you can refer to this great tutorial: https://codeburst.io/api-authentication-in-laravel-vue-spa-using-jwt-auth-d8251b3632e0
Related
I'm using a helper file to import VueX modules:
const requireModule = require.context('.', false, /\.store\.js$/)
const modules = {}
requireModule.keys().forEach(filename => {
const moduleName = filename
.replace(/(\.\/|\.store\.js)/g, '')
.replace(/^\w/, c => c.toUpperCase())
modules[moduleName] = requireModule(filename).default || requireModule(filename)
})
export default modules
This lives in #/store/modules/index.js and is imported by #/store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import modules from './modules'
Vue.use(Vuex)
export default new Vuex.Store({
modules,
actions: {
reset({commit}) {
Object.keys(modules).forEach(moduleName => {
commit(`${moduleName}/RESET`);
})
}
}
})
Imported in to Vue: #/main.js:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Works great for all of my store modules! Each of which are namespaced:
const initialState = () => ({})
const state = initialState()
const mutations = {
RESET(state) {
const newState = initialState();
Object.keys(newState).forEach(key => {
state[key] = newState[key]
});
}
}
const getters = {}
const actions = {}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
Now, I'm trying to import a package as a state module. Which I don't have any experience with. This might seem silly... but I'm not sure how to inject the namespace enablement into the package importation in #/store/modules/Auth.store.js:
import AmazonCognitoVuexModule from 'amazon-cognito-vuex-module';
const cognito = new AmazonCognitoVuexModule({
region: process.env.VUE_APP_COGNITO_REGION,
userPoolId: process.env.VUE_APP_COGNITO_USERPOOL_ID,
clientId: process.env.VUE_APP_COGNITO_CLIENT_ID,
})
export default cognito
So when I try to call the imported store module's actions with $store.dispatch('Auth/...') they're not found... because they're not namespaced. I want to namespace this module "Auth". I bet I'm overlooking something really simple. Any help appreciated.
My first try would be (based on the docs of this package on NPM):
// source: https://www.npmjs.com/package/amazon-cognito-vuex-module
const store = new Vuex.Store({
modules: {
cognito: new AmazonCognitoVuexModule({
region: '<region>',
userPoolId: '<user pool id>',
clientId: '<client id>'
})
}
});
The code above shows that you can import it as a module (they named it cognito, you want auth - that should make no difference; I use the naming in the official docs). So you need to update your code, like this:
import Vue from 'vue'
import Vuex from 'vuex'
import modules from './modules'
import cognito from './path/to/cognito'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
...modules,
cognito,
},
actions: {
reset({commit}) {
Object.keys(modules).forEach(moduleName => {
commit(`${moduleName}/RESET`);
})
}
}
})
I'm not sure this works, but this would be my first try :)
I am new to VueJS and I have been trying to setup graphql with my vuejs but I can't seem to get it right.
Funny thing is there's no error on my console apart from a
[Vue warn]: A plugin must either be a function or an object with an "install" function. error.
And this only comes up when I instantiate vueapollo to the use method.
Here's my main.js file
import { createApp } from 'vue';
import ElementUI from 'element-plus';
import ApolloClient from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import VueApollo from 'vue-apollo';
import App from './App.vue';
import router from './router';
import store from './store';
import './assets/style/theme/index.css';
// HTTP connection to the API
const httpLink = createHttpLink({
// You should use an absolute URL here
uri: 'http://localhost:4999/graphql',
});
// Cache implementation
const cache = new InMemoryCache();
// Create the apollo client
const apolloClient = new ApolloClient({
link: httpLink,
cache,
});
/* The provider holds the Apollo client instances
that can then be used by all the child components. */
// eslint-disable-next-line
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
});
createApp(App)
.use(ElementUI)
.use(apolloClient)
.use(store)
.use(router)
.mount('#app');
I have a page file where presently, I want to reach the "Hello" endpoint I created earlier
<template>
<div>
<h1>Hello</h1>
<h1>{{ hello }}</h1>
</div>
</template>
<script>
import gql from 'graphql-tag';
export default {
data() {
return {
hello: '',
};
},
apollo: {
// Simple query that will update the 'hello' vue property
hello: gql`
query {
hello
}
`,
},
};
</script>
I also struggled with it a couple of weeks ago.
I don't remember how, but I got it to work.
I post my code here, in case it helps anyone in the future.
The difference between the question author and my code is how I pass the Apollo client to the create-app setup function. I don't know if it is correct, but it works.
PS: I am also using TypeScript on top of everything.
My apollo-client.ts file
import { ApolloError } from '#apollo/client';
import { ApolloClient, InMemoryCache, HttpLink } from '#apollo/client/core';
import { ErrorResponse } from '#apollo/client/link/error';
import { onError } from '#apollo/client/link/error';
import { logErrorMessages } from '#vue/apollo-util';
function getHeaders() {
const headers = {
'content-type': 'application/json',
};
/* const token = window.localStorage.getItem('apollo-token');
if (token) {
headers['Authorization'] = `Bearer ${token}`;
} */
return headers;
}
// Create an http link:
const httpLink = new HttpLink({
uri: 'http://localhost:3000/query',
fetch: (uri: RequestInfo, options: RequestInit) => {
options.headers = getHeaders();
return fetch(uri, options);
},
});
const errorLink = onError((error: ErrorResponse | ApolloError) => {
if (process.env.NODE_ENV !== 'production') {
logErrorMessages(error);
}
});
// Create the apollo client
export const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
connectToDevTools: true,
link: errorLink.concat(httpLink),
});
My main.ts file:
import { apolloClient } from './apollo-client';
import { createApp, provide, h } from 'vue';
import { DefaultApolloClient } from '#vue/apollo-composable';
import { createApolloProvider } from '#vue/apollo-option';
import { loadFonts } from './plugins/webfontloader';
import App from './App.vue';
import router from './router';
import store from './store';
import vuetify from './plugins/vuetify';
// TODO: Auth
// import authPlugin from "./auth/authPlugin"
// Create a provider
const apolloProvider = createApolloProvider({
defaultClient: apolloClient,
});
loadFonts();
const app = createApp({
setup() {
provide(DefaultApolloClient, apolloClient);
},
render: () => h(App),
});
app.use(router).use(store).use(vuetify).use(apolloProvider).mount('#app');
The main.js of my vue app looks like this:
import VueResource from 'vue-resource'
import VueRouter from 'vue-router'
import Routes from './routes'
import App from './App.vue'
import Vue from 'vue'
import './style/customColor.scss';
import store from "./store/store";
import { USER_ROLECHECK } from './store/actions/user'
import { REQ_ADMIN_ROLE } from "./utility/namespaces";
Vue.use(VueResource);
Vue.use(VueRouter);
const router = new VueRouter({
routes: Routes,
mode: 'history'
})
router.beforeEach((to, from, next) => {
if(to.meta.reqAuth){
if(store.getters.isAuthenticated){
if(to.meta.reqAdmin){
store.dispatch(USER_ROLECHECK, REQ_ADMIN_ROLE).then(() =>{
next();
}).catch(() =>{
next({path: '/'})
})
}else{
next();
}
}else{
next({path: '/login'});
}
}else{
next();
}
})
new Vue({
el: '#app',
router,
store,
render: h => h(App),
})
Im running vue in production mode. I still want to use devtools, but they give me this error:
Vue.js is detected on this page.
Devtools inspection is not available because it's in production mode or explicitly disabled by the author.
I read here https://github.com/vuejs/vue-devtools/issues/190 that I need to change main.js like this:
You are probably using Vue from CDN, and probably using a production build (dist/vue.min.js). Either replace it with a dev build (dist/vue.js) or add Vue.config.devtools = true to the main js file.
But I dont know where to make this entry into my projects/apps main.js :(
Please help!
Okay, I found the answer myself:
This is what the code of main.js looks like with devtools=true:
import VueResource from 'vue-resource'
import VueRouter from 'vue-router'
import Routes from './routes'
import App from './App.vue'
import Vue from 'vue'
import './style/customColor.scss';
import store from "./store/store";
import { USER_ROLECHECK } from './store/actions/user'
import { REQ_ADMIN_ROLE } from "./utility/namespaces";
Vue.use(VueResource);
Vue.use(VueRouter);
//HERE IT IS=============================================================
Vue.config.devtools = true; //this line should be removed in the actual live
build!
//HERE IT IS==================================================
const router = new VueRouter({
routes: Routes,
mode: 'history'
})
router.beforeEach((to, from, next) => {
if(to.meta.reqAuth){
if(store.getters.isAuthenticated){
if(to.meta.reqAdmin){
store.dispatch(USER_ROLECHECK, REQ_ADMIN_ROLE).then(() =>{
next();
}).catch(() =>{
next({path: '/'})
})
}else{
next();
}
}else{
next({path: '/login'});
}
}else{
next();
}
})
new Vue({
el: '#app',
router,
store,
render: h => h(App),
})
I'm using below code to watch for the change in Vuex state but watch is not working. I get the following error: Uncaught TypeError: Cannot read property 'watch' of undefined
acl.js
import Vue from 'vue'
import { AclInstaller, AclCreate, AclRule } from 'vue-acl'
import router from '#/router'
import axios from '../axios'
import { store } from '../store/store'
Vue.use(AclInstaller)
store.watch(state => state.auth.token, (val) => {
if (val) {
console.log(val)
}
}
)
export default new AclCreate({
initial: 'admin',
notfound: '/pages/not-authorized',
router,
acceptLocalRules: true,
globalRules: new AclRule('admin').generate(),
})
store.js
import Vue from 'vue'
import Vuex from 'vuex'
import auth from "./auth";
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
auth: auth
},
strict: process.env.NODE_ENV !== 'production'
})
I tried to create some organization in my Vue app, so I moved my router confirguration to a separate file:
# /_helpers/router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import MemberDetail from '../MemberDetail';
import LoginPage from '../LoginPage';
Vue.use(VueRouter)
const routes = [
{ path: '/', component: MemberDetail },
{ path: '/login', component: LoginPage },
];
export const router = new VueRouter({routes});
router.beforeEach((to, from, next) => {
// redirect to login page if not logged in and trying to access a restricted page
const publicPages = ['/login'];
const authRequired = !publicPages.includes(to.path);
const loggedIn = localStorage.getItem('user');
if (authRequired && !loggedIn) {
return next('/login');
}
next();
})
Then I add the exported router in my main application.js:
import Vue from 'vue/dist/vue.esm'
import App from '../components/app.vue'
import { router } from '../components/_helpers';
document.addEventListener('DOMContentLoaded', () => {
new Vue({
el: '#app',
router,
render: h => h(App)
});
})
In my App.vue, I try to display the router-view:
<template>
<div class="page-container">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app'
};
</script>
<style scoped>
</style>
Unfortunataly this results in the following error:
[Vue warn]: Unknown custom element: <router-view> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I don't understand what's wrong... I'm adding the router to the new Vue call, so I think it should be available.
Thanks