iT邦幫忙

1

請問如何在 Vue-cli 專案 dist 中,動態修改 axios 的 baseURL ?

各位大大好:

公司採用 Vue-cli 4 開發,
目前有個需求是要在 build 後的 dist 中,修改一個 config 檔,
可以動態修改 axios 的 baseURL,而不用重新 build 一次。

目前資料夾規劃如下
https://ithelp.ithome.com.tw/upload/images/20201210/20133396gzRFUzuu3w.png

api 資料夾會統一管理所有 API function,例如:

// api/aPage.js
import request from '@/utils/request';

export function getData() {
    return request({
        url: '/data',
        method: 'get'
    })
 }
 
 export function delData(id) {
    return request({
        url: '/del',
        method: 'delete',
        data: id
    })
 }
 
 ...

utils 資料夾下的 request.js 會封裝一個 axios,例如:

// utils/request.js
import axios from 'axios';

import { dev, prod } from 'public/apiPath.json';

const service = axios.create({
  baseURL: process.env.NODE_ENV === 'production' ? prod : dev,
  withCredentials: true,
  timeout: 1000 * 10,
});

service.interceptors.request.use(
  (config) => config,
  (error) => Promise.reject(error),
);

service.interceptors.response.use(
  (response) => response.data,
  (error) => Promise.reject(error),
);

export default service;

request.js 會取得放置在 public 的 apiPath.json,apiPath.json 會寫上所有 API 路徑 (放在 public 也是希望可以在 Vue-cli 打包後,仍然可以修改這個 json)

但目前修改 dist 的 apiPath.json,仍然無法動態修改網站的 API 路徑,即使將伺服器關掉重啟也沒有用/images/emoticon/emoticon02.gif,刪掉 apiPath.json 也對專案沒有影響,所以猜測 Vue-cli 已經將 apiPath.json 的值打包進去了。

嘗試很久,還是沒有找到解法,想請問有什麼方向給可以解決呢,感謝!

froce iT邦大師 1 級 ‧ 2020-12-10 15:14:54 檢舉
https://stackoverflow.com/questions/53035036/how-do-i-exclude-a-file-eg-config-file-in-vue-js

這個?
https://stackoverflow.com/questions/54004759/vue-cli-keep-config-file-as-external-after-compilation/59576534#59576534
感謝回覆,研究中

2 個回答

0
通靈亡
iT邦研究生 3 級 ‧ 2020-12-11 12:02:58
最佳解答

將json檔案放在public,並透過<script src> 掛在 public/index.html,
使用window.xxx存取那個json檔的變數

public/index.htm

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />

    <script src="<%= BASE_URL %>abc.json" /></script>
    <title>test</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but codesandbox doesn't work properly without JavaScript
        enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

public/abc.json

var abcConfig = {
  api: "http://example.com.tw/api"
};

Vue裡面

<template>
  <div id="app">
    {{this.api}}
  </div>
</template>

<script>
export default {
  name: "App",
  computed: {
    api () {
      return window.abcConfig.api
    }
  },
  mounted() {
    console.log(window.abcConfig);
  },
};
</script>

<style>
</style>

感謝,在 stackoverflow 跟社群都貼過問題,最後在這裡得到解法,謝謝!/images/emoticon/emoticon07.gif

0

這之前我也挑戰過。
任何方法都想過了。

也曾經考量動態式的編譯方式。
但太操效能了宣告失敗。

目前的做法是採用一支env來處理,區分開發跟正式。
env這支就是設定為主路由的地方。
並不列入git處理。

一但有增加新的路由,還是會跑一次編譯。
不過我有用pm2來處理。所以它會在編譯完後,自動重啟運行。

對user來說還算是無感更換。

我曾經有參考過用外部呼叫的方式。也就是另外規劃一個不列入編譯處理。
但程式碼會對其載入運行。
不過在編譯上會報錯。

再用另外一招,用遠端載入呼叫設定的方式來處理。
但運行中不太穩定,也是宣告失敗。

看更多先前的回應...收起先前的回應...

感謝回答,終於找到同胞了><

我後來寫成,在每個 API function 中,都要重新取得一次 API 路徑,這樣似乎可以動態改變 API 路徑了。

變成以下:

// api/init.js
// 封裝一個取得路徑的 function
import axios from "axios";

export async function init() {
  const { data } = await axios.get("apiPath.json");
  const { dev, prod } = data

  return process.env.NODE_ENV === "production" ? prod : dev;
}
// api/aPage.js
import request from "@/utils/request";
import { init } from "@/api/init";

export async function getData(param) {
  // 每個 API function 都要加上這一段,重新取得路徑
  const domain = await init()
  // 直接將 API 路徑寫在這裡
  return request({
    url: `${domain}/todos/${param}`,
    method: "get",
  });
}
// utils/request.js
import axios from "axios";

// import { dev, prod } from "/public/apiPath.json";

const service = axios.create({
  // 這裡就不寫 baseURL 了,直接把路徑寫在每個 API function
  // baseURL: process.env.NODE_ENV === "production" ? prod : dev,
  withCredentials: true,
  timeout: 1000 * 10,
});

service.interceptors.request.use(
  (config) => config,
  (error) => Promise.reject(error)
);

service.interceptors.response.use(
  (response) => response.data,
  (error) => Promise.reject(error)
);

export default service;

每個 API function 皆改為 async function,並且多出一行 code 每執行一次就重新取得路徑,不知道這樣寫是否有問題 ...

你是可以試試,其實我現在的做法跟你大同小異。
本來以為是可以解決的。
但還是會在一些地方讀到舊路由。
也不知道是我沒寫好還是怎麼樣。

現在其實是用了上架系統。每一次更新上架都會重新build。
倒也已經不會再理會這個問題了。

不過因為我是同程式多個站。
所以還是得搭配一下env的機制。

通靈亡 iT邦研究生 3 級 ‧ 2020-12-11 12:02:37 檢舉

有一招比較冷門的招,就是將json透過<script src="xxx.json">掛在public 的index.htm

謝謝星空回覆,目前使用通靈亡的方法解決了!

這招就是外部連結了。
但跑起來怪怪的。且我家的前端一直跟我抗議。
所以就沒這樣幹了。

我要發表回答

立即登入回答