Vue CLI - 编译后保持配置文件为外部文件

10

我正在使用Vue CLI开发一个应用程序。这个应用程序是一个Web界面,需要与板子上的Rest API通信。

因此,由于板子会移动,板子的IP地址会随着时间和位置的变化而改变。

这是我的项目目录结构:

Project tree

IP配置信息包含在Settings.js文件中:

export const Settings = {
    // Server configuration
    SERVER_IP: '127.0.0.1',
    SERVER_PORT: '9000',

    SERVER_PROTOCOL: 'http', // http or https

    // Website configuration
    DEBUG_MODE: true
};

在我的文件中,我使用以下语句导入此IP:

import {Settings} from '../../Settings'
const ip = Settings.SERVER_IP;

// Do stuff

这很好用。但问题在于:当IP地址改变时,我必须重新编译所有内容。因为Settings.js与其他JS文件一起编译。

所以,我想知道是否有一种方法可以拥有一个配置文件,该文件将保留在dist/目录中,并且在我的JS应用程序执行期间将被读取。这样,每次应用服务器IP更改时,我就不必重新编译所有内容。

谢谢您的帮助 :)

4个回答

12

我的Vue解决方案基于Angular的解决方案

你可以像后端开发者一样拥有环境变量。

但不同的是,后端代码在服务器内执行,而前端代码只是存储在磁盘上的静态文件,没有机会在交付到浏览器之前运行和检查环境变量。

然而,你的代码必须在浏览器内执行。因此,这是拥有环境变量的理想和唯一适当的位置。因此,你需要提前准备好这个环境-根据你的后端环境。

以下是计划:

  1. 你从编译中排除你的设置文件(见下文)。
  2. 你的设置文件在运行Vue应用程序之前“构建”环境。
  3. 从你的代码中使用该环境,并且你还可以在运行时更新此环境。

所以这里是你最终的代码结构:

root_project_dir:
├─> cfg
│   └── settings.js
├─> public
│   ├── favicon.ico
│   └── index.html
├─> src
│   ├── App.vue
│   ├─> assets
│   │   └── logo.png
│   ├─> components
│   ├─> layouts
│   ├── main.js
│   ├─> plugins
│   ├─> router
│   ├─> store
│   └─> views
└── vue.config.js

创建设置文件 cfg/settings.js:

/*
This file goes as an asset without any of compilation even after build process.
Thus, it can be replaced in a runtime by different file in another environment.

Example for Docker:
  docker run -v ./local_cfg_dir:cfg image:tag
*/

(function(window) {
  window.__env = window.__env || {};

  window.__env.api = {
    "url": "http://127.0.0.1:8000",
    "timeout": 80000
  };
  window.__env.captcha = {
    "enabled": true,
    "key": "Mee1ieth1IeR8aezeiwi0cai8quahy"
  };
  window.__env.rollbar = {
    "enabled": true,
    "token": "zieriu1Saip5Soiquie6zoo7shae0o"
  };
  window.__env.debug = true;
})(this);

vue.config.js中为Webpack Copy plugin提供指令,在npm run build阶段复制cfg文件(您无法更改此名称):

module.exports = {
  chainWebpack: config => {
    config.plugin("copy").tap(([pathConfigs]) => {
      pathConfigs.unshift({
        from: "cfg",
        to: "cfg"
      });
      return [pathConfigs]})
  },
  transpileDependencies: ["vuetify"]
};

检查生成的 webpack 配置并查找是否应用(在输出底部):

检查生成的 webpack 配置并查找是否已应用(在输出底部):

vue inspect

现在,当您构建该项目时,您将在生成目录中看到它:

dist
 ├─> cfg
 │   └── settings.js
 ├─> css
 │   ├── app.06b1fea6.css
 │   └── chunk-1f2efba6.a298b841.css
 ├── favicon.ico
 ├─> img
 │   └── logo.09e0e4e1.png
 ├── index.html
 └─> js
     ├── app.8fc75c19.js
     ├── app.8fc75c19.js.map
     └── chunk-vendors.1ab49693.js.map

在你打开应用程序之前,你可以在 public/index.html 中运行这个设置:

  <body>
    <script src="/cfg/settings.js"></script>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>

现在你的窗口里有它:

输入图片描述

从代码的任何位置,你都可以访问这个环境变量:

Vue.use(VueReCaptcha, { siteKey: window.__env.captcha.key })

附注:

如果你想成为“DevOps兼容”,你需要在一个嵌套目录(例如cfg)中设置。这将使得在Kubernetes/Swarm中进行挂载而不会覆盖整个dist目录的能力。



感谢提供这么好的指南。但是我无法使其正常工作,因为最后一步“从代码中的任何位置都可以访问此环境”无法实现。在VSCode中,我遇到了一个错误:“Property '__env' does not exist on type 'Window & typeof globalThis'。” 我正在开发的应用程序是使用TypeScript编写的。 - kumaheiyama
@kumaheiyama 但它真的存在吗?您是否可以在控制台中像上面的图片一样看到 window.__env? - Michael A.
是的,我可以在控制台中看到window.__env。这个解决方案可能与TypeScript不兼容吗?不过我已经找到了另一个解决方案,使用了你的一部分解决方案。我会在另一个答案中发布。 - kumaheiyama
如果你的 window.__env 存在并且包含来自 settings.js 的数据 - 解决方案可以百分之百地工作。如果你的代码无法访问 window 的子对象 - 这是一个单独的问题,值得在 StackOveflow 上提出专门的问题。也许你需要先声明类型:(window as any).__env。 - Michael A.
1
非常好的解释。关于Vue 3的说明 - Vue.use不再可用;我使用了在此处描述的provide/inject模式:https://dev59.com/z1IG5IYBdhLWcg3wvELW#63101214 - denvercoder9

5
你可以在public目录中创建一个config.json文件,然后在main.js中获取它并加载它。现在,使用这个config.json创建你的dist文件。
fetch('/config.json').then(res => res.json()).then(config => {
     .......
})

1
非常简单实用,非常感谢! - FcoJavier99

1

使用Melih Altıntaş的答案(谢谢! :)),但想要避免获取,我在/public文件夹中创建了一个JavaScript文件:

/public/config.js --> /dist/config.js

将其加载到 index.html 的头部

<script src="<%= BASE_URL %>config.js">

并在任何后续的*.js文件中使用在/public/config.js中声明的变量(例如main.js,mixins.js...)。

构建后,可以轻松修改/dist/config.js,而其值仍会自动用于应用程序,无需重新编译;)。

也许这是一个愚蠢的解决方案,但它确实起到了作用。正是我所需要的(使客户端轻松编辑某些值)。

再次感谢你,Melih!:)


0

你是否提前知道完整的IP地址列表?如果是,你可以创建一个函数,根据任何时间/位置逻辑返回正确的IP地址。

否则,你可以尝试将设置文件移动到公共文件夹中,在.gitignore文件中添加它,并确保在public/index.html中引用它。它现在将位于编译后的Vue应用程序之外,并且可以作为全局设置变量从Vue中访问。

因此,你可以使用window.Settings来代替import {Settings} from '../../Settings'

例如:const ip = window.Settings.SERVER_IP;

这样,你就可以直接编辑设置,而无需每次重新编译。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接