axios-module icon indicating copy to clipboard operation
axios-module copied to clipboard

Enable axios to use current domain as host for client requests

Open kyrsquir opened this issue 5 years ago • 7 comments

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.

This feature request is available on Nuxt community (#c343)

kyrsquir avatar Mar 06 '20 20:03 kyrsquir

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 avatar Jun 26 '20 10:06 kkojot

@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:

  1. development SPA
  2. testing in universal mode
  3. 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.

kyrsquir avatar Jun 26 '20 11:06 kyrsquir

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 avatar Jun 26 '20 12:06 kkojot

@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?

kyrsquir avatar Jun 26 '20 15:06 kyrsquir

Yes, it looks like everything works fine, thanks.

kkojot avatar Jun 26 '20 16:06 kkojot

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 avatar Sep 09 '20 09:09 vipulphysiofirst

@vipulphysiofirst You should mock axios inside jest. checkout #105

farnabaz avatar Feb 08 '21 11:02 farnabaz