Nuxt3 setup Apollo (or any plugin that uses .env) - vue.js

I'm new to the node world and I'm having issues setting up my Nuxt3 project to use Apollo, but I think most of it is lack of knowledge with node and Nuxt.
Everything works fine when the setup code is in app.vue but I want it in a separate file to keep things tidy.
This is my latest attempt, I also tried using /server/api to return values, but I ran into top-level await issues.
I created a Stack Blitz instance to show what's happening. It renders successfully once, then shows an undefined error underneath. In my project, it's similar in a way where I see a flash of content, and then an empty white page and a console error that spaceId is undefined (braking the url).
plugins/apollo.ts
import { ApolloClient,createHttpLink,InMemoryCache} from '#apollo/client/core';
import { createApp, provide, h } from 'vue';
import { DefaultApolloClient,provideApolloClient} from '#vue/apollo-composable';
export default defineNuxtPlugin(async (nuxtApp) => {
const config = useRuntimeConfig();
const httpLink = createHttpLink({
uri: `https://someapi/${config.spaceID}/`,
headers: {
Authorization: `Bearer ${config.token}`,
},
});
// Cache implementation
const cache = new InMemoryCache();
// Create the apollo client
const apolloClient = new ApolloClient({
link: httpLink,
cache,
});
provideApolloClient(apolloClient);
});
Thanks

Related

Forward basiauth to axios

I have a site which makes an Axios request. Both the backend and vuejs frontend are on the same domain, and have the same basic auth covering them.
The issue is that whilst the pages load, as soon as an Axios request is made, it asks me again for the basic auth, which doesn't even work if I fill in the details.
Now I imagine I need to pass through the basic auth details somehow, but none of the things I have tried work (and example being below).
If anyone has any tips on passing through the auth token from the parent page to the axios request, that would be great.
const requestOne = axios.get(requestUrl)
const requestTwo = axios.get(requestUrl)
axios
.all([requestOne, requestTwo])
.then(
axios.spread((...responses) => {
<some code here>
})
)
I just answered a similar question with the 3 ways to pass around data in Vue.
You might find it helpful: How to pass v-for index to other components
However, in my opinion, the best approach would be to create a Vue plugin with your Axios client and an init method.
Consider this following (untested) example:
axiosClient.js
import Vue from 'vue';
let instance;
export const getInstance = () => instance;
export const useAxios = () => {
if (instance) return instance;
instance = new Vue({
data() {
return {
client: null,
}
}
});
methods: {
init(authToken) {
this.client = axios.create({
headers: {'Authorization': authToken }
});
}
}
}
export const axiosPlugin = {
install(Vue) {
Vue.prototype.$axios = useAxios();
},
};
Vue.use(axiosPlugin);
Once installed, you can access this in your components using $axios.init(...) and $axios.client.
You can even write API methods directly onto the plugin as well and interact with Vuex through the plugin!
You may need to tweak the plugin a little (and keep in mind this is Vue2 syntax) as I wrote this directly into StackOverflow.
You can also pass any other default values or configuration options through to the axios client by providing options to the plugin and accessing them within init.
You can learn more about plugins here: https://v2.vuejs.org/v2/guide/plugins.html

Apollo GraphQL Client does not work on release build in react native

it's been around two weeks that I'm dealing with this problem.
at first, it did not work at all. After spending several days searching for a solution I could fix it by adding these lines of code to my index.js file.
XMLHttpRequest = GLOBAL.originalXMLHttpRequest ?
GLOBAL.originalXMLHttpRequest :
GLOBAL.XMLHttpRequest;
global.Blob = null
After that, it worked fine in the development mode and everything was fine.
But as soon as I released my app I realized it does not work in the release build!
I'm kind of sure it's a problem with fetch API that apollo uses behind the scenes. But I don't know what to do to fix it.
I also tried to run a new project and paste my code on it, but no luck.
this is my apollo client code:
import ApolloClient from 'apollo-client'
import Statics from './statics'
import {HttpLink} from 'apollo-link-http'
import { InMemoryCache } from '#apollo/client';
const customFetch = (uri, options) => {
return fetch(uri, options)
.then(response => {
if (response.status >= 500) { // or handle 400 errors
return Promise.reject(response.status);
}
return response;
});
};
export const client = new ApolloClient({
link: new HttpLink({uri:`${Statics.baseUrl}/graphql`, fetch:customFetch}) ,
cache: new InMemoryCache(),
});
Try using isomorphic-fetch instead of fetch

Vue 3 external component/plugin loading in runtime

I am designing an architecture for the Vue 3 app with distributed module-based ownership. Module system will be represented with plugins (seems like the most appropriate solution allowing vuex module and vue-router dynamic injects). Each such module/plugin will be developed by dedicated team working within isolated repos. We cannot use npm package-per-plugin approach as deployment process should be isolated as well, and with npm approach core app team will have to rebuild app each time npm package plugin has updates. This means we will have to load such plugins/pages at runtime via http.
So far this approach by Markus Oberlehner seems like some sort of the way to go - it uses custom Promise based solution for webpack's missing "load external url script at runtime" functionality. While it works fine with Vue 2, Vue 3 gives VNode type: undefined error.
The above mentioned article offers the following webpack external component loading solution:
// src/utils/external-component.js
export default async function externalComponent(url) {
const name = url.split('/').reverse()[0].match(/^(.*?)\.umd/)[1];
if (window[name]) return window[name];
window[name] = new Promise((resolve, reject) => {
const script = document.createElement('script');
script.async = true;
script.addEventListener('load', () => {
resolve(window[name]);
});
script.addEventListener('error', () => {
reject(new Error(`Error loading ${url}`));
});
script.src = url;
document.head.appendChild(script);
});
return window[name];
}
But above, as I said, does not work with Vue 3 defineAsyncComponent mechanism.
// 2.x version WORKS
const oldAsyncComponent = () => externalComponent('http://some-external-script-url.js')
// 3.x version DOES NOT WORK
const asyncComponent = defineAsyncComponent(
() => externalComponent('http://some-external-script-url.js')
)
So I have two questions:
Are there any known better solutions/suggestions for above architectural specification?
Is there any working webpack dynamic external import solutions tested with Vue 3 out there?
UPD: Here is small reproduction repo
We solved this problem together via chat.
Components built via the Vue 3 vue-cli rely on Vue being available in the global scope. So in order to render components loaded via the technique described in my article, you need to set window.Vue to a reference to Vue itself. Then everything works as expected.
update:
If import vue from vue/dist/vue.esm-bundler and set to global, then no need to change webpack / Vite config, and no need to load vue from cdn.
import * as Vue from 'vue/dist/vue.esm-bundler';
window.Vue = Vue;
Besides setting window.Vue, some other webpack or Vite configuration should also be set, otherwise some error is presented in console: vue warn invalid vnode type symbol(static) (symbol)
Vue3 + webpack:(https://github.com/vuejs/vue-next/issues/2913#issuecomment-753716888)
// index.html:
<script src="https://cdn.jsdelivr.net/npm/vue#3.0.4"></script>
// vue.config.js
configureWebpack: config => {
...
config.externals = { vue: 'Vue' }
...
}
Vue3 + vite:(https://github.com/crcong/vite-plugin-externals)
// vite.config.js
import { viteExternalsPlugin } from 'vite-plugin-externals'
export default {
plugins: [
viteExternalsPlugin({
vue: 'Vue'
}),
]
}

Unable to use axios in js function

We are building an application using VueJS, are new to its concepts. Facing an error when we try to make a call using axios from a js function.
The error is "export 'default' (imported as axios) was not found in ./axios.js"
Please let us know what we might be doing wrong. Appreciate your help.
import Vue from 'vue';
import axios from './axios.js';
export const MY_CONST = 'Vue.js';
export let memberList = new Vue({
el: '#members',
data: {
members: []
},
mounted: function () {
this.getAllMembers();
},
methods: {
getAllMembers: function () {
var me = this;
axios.get("https://xxxxx.com/services/api.php")
.then(function (response) {
me.members = response.data.members;
});
}
}
});
Assuming you've installed axios as a dependency or devDependency in your package.json and installed it via npm or yarn then I would suspect your issue is that you're looking for axios in a file called axios.js in the same directory as the calling component. You should instead look for the package axios like this:
import axios from 'axios';
If you're indeed trying to export axios from a custom file with configuration or something then you need to see what you're exporting from the file and make sure it is indeed axios. Though from the sound of your error that doesn't seem to be what your'e trying to do.

Populate router with external json

I would like to add routes from an external json file, which can change at runtime, to my Nuxt application. A similar topic can be found here.
I've overridden the default Nuxt router with my own implementation. If I import the routes async using axios + router.addRoutes(), I seem to loose the server side rendering. It seems like createRouter will have async support, but it's not in an official release of Nuxt yet.
How do I import a js/json file synchronously to my router.js below, so that I can populate the routes? I want to be able to configure the routes at runtime, so I don't want it to be a part of the bundle.
modules/router.js:
const path = require('path')
module.exports = function () {
this.nuxt.options.build.createRoutes = () => {}
this.addTemplate({
fileName: 'router.js',
src: path.resolve(`${this.options.srcDir}`, 'router.js')
})
}
nuxt.config.js:
modules: ['~/modules/router']
router.js:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export function createRouter () {
const router = new Router({
mode: 'history',
routes: [/* ... */]
})
return router
}
You could try with sync-request.
It is a NPM package aimed to perform synchronous web requests. It is available here.
Please note that, as stated in the documentation of the package itself, it is not suitable for production environment, probably because of application hanging in case of missing data.
So await would be an answer but I guess you already tried that? So, something like this.
const routeFile = await fetch('pathToTheJsonFile');
const routes = await routeFile.json();
In case you can't make the method async, as a workaround maybe use jQuery. I don't like this but if there's no other option, for now, use async: false in jQuery get.
jQuery.ajax({
url: 'pathToYourJsonRoutes',
success: function (result) {
},
async: false
});