Best practice to switch between development and production urls when using Vue/Vite and Django

I want to build a website with Vue/Vite as frontend and Django as a backend.
When my frontend needs to get data from the backend I currently do something like this (which works perfectly fine):
const response = await fetch('http://localhost:8000/api/register', {...

But for a production environment I (probably?) want something like this to be able to switch between dev and prod without manually changing every url:
const response = await fetch(backend_url + '/register', {...

My Question is, what is the best/standard way to setup this backend_url in Vue/Vite?

Kind regards
feps

My Search so far:
Vue has a provide/inject feature which could be used to define a gloable Variables in my App.vue file.
Vite has "Shared options" defined in vite.config.js
But for both options I was unable to find any example, which leaves me wondering if there is another option which I was unable to find, which is used to solve this "problem".

The best practice would be to implement the following:

  1. Abstract your VueJS calls to the backend in a utility file that you import in your components. This will allow for a "single point of control" scenario where the backend URL is only defined in one spot

    Example:

    /util/api.js

    /*
     * Required Types
     *
     * url: String
     * method: String
     * headers: Object
     * body:
     * query: [{'key': 'value'}, {'key': 'value'}... ]
     * onFailure: Function
     */
    export const httpRequest = async (params) => {
      let { url_endpoint, method, headers, body, query, onFailure } = params;
      let url = ""
    
      // utilize Vite's environment variables to detect mode
      if (import.meta.env.MODE === "development") {
        url = "http://localhost:8000" + url_endpoint;
        requestCredentials = "include";
      } else if (import.meta.env.MODE === "production"){
        // TODO: Define production URL
      }
      // append query params to url
      if (Array.isArray(query) && query.length) {
        url += "?";
        query.forEach(
          (q) => (url += `${Object.keys(q)[0]}=${Object.values(q)[0]}&`),
        );
      }
    
      try {
        return await fetch(url, {
          method: method,
          credentials: requestCredentials,
          headers: headers,
          body: body,
        });
      } catch(e) {
        console.error(e)
        return onFailure()
      }
    
    
    
  2. Import your httpRequest helper method in your VueJS file and interact with your backend as desired.

    /views/HomeView.vue

    <script setup>
    import { httpRequest } from "@/util/api.js";
    const res = await httpRequest({
      url_endpoint: "/api/register",
      method: "GET",
      onFailure: () => console.error("Could not fetch register"),
    });
    </script>
    
    
  3. Bonus: Configure alias paths in vite.config.js

    import { fileURLToPath, URL } from "node:url";
    
    import { defineConfig } from "vite";
    import vue from "@vitejs/plugin-vue";
    
    // https://vitejs.dev/config/
    export default defineConfig({
      server: {},
      plugins: [vue()],
      resolve: {
        alias: {
          "@": fileURLToPath(new URL(".", import.meta.url)),
        },
      },
    });
    
    

Usually there is no need to switch base urls at runtime, and at build time this is handled with Vite's env vars. There will be VITE_API_BASE_URL variable that can depend on build mode and local environment.

Use high-level wrappers for fetch API like Ky or Axios or your own wrapper function to provide base url to all requests once instead of concatenating VITE_API_BASE_URL everywhere.

tl;dr step by step version

  1. create a file in the root of your app called .env and put this in the file
    VITE_API_URL="'http://localhost:8000/"
    
  2. in your vue app file, add this to the top
    API_URL = import.meta.env.VITE_API_URL
    
  3. when you need to use it in the same file, you can just do
    const response = await fetch(`${API_URL}api/register`, {...
    

that should work, and on the production server, you will have a different .env file with a different value for this.
Don't forget to add .env to your .gitignore so you don't commit it to your app.

You might also want to consider having a file called api.js/ts in your app where you are storing your api calls so things becomes easier for you in the long run.

here's some references for you

Вернуться на верх