Enable axios to use current domain as host for client requests
What problem does this feature solve?
Since nuxt generate can't be used together with nuxt.config.js axios: { proxy: true }, is there a way to configure axios to extract host for browser(client) requests from current browser page domain? If what I'm asking for doesn't make sense please point me to the right direction on where to look for solution. I'm trying to setup a Docker config with nuxt generate which could be run from both local development machine and production without any adjustments and this proxy limitation really prevents me from reaching this without hardcoding stuff.
If described above makes any sense at all consider the following changes:
What does the proposed changes look like?
Perhaps we could use document.location.host to extract host while in the browser and append our port and prefix to it?
This would mean settings in nuxt.config.js like (inspired by proxy setting)
axios: {
reuseBrowserDomain: true
},
browserAxios: {
port: 1337,
prefix: '/api'
}
which take precedence over browserBaseURL in case they are set.
Another option would be to allow setting a function to browserBaseURL which is to be executed in browser context.
I've got the same problem. @kyrsquir could you show me your workaround for this?
If I set in nuxt.config.js: axios: { port: 8080 } it's trying to connect to localhost in production. See link
Workaround like this:
axios: {
baseURL: development
? "http://localhost:8080"
: "http://prod-domain:8080"
}
doesn't work, because when I run a docker image locally it's trying to connect with the production domain. How do you do this?
@kkojot
My nuxt.config.js:
if (IS_STATIC) {
axiosConfig = {
baseURL: `http://${HOSTNAME}${PREFIX}`
};
} else {
axiosConfig = {
// API_HOST holds internal nginx IP
proxy: true,
prefix: PREFIX
};
}
module.exports = {
axios: axiosConfig
...
}
HOSTNAME is localhost for development and server domain for remote server.
This covers my three use cases:
- development SPA
- testing in universal mode
- static-generated (using nuxt-generate) production
The first two involve a Nuxt server so they require Nuxt Docker config.
Dockerfile:
FROM node:alpine AS dev
WORKDIR /usr/src/app
COPY package.json .
ARG NODE_ENV
ENV NODE_ENV=$NODE_ENV
ENV NODE_PATH=/usr/src/node_modules
ENV PATH=$PATH:$NODE_PATH/.bin/
RUN yarn --modules-folder=$NODE_PATH
FROM dev AS universal
COPY . .
ARG DOMAIN
ENV DOMAIN=$DOMAIN
RUN yarn build
Dev docket-compose.yml:
nuxt:
container_name: nuxt
image: nuxt:dev
build:
context: ./nuxt
target: dev
args:
NODE_ENV: development
environment:
NUXT_HOST: nuxt
NUXT_PORT: 80
NUXT_BUILD_DIR: ../.nuxt # to prevent hoisting it to the host
API_HOST: nginx
networks:
- dev
volumes:
- ./nuxt:/usr/src/app:delegated
command: yarn dev
Testing (universal mode) docket-compose.yml:
nuxt:
container_name: nuxt
image: nuxt
build:
context: ./nuxt
target: universal
args:
NODE_ENV: testing
DOMAIN: $DOMAIN
environment:
NUXT_HOST: nuxt
NUXT_PORT: 80
API_HOST: nginx
networks:
- alpha
command: yarn start
I'm using nginx as reverse proxy. Let me know if you also need its config.
Thank you @kyrsquir for your quick response. Well, I use apache to host my frontend static files in production and I don't have any proxy. I also develop in SPA mode.
If you have backend on the same port as frontend, you can simply set axios: { browserBaseURL: "/" } and it's going to use current browser domain, but if you want to set the port also axios: { port: 8080, browserBaseURL: "/"} then it's going to use localhost always and it seems to be a bug for me.
My workaround is to use a client-side plugin and set the base URL to axios.
nuxt.config.js
plugins: [
"~/plugins/axios.client.js"
]
axios.client.js in /plugins
export default function({ $axios }) {
if (process.client) {
const host = window.location.hostname;
$axios.setBaseURL("http://" + host + ":8080");
}
}
This covers all of my cases: developing locally, running docker on the local machine, running docker in production.
@kkojot
My workaround is to use a client-side plugin and set the base URL to axios.
Yeah I also use this approach, forgot to mention that. One difference is that I'm also setting baseUrl from browser if the app was statically generated, so instead of
if (process.client)
my condition is
if (process.client || process.static) {
So you have figured it out and everything works for you now?
Yes, it looks like everything works fine, thanks.
I am using nuxt + jest for unit testing, when id testing a page it has Axios call in a method like this
IN pay.vue
async pay(){
try{
var respone = this.$axios.get('API_URL_HERE);
this.fee = response.data;
} catch(e){
console.log(e)
}
}
and test file pay.spec.js
import { mount } from '@vue/test-utils';
import paynow from '../pages/pay';
import axios from "axios";
import Vue from 'vue'
jest.mock("axios", () => ({
get: () => Promise.resolve({ data: [{ val: 1 }] })
}));
describe("paynow.vue", () => {
it("mocking the axios call to get posts should work", async () => {
var wrapper = mount(paynow);
wrapper.vm.pay()
});
});
But I am getting this error after running it. TypeError: Cannot read property 'get' of undefined Axios is injected in the plugin then why it is showing undefined
@vipulphysiofirst You should mock axios inside jest. checkout #105