前言
在还没将
vue-cli
迁移到rsbuild
之前呢,根据proxy.router
实现了无需重启项目就能修改服务器IP的方法。现在迁移后,在rsbuild.config.mjs
修改IP地址时,热更新还是有点慢,所以想把之前的实现重新应用
Vue-Cli(require)
先把
Vue-Cli
情况下的实现记录一下
- 在根目录下新建
service-config.js
文件
js
module.exports = {
serverOrigin: 'https://192.168.70.28'
};
- 在
vue.config.js
中- require请求文件信息时,node会解析出我们传入的字符串的文件路径的绝对路径,并且以绝对路径为键值,对该文件进行缓存
js
const hotServer = () => {
const path = './server-config.js';
// require.resolve可以通过相对路径获取绝对路径
// 以绝对路径为键值删除require中的对应文件的缓存
delete require.cache[require.resolve(path)];
// 重新获取文件内容
const { serverOrigin } = require(path);
return serverOrigin || '';
};
// devServer下的proxy
proxy: {
'/audit-apiv2': {
secure: false,
// target: 'that must have a empty placeholder',
target: 'http://127.0.0.1:10086',
router: () => hotServer(),
onProxyReq(proxyReq) {
// 绕过后端的csrf验证
proxyReq.setHeader('referer', hotServer());
}
},
}
- vue-cli 的代理是使用的
http-proxy-middleware
包,所以proxy
选项的配置也是基于这个包的配置。在proxy
配置选项中有两个属性target
以及router
。其中target
是默认的代理地址。而router
可以return
一个字符串服务地址,那么当两个选项都配置了时,http-proxy-middleware
在解析配置时,会首先使用router
函数的返回值,当router
的返回值不可以用时,那么就会fallback
至target
。 - 项目在每次发起http请求时都会调用router中的函数,对我们的环境地址文件进行实时读取,从而指向我们最新修改的环境地址。
Rsbuild(jiti)
查了rsbuild的
proxy
实现方式后,发现和webpack
对proxy
的实现是差不多的,都是使用了http-proxy-middleware
包,描述也和webpack
一致,所以我直接原封不动的迁移过来了
- 在迁移完代码后,我对其进行验证发现,并没有生效,修改
service.config.js
中serverOrigin
的值并不生效 - 在
hotServer
函数中打印
js
const hotServer = () => {
const path = './server-config.js';
// require请求文件信息时,node会解析出我们传入的字符串的文件路径的绝对路径,并且以绝对路径为键值,对该文件进行缓存
// require.resolve可以通过相对路径获取绝对路径
// 以绝对路径为键值删除require中的对应文件的缓存
console.log('require', require);
console.log('require.cache', require.cache);
delete require.cache[require.resolve(path)];
// 重新获取文件内容
const { serverOrigin } = require(path);
console.log(serverOrigin, 'serverOrigin');
return serverOrigin || '';
};
- 打印内容如下:
js
[Function: jiti] {
resolve: [Function: _resolve] { paths: [Function: paths] },
cache: {},
extensions: {
'.js': [Function (anonymous)],
'.json': [Function (anonymous)],
'.node': [Function (anonymous)]
},
main: undefined,
transform: [Function: transform],
register: [Function (anonymous)],
evalModule: [Function: evalModule],
import: [Function (anonymous)]
}
-
resolve
:用于动态解析模块路径(类似 Node.js 的require.resolve
)。 -
cache
:JITI 的模块缓存,类似于 Node.js 的require.cache
,但独立于 Node.js 的缓存机制。 -
extensions
:定义可被加载的文件类型及其对应的处理器(.js
,.json
,.node
等)。 -
transform
:即时编译模块(例如 TS 转译为 JS)。 -
register
:注册自定义模块加载逻辑(例如扩展.ts
支持)。 -
evalModule
:直接对模块代码进行动态求值。 -
发现,这打印的是一个
jiti
,而且cache
是个空对象。难怪不生效,service-config.js
并不在缓存中。
什么是jiti
ITI 是一个轻量级动态模块加载工具,支持 CommonJS 和 ES 模块的动态加载,且在运行时进行编译和解析。以下是 JITI 的主要特性:
-
替代 Node.js 的
require
JITI 提供类似require
的 API,但它在内部可能对模块进行即时编译(尤其是 TS 或 ES Module),所以你看到它不是原生的require
。 -
缓存管理
- JITI 提供自己的缓存机制(如
jiti.cache
),和 Node.js 的require.cache
不同。 - 你可以通过
jiti.cache
来管理模块缓存。
- JITI 提供自己的缓存机制(如
-
扩展支持
- JITI 支持多种扩展(
.js
,.json
,.ts
等),可以动态解析不同格式的模块。
- JITI 支持多种扩展(
-
增强功能
- 支持动态
import
。 - 提供更灵活的模块解析机制(如内联编译 TypeScript)。
- 支持动态
在我的 Rspack 配置中,require
并不是传统 Node.js 的 require
函数,而是被替换为了 JITI("Just-In-Time-Interpreter")。
如果使用 JITI,模块的缓存不会存储在 require.cache
中,而是在 jiti.cache
中。因此,你无法通过传统的 delete require.cache[require.resolve(...)]
来清除缓存,而需要清理 jiti.cache
。
那么,我们需要安装jiti
sh
npm install jiti
删除cache缓存
- 在
rsbuild.config.mjs
文件中
mjs
const jiti = require('jiti')(__dirname);
const hotServer = () => {
const path = './server-config.js';
// require.resolve可以通过相对路径获取绝对路径
// 以绝对路径为键值删除require中的对应文件的缓存
delete jiti.cache[require.resolve(path)];
// 重新获取文件内容
const { serverOrigin } = require(path);
return serverOrigin || '';
};
- 其余的代码照旧使用
hotServer
,如此一来,只需要修改service-config.js
文件中的IP
地址即可,这样省略了热更新的时间,也能提升一点效率。
通用方法(fs文件读取)
使用文件读取的方式,这样就不需要再安装jiti
rsbuild.config.mjs
js
import fs from 'fs';
const hotServer = () => {
const path = './server-config.json';
const content = fs.readFileSync(path).toString();
const { serverOrigin } = JSON.parse(content);
return serverOrigin || '';
};
service-config.json
json
{
"serverOrigin": "https://192.168.70.203"
}
总结
以上三种方式都能实现,在修改IP
地址后,无需重新启动项目或等待热更新,直接刷新浏览器页面即可。
当然,service-config.json
中的serverOrigin
也可以抽取到.env
文件,本质都是读取文件。