@xysfe/vite-plugin-dev-proxy 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +511 -145
- package/dist/index.cjs +393 -163
- package/dist/index.d.cts +178 -4
- package/dist/index.d.mts +178 -4
- package/dist/index.d.ts +178 -4
- package/dist/index.mjs +388 -163
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -1,230 +1,596 @@
|
|
|
1
1
|
# @xysfe/vite-plugin-dev-proxy
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@xysfe/vite-plugin-dev-proxy)
|
|
4
|
+
[](./LICENSE)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
一个强大的开发环境代理插件,支持 **Vite** 和 **Vue CLI**,用于代理远程服务器并自动注入本地开发代码。
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
- 📦 Smart HTML response handling, replacing remote scripts and stylesheets with local development versions
|
|
9
|
-
- 🍪 Automatic cookie rewriting, removing Secure and Domain attributes
|
|
10
|
-
- 🔀 Redirect handling with protocol mismatch fixes
|
|
11
|
-
- ⚙️ Support for custom static resource prefixes
|
|
12
|
-
- 🎯 Flexible script/link tag filtering with string, array, regex, or function
|
|
13
|
-
- 🏷️ Custom placeholder replacement for development script injection
|
|
14
|
-
- 🐛 Debug logging support
|
|
15
|
-
- 🔗 Merge with other proxy configurations
|
|
16
|
-
- 🔧 TypeScript support with full type definitions
|
|
8
|
+
[English](./README.en.md) | 简体中文
|
|
17
9
|
|
|
18
|
-
##
|
|
10
|
+
## ✨ 特性
|
|
19
11
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
- 🚀 **双框架支持** - 同时支持 Vite 和 Vue CLI
|
|
13
|
+
- 🔄 **智能代理** - 自动代理远程服务器的 HTML、API 等请求
|
|
14
|
+
- 💉 **脚本注入** - 自动注入本地入口脚本到远程 HTML
|
|
15
|
+
- 🧹 **脚本清理** - 灵活清除远程 HTML 中不需要的脚本和样式
|
|
16
|
+
- 🍪 **Cookie 处理** - 自动重写 Cookie,解决本地开发跨域问题
|
|
17
|
+
- 🔀 **重定向处理** - 智能处理 HTTP 重定向,自动转换为本地地址
|
|
18
|
+
- 🗜️ **解压缩支持** - 支持 gzip、deflate、brotli 压缩格式
|
|
19
|
+
- 🔌 **WebSocket 热更新** - 自动识别并排除 HMR WebSocket,无需手动配置
|
|
20
|
+
- 🎯 **灵活配置** - 支持字符串、数组、函数、正则等多种配置方式
|
|
21
|
+
- 📦 **零依赖** - 核心功能无外部依赖
|
|
22
|
+
- 🔧 **TypeScript** - 完整的类型定义和 JSDoc 注释
|
|
23
|
+
- 🐛 **调试模式** - 详细的日志输出,方便排查问题
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
yarn add @xysfe/vite-plugin-dev-proxy --dev
|
|
26
|
-
```
|
|
25
|
+
## 📦 安装
|
|
27
26
|
|
|
28
27
|
```bash
|
|
29
|
-
|
|
28
|
+
# npm
|
|
29
|
+
npm install @xysfe/vite-plugin-dev-proxy -D
|
|
30
|
+
|
|
31
|
+
# yarn
|
|
32
|
+
yarn add @xysfe/vite-plugin-dev-proxy -D
|
|
33
|
+
|
|
34
|
+
# pnpm
|
|
35
|
+
pnpm add @xysfe/vite-plugin-dev-proxy -D
|
|
30
36
|
```
|
|
31
37
|
|
|
32
|
-
##
|
|
38
|
+
## 🚀 快速开始
|
|
33
39
|
|
|
34
|
-
###
|
|
40
|
+
### Vite 项目
|
|
35
41
|
|
|
36
|
-
```
|
|
42
|
+
```javascript
|
|
37
43
|
// vite.config.js
|
|
38
44
|
import { defineConfig } from "vite";
|
|
39
|
-
import
|
|
45
|
+
import { VitePluginDevProxy } from "@xysfe/vite-plugin-dev-proxy";
|
|
40
46
|
|
|
41
47
|
export default defineConfig({
|
|
42
48
|
plugins: [
|
|
43
|
-
|
|
44
|
-
appHost: "example.com",
|
|
49
|
+
VitePluginDevProxy({
|
|
50
|
+
appHost: "example.com", // 远程服务器地址(必填)
|
|
51
|
+
https: true, // 使用 HTTPS
|
|
52
|
+
entry: "/src/main.js", // 本地入口文件
|
|
53
|
+
staticPrefix: "/dev/static", // 静态资源前缀
|
|
54
|
+
remotePrefixes: ["/static/component"], // 远程资源路径
|
|
55
|
+
clearScriptCssPrefixes: "/static", // 清除远程脚本/样式
|
|
56
|
+
debug: true, // 开启调试日志
|
|
45
57
|
}),
|
|
46
58
|
],
|
|
47
59
|
});
|
|
48
60
|
```
|
|
49
61
|
|
|
50
|
-
###
|
|
62
|
+
### Vue CLI 项目
|
|
51
63
|
|
|
52
|
-
```
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
import viteDevProxy from "@xysfe/vite-plugin-dev-proxy";
|
|
64
|
+
```javascript
|
|
65
|
+
// vue.config.js
|
|
66
|
+
const { VueCliPluginDevProxy } = require("@xysfe/vite-plugin-dev-proxy");
|
|
56
67
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
developmentAgentOccupancy:
|
|
66
|
-
"<!-- Vite development mode proxy occupancy -->",
|
|
67
|
-
entry: "/src/main.js",
|
|
68
|
-
debug: true,
|
|
69
|
-
}),
|
|
70
|
-
],
|
|
68
|
+
module.exports = VueCliPluginDevProxy({
|
|
69
|
+
appHost: "example.com",
|
|
70
|
+
https: true,
|
|
71
|
+
entry: ["/js/chunk-vendors.js", "/js/app.js"],
|
|
72
|
+
staticPrefix: "/dev/static",
|
|
73
|
+
remotePrefixes: ["/static/component"],
|
|
74
|
+
clearScriptCssPrefixes: "/static",
|
|
75
|
+
debug: true,
|
|
71
76
|
});
|
|
72
77
|
```
|
|
73
78
|
|
|
74
|
-
|
|
79
|
+
## 📚 配置选项
|
|
75
80
|
|
|
76
|
-
|
|
77
|
-
// vite.config.js
|
|
78
|
-
import { RegeExp } from "vite";
|
|
79
|
-
import viteDevProxy from "@xysfe/vite-plugin-dev-proxy";
|
|
81
|
+
### ProxyOptions
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
83
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
84
|
+
| --------------------------- | ------------------------------------------ | --------------------------------------------------------------------------- | -------------------------------------------- |
|
|
85
|
+
| `appHost` | `string` | - | **必填**。远程服务器地址,如 `'example.com'` |
|
|
86
|
+
| `https` | `boolean` | `true` | 是否使用 HTTPS 协议 |
|
|
87
|
+
| `staticPrefix` | `string` | `'/dev/static'` | 静态资源路径前缀,用于构建本地资源路径 |
|
|
88
|
+
| `remotePrefixes` | `string \| string[] \| Function \| RegExp` | `['/static/component']` | 远程资源路径规则,匹配的资源从远程加载 |
|
|
89
|
+
| `clearScriptCssPrefixes` | `string \| string[] \| Function \| RegExp` | `''` | 清除脚本/CSS 的规则,匹配的标签会被移除 |
|
|
90
|
+
| `entry` | `string \| string[]` | Vite: `'/src/main.js'`<br>Vue CLI: `['/js/chunk-vendors.js', '/js/app.js']` | 本地入口文件路径,支持单个或多个 |
|
|
91
|
+
| `developmentAgentOccupancy` | `string` | `''` | 自定义占位符,用于替换为入口脚本 |
|
|
92
|
+
| `localIndexHtml` | `string` | `''` | 本地 HTML 文件路径(库模式使用) |
|
|
93
|
+
| `debug` | `boolean` | `false` | 是否开启调试模式,输出详细日志 |
|
|
94
|
+
|
|
95
|
+
## 🎯 高级用法
|
|
96
|
+
|
|
97
|
+
### 1. remotePrefixes - 远程资源路径配置
|
|
98
|
+
|
|
99
|
+
`remotePrefixes` 用于指定哪些资源应该从远程服务器加载,支持 4 种类型:
|
|
100
|
+
|
|
101
|
+
#### 字符串类型(单个前缀)
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
VitePluginDevProxy({
|
|
105
|
+
appHost: "example.com",
|
|
106
|
+
remotePrefixes: "/static/component", // 字符串
|
|
97
107
|
});
|
|
98
108
|
```
|
|
99
109
|
|
|
100
|
-
|
|
110
|
+
**匹配规则**:URL 以 `/static/component` 开头的资源从远程加载。
|
|
101
111
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
**示例**:
|
|
113
|
+
|
|
114
|
+
- ✅ `/static/component/button.js` → 远程加载
|
|
115
|
+
- ✅ `/static/component/styles/main.css` → 远程加载
|
|
116
|
+
- ❌ `/static/images/logo.png` → 本地加载
|
|
117
|
+
|
|
118
|
+
#### 数组类型(多个前缀)
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
VitePluginDevProxy({
|
|
122
|
+
appHost: "example.com",
|
|
123
|
+
remotePrefixes: ["/static/component", "/static/lib", "/api"], // 数组
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**匹配规则**:URL 以数组中任一前缀开头的资源从远程加载。
|
|
128
|
+
|
|
129
|
+
#### 正则表达式类型
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
VitePluginDevProxy({
|
|
133
|
+
appHost: "example.com",
|
|
134
|
+
remotePrefixes: /^\/static\/(?!images)/, // 正则:排除 images 文件夹
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**更多正则示例**:
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// 匹配所有 .min.js 文件
|
|
142
|
+
remotePrefixes: /\.min\.js$/;
|
|
143
|
+
// 匹配 /api/ 或 /services/ 开头的路径
|
|
144
|
+
remotePrefixes: /^\/(api|services)\//;
|
|
145
|
+
// 匹配包含版本号的资源
|
|
146
|
+
remotePrefixes: /\/lib\/v\d+\.\d+\.\d+\//;
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### 函数类型(自定义逻辑)
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
VitePluginDevProxy({
|
|
153
|
+
appHost: "example.com",
|
|
154
|
+
remotePrefixes: (url) => {
|
|
155
|
+
// 微前端场景:子应用使用远程资源
|
|
156
|
+
const microApps = ["/micro-app-1/", "/micro-app-2/"];
|
|
157
|
+
return microApps.some((app) => url.startsWith(app));
|
|
116
158
|
},
|
|
117
159
|
});
|
|
118
160
|
```
|
|
119
161
|
|
|
120
|
-
|
|
162
|
+
**函数签名**:`(url: string) => boolean`
|
|
163
|
+
|
|
164
|
+
- 参数 `url`:完整的请求 URL
|
|
165
|
+
- 返回 `true`:从远程加载
|
|
166
|
+
- 返回 `false`:使用本地资源
|
|
167
|
+
|
|
168
|
+
**更多函数示例**:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
// 根据环境变量决定
|
|
172
|
+
remotePrefixes: (url) => {
|
|
173
|
+
return process.env.USE_REMOTE === "true" && url.startsWith("/static");
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// 复杂的业务逻辑
|
|
177
|
+
remotePrefixes: (url) => {
|
|
178
|
+
if (url.startsWith("/modules/payment/")) return true;
|
|
179
|
+
if (url.startsWith("/modules/checkout/")) return true;
|
|
180
|
+
if (url.includes("/vendor/")) return true;
|
|
181
|
+
return false;
|
|
182
|
+
};
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 2. clearScriptCssPrefixes - 清除远程脚本/样式
|
|
186
|
+
|
|
187
|
+
`clearScriptCssPrefixes` 用于清除远程 HTML 中不需要的 `<script>` 和 `<link>` 标签,同样支持 4 种类型:
|
|
188
|
+
|
|
189
|
+
#### 字符串类型
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
VitePluginDevProxy({
|
|
193
|
+
appHost: "example.com",
|
|
194
|
+
clearScriptCssPrefixes: "/static", // 清除 src/href 以 /static 开头的标签
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### 数组类型
|
|
121
199
|
|
|
122
|
-
|
|
200
|
+
```javascript
|
|
201
|
+
VitePluginDevProxy({
|
|
202
|
+
appHost: "example.com",
|
|
203
|
+
clearScriptCssPrefixes: ["/static", "/vendor"], // 清除多个前缀
|
|
204
|
+
});
|
|
205
|
+
```
|
|
123
206
|
|
|
124
|
-
####
|
|
207
|
+
#### 正则表达式类型
|
|
125
208
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
| `clearScriptCssPrefixes` | `string \| string[] \| RegExp \| Function` | `''` | - | Filter script/link tags to remove. Supports string prefix, array of prefixes, regex, or custom function |
|
|
133
|
-
| `developmentAgentOccupancy` | `string` | `''` | - | Custom placeholder string to replace with local development script. If not set, script will be injected into div with id="app" |
|
|
134
|
-
| `entry` | `string` | `'/src/main.js'` | - | Local development entry file path |
|
|
135
|
-
| `isLib` | `boolean` | `false` | - | Whether in component library mode, returns local HTML file when true |
|
|
136
|
-
| `localIndexHtml` | `string` | `'index.html'` | - | Local HTML file path (only used when isLib=true) |
|
|
137
|
-
| `debug` | `boolean` | `false` | - | Whether to enable debug logging |
|
|
209
|
+
```javascript
|
|
210
|
+
VitePluginDevProxy({
|
|
211
|
+
appHost: "example.com",
|
|
212
|
+
clearScriptCssPrefixes: /\.(min\.js|min\.css)$/, // 清除压缩文件
|
|
213
|
+
});
|
|
214
|
+
```
|
|
138
215
|
|
|
139
|
-
|
|
216
|
+
#### 函数类型
|
|
140
217
|
|
|
141
|
-
|
|
218
|
+
```javascript
|
|
219
|
+
VitePluginDevProxy({
|
|
220
|
+
appHost: "example.com",
|
|
221
|
+
clearScriptCssPrefixes: (tag) => {
|
|
222
|
+
// 清除包含 'legacy' 的标签
|
|
223
|
+
return tag.includes("legacy");
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
```
|
|
142
227
|
|
|
143
|
-
|
|
228
|
+
**函数签名**:`(tag: string) => boolean`
|
|
144
229
|
|
|
145
|
-
|
|
230
|
+
- 参数 `tag`:完整的 HTML 标签字符串
|
|
231
|
+
- 返回 `true`:清除该标签
|
|
232
|
+
- 返回 `false`:保留该标签
|
|
146
233
|
|
|
147
|
-
|
|
234
|
+
### 3. 多入口配置
|
|
148
235
|
|
|
149
|
-
|
|
150
|
-
- Removes tags based on `clearScriptCssPrefixes` configuration:
|
|
151
|
-
- If string: removes tags where src/href starts with the prefix
|
|
152
|
-
- If array: removes tags where src/href starts with any of the prefixes
|
|
153
|
-
- If RegExp: removes tags matching the regex pattern
|
|
154
|
-
- If Function: removes tags where the function returns true
|
|
155
|
-
- Inserts local development script entry:
|
|
156
|
-
- If `developmentAgentOccupancy` is set, replaces that placeholder with the local script
|
|
157
|
-
- Otherwise, injects the local script into `<div id="app">` element
|
|
236
|
+
支持单个或多个入口文件:
|
|
158
237
|
|
|
159
|
-
|
|
238
|
+
```javascript
|
|
239
|
+
// 单入口
|
|
240
|
+
VitePluginDevProxy({
|
|
241
|
+
appHost: "example.com",
|
|
242
|
+
entry: "/src/main.js",
|
|
243
|
+
});
|
|
160
244
|
|
|
161
|
-
|
|
245
|
+
// 多入口(会按顺序注入)
|
|
246
|
+
VitePluginDevProxy({
|
|
247
|
+
appHost: "example.com",
|
|
248
|
+
entry: ["/src/vendors.js", "/src/polyfills.js", "/src/main.js"],
|
|
249
|
+
});
|
|
250
|
+
```
|
|
162
251
|
|
|
163
|
-
|
|
252
|
+
生成的 HTML:
|
|
164
253
|
|
|
165
|
-
|
|
166
|
-
|
|
254
|
+
```html
|
|
255
|
+
<script crossorigin type="module" src="/dev/static/src/vendors.js"></script>
|
|
256
|
+
<script crossorigin type="module" src="/dev/static/src/polyfills.js"></script>
|
|
257
|
+
<script crossorigin type="module" src="/dev/static/src/main.js"></script>
|
|
258
|
+
```
|
|
167
259
|
|
|
168
|
-
|
|
260
|
+
### 4. 自定义占位符
|
|
169
261
|
|
|
170
|
-
|
|
262
|
+
使用自定义占位符精确控制脚本注入位置:
|
|
171
263
|
|
|
172
|
-
```
|
|
173
|
-
|
|
264
|
+
```javascript
|
|
265
|
+
VitePluginDevProxy({
|
|
174
266
|
appHost: "example.com",
|
|
175
|
-
|
|
267
|
+
developmentAgentOccupancy: "<!-- DEV_ENTRY -->",
|
|
268
|
+
entry: "/src/main.js",
|
|
176
269
|
});
|
|
177
270
|
```
|
|
178
271
|
|
|
179
|
-
|
|
272
|
+
远程 HTML:
|
|
180
273
|
|
|
274
|
+
```html
|
|
275
|
+
<body>
|
|
276
|
+
<div id="app"></div>
|
|
277
|
+
<!-- DEV_ENTRY -->
|
|
278
|
+
</body>
|
|
181
279
|
```
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
280
|
+
|
|
281
|
+
处理后:
|
|
282
|
+
|
|
283
|
+
```html
|
|
284
|
+
<body>
|
|
285
|
+
<div id="app"></div>
|
|
286
|
+
<script crossorigin type="module" src="/dev/static/src/main.js"></script>
|
|
287
|
+
</body>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
如果不设置占位符,脚本会自动注入到 `<div id="app">` 后面。
|
|
291
|
+
|
|
292
|
+
### 5. 库模式
|
|
293
|
+
|
|
294
|
+
开发组件库时,直接使用本地 HTML 文件:### 5. 库模式
|
|
295
|
+
|
|
296
|
+
```javascript
|
|
297
|
+
VitePluginDevProxy({
|
|
298
|
+
appHost: "example.com",
|
|
299
|
+
localIndexHtml: "./public/index.html",
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## 📖 使用场景
|
|
304
|
+
|
|
305
|
+
### 场景 2:渐进式迁移
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
VitePluginDevProxy({
|
|
309
|
+
appHost: "legacy.com",
|
|
310
|
+
// 已迁移的模块使用本地,未迁移的使用远程
|
|
311
|
+
remotePrefixes: (url) => {
|
|
312
|
+
const migratedModules = ["/modules/user/", "/modules/product/"];
|
|
313
|
+
return !migratedModules.some((m) => url.startsWith(m));
|
|
314
|
+
},
|
|
315
|
+
entry: "/src/main.js",
|
|
316
|
+
});
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### 场景 3:组件库开发
|
|
320
|
+
|
|
321
|
+
```javascript
|
|
322
|
+
VitePluginDevProxy({
|
|
323
|
+
appHost: "showcase.com",
|
|
324
|
+
localIndexHtml: "./examples/index.html",
|
|
325
|
+
// 清除远程组件库的脚本
|
|
326
|
+
clearScriptCssPrefixes: /^\/lib\//,
|
|
327
|
+
entry: "/src/index.js",
|
|
328
|
+
});
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### 场景 4:A/B 测试
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
VitePluginDevProxy({
|
|
335
|
+
appHost: "example.com",
|
|
336
|
+
// 根据条件决定使用本地还是远程
|
|
337
|
+
remotePrefixes: (url) => {
|
|
338
|
+
if (!url.startsWith("/components/")) return false;
|
|
339
|
+
|
|
340
|
+
// 50% 的流量使用远程组件
|
|
341
|
+
const userId = getUserId();
|
|
342
|
+
return userId % 2 === 0;
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## 🔍 调试
|
|
348
|
+
|
|
349
|
+
开启 `debug` 模式查看详细日志:
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
VitePluginDevProxy({
|
|
353
|
+
appHost: "example.com",
|
|
354
|
+
debug: true, // 开启调试
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**控制台输出示例**:
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
vite-plugin-dev-proxy: staticPrefix /dev/static
|
|
362
|
+
[shouldUseLocal] /src/main.js
|
|
363
|
+
[Proxy] /static/component/button.js
|
|
364
|
+
Redirect handled: https://example.com/login -> http://localhost:5173/login (15ms)
|
|
365
|
+
HTML processed: /dashboard (342ms)
|
|
366
|
+
dev-proxy: rewrittenCookie token=xxx
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## 🛠️ 工作原理
|
|
370
|
+
|
|
371
|
+
### 流程图
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
┌─────────────────┐
|
|
375
|
+
│ 浏览器请求 │
|
|
376
|
+
└────────┬────────┘
|
|
377
|
+
│
|
|
378
|
+
▼
|
|
379
|
+
┌─────────────────┐
|
|
380
|
+
│ 判断资源类型 │
|
|
381
|
+
└────────┬────────┘
|
|
382
|
+
│
|
|
383
|
+
┌────┴────┐
|
|
384
|
+
│ │
|
|
385
|
+
▼ ▼
|
|
386
|
+
┌────────┐ ┌────────┐
|
|
387
|
+
│ 本地资源│ │ 远程资源│
|
|
388
|
+
└────────┘ └───┬────┘
|
|
389
|
+
│
|
|
390
|
+
┌────┴────┐
|
|
391
|
+
│ │
|
|
392
|
+
▼ ▼
|
|
393
|
+
┌────────┐ ┌────────┐
|
|
394
|
+
│ HTML │ │ 其他 │
|
|
395
|
+
└───┬────┘ └────────┘
|
|
396
|
+
│
|
|
397
|
+
▼
|
|
398
|
+
┌────────────────────┐
|
|
399
|
+
│ 1. 解压缩内容 │
|
|
400
|
+
│ 2. 清除远程脚本 │
|
|
401
|
+
│ 3. 注入本地脚本 │
|
|
402
|
+
│ 4. 重写 Cookie │
|
|
403
|
+
│ 5. 处理重定向 │
|
|
404
|
+
└────────────────────┘
|
|
187
405
|
```
|
|
188
406
|
|
|
189
|
-
|
|
407
|
+
### 详细说明
|
|
190
408
|
|
|
191
|
-
|
|
409
|
+
1. **请求拦截**:拦截所有开发服务器请求
|
|
410
|
+
2. **资源判断**:根据 `remotePrefixes` 判断使用本地还是远程资源
|
|
411
|
+
3. **HTML 处理**:
|
|
412
|
+
- 代理远程 HTML
|
|
413
|
+
- 解压缩内容(gzip/deflate/br)
|
|
414
|
+
- 根据 `clearScriptCssPrefixes` 清除指定标签
|
|
415
|
+
- 注入本地入口脚本
|
|
416
|
+
- 重写 Cookie 和重定向
|
|
417
|
+
4. **其他资源**:直接代理或使用本地资源
|
|
418
|
+
|
|
419
|
+
### Cookie 重写
|
|
420
|
+
|
|
421
|
+
自动移除 Cookie 的 `secure`、`domain`、`samesite` 属性:
|
|
422
|
+
|
|
423
|
+
```javascript
|
|
424
|
+
// 原始 Cookie
|
|
425
|
+
Set-Cookie: token=xxx; Domain=example.com; Secure; SameSite=Strict
|
|
426
|
+
|
|
427
|
+
// 重写后
|
|
428
|
+
Set-Cookie: token=xxx
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### 重定向处理
|
|
432
|
+
|
|
433
|
+
自动将远程重定向转换为本地重定向:
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
// 原始重定向
|
|
437
|
+
Location: https://example.com/dashboard
|
|
438
|
+
|
|
439
|
+
// 转换后
|
|
440
|
+
Location: http://localhost:5173/dashboard
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## 📁 项目结构
|
|
444
|
+
|
|
445
|
+
```
|
|
446
|
+
src/
|
|
447
|
+
├── core.ts # 核心共享逻辑(~500 行)
|
|
448
|
+
│ ├── 类型定义 (ProxyOptions, IncomingMessage, etc.)
|
|
449
|
+
│ ├── 常量配置 (正则表达式、状态码等)
|
|
450
|
+
│ ├── 工具函数 (20+ 个纯函数)
|
|
451
|
+
│ │ ├── createLogger - 创建日志函数
|
|
452
|
+
│ │ ├── normalizePath - 路径标准化
|
|
453
|
+
│ │ ├── generateEntryScript - 生成入口脚本
|
|
454
|
+
│ │ ├── rewriteCookies - Cookie 重写
|
|
455
|
+
│ │ ├── decompressBuffer - 解压缩
|
|
456
|
+
│ │ ├── shouldClearScriptCss - 判断是否清除标签
|
|
457
|
+
│ │ ├── injectEntryScript - 注入脚本
|
|
458
|
+
│ │ ├── clearScriptCssTags - 清除标签
|
|
459
|
+
│ │ ├── isRedirectResponse - 判断重定向
|
|
460
|
+
│ │ ├── shouldProcessAsHtml - 判断处理HTML
|
|
461
|
+
│ │ ├── matchesRemoteResource - 匹配远程资源
|
|
462
|
+
│ │ ├── shouldUseLocal - 判断使用本地
|
|
463
|
+
│ │ ├── handleRedirect - 处理重定向
|
|
464
|
+
│ │ ├── handleLibModeHtml - 处理库模式HTML
|
|
465
|
+
│ │ ├── handleHtmlResponse - 处理HTML响应
|
|
466
|
+
│ │ ├── validateOptions - 验证配置
|
|
467
|
+
│ │ └── processOptions - 处理配置
|
|
468
|
+
│ └── 导出所有公共功能
|
|
469
|
+
│
|
|
470
|
+
├── vite-cli.ts # Vite 插件(~160 行)
|
|
471
|
+
│ ├── VitePluginDevProxy - 默认导出
|
|
472
|
+
│ ├── createProxyConfig - 创建代理配置
|
|
473
|
+
│ └── 使用 core.ts 的工具函数
|
|
474
|
+
│
|
|
475
|
+
├── vue-cli-plugin-dev-proxy.ts # Vue CLI 插件(~180 行)
|
|
476
|
+
│ ├── VueCliPluginDevProxy - 默认导出
|
|
477
|
+
│ ├── createProxyConfig - 创建代理配置
|
|
478
|
+
│ ├── onProxyReq, onError, onProxyRes 钩子
|
|
479
|
+
│ └── 使用 core.ts 的工具函数
|
|
480
|
+
│
|
|
481
|
+
└── index.ts # 入口文件
|
|
482
|
+
├── export VitePluginDevProxy
|
|
483
|
+
└── export VueCliPluginDevProxy
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
## 📝 TypeScript 支持
|
|
487
|
+
|
|
488
|
+
完整的 TypeScript 类型定义和 JSDoc 注释:
|
|
192
489
|
|
|
193
490
|
```typescript
|
|
194
|
-
import
|
|
491
|
+
import { VitePluginDevProxy } from "@xysfe/vite-plugin-dev-proxy";
|
|
492
|
+
import type { ProxyOptions } from "@xysfe/vite-plugin-dev-proxy/dist/core";
|
|
195
493
|
|
|
196
494
|
const config: ProxyOptions = {
|
|
197
495
|
appHost: "example.com",
|
|
198
496
|
https: true,
|
|
497
|
+
entry: "/src/main.js",
|
|
498
|
+
remotePrefixes: ["/static/component"],
|
|
499
|
+
clearScriptCssPrefixes: (tag: string) => tag.includes("legacy"),
|
|
199
500
|
debug: true,
|
|
200
501
|
};
|
|
201
502
|
|
|
202
503
|
export default defineConfig({
|
|
203
|
-
plugins: [
|
|
504
|
+
plugins: [VitePluginDevProxy(config)],
|
|
505
|
+
});
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## ⚙️ 与其他工具对比
|
|
509
|
+
|
|
510
|
+
| 功能 | dev-proxy-plugin | vite-plugin-proxy | http-proxy-middleware |
|
|
511
|
+
| ------------- | ------------------ | ----------------- | --------------------- |
|
|
512
|
+
| 双框架支持 | ✅ Vite + Vue CLI | ❌ | ✅ |
|
|
513
|
+
| HTML 脚本注入 | ✅ | ❌ | ❌ |
|
|
514
|
+
| 脚本清除 | ✅ 4种类型 | ❌ | ❌ |
|
|
515
|
+
| Cookie 重写 | ✅ 自动 | ❌ | ⚠️ 手动 |
|
|
516
|
+
| 重定向处理 | ✅ 自动转换 | ⚠️ | ⚠️ |
|
|
517
|
+
| 压缩支持 | ✅ gzip/deflate/br | ❌ | ⚠️ |
|
|
518
|
+
| 灵活配置 | ✅ 4种类型 | ⚠️ 数组 | ⚠️ 对象 |
|
|
519
|
+
| TypeScript | ✅ 完整 | ⚠️ 部分 | ✅ |
|
|
520
|
+
| 文档 | ✅ 详细 | ⚠️ 简单 | ✅ |
|
|
521
|
+
| 代码量 | 📦 ~850 行 | - | - |
|
|
522
|
+
|
|
523
|
+
## 💡 常见问题
|
|
524
|
+
|
|
525
|
+
### 1. 为什么需要这个插件?
|
|
526
|
+
|
|
527
|
+
**场景**:你的项目依赖后端服务器渲染的 HTML,但你想在本地开发时使用 Vite/Vue CLI 的热更新功能。
|
|
528
|
+
|
|
529
|
+
**解决方案**:
|
|
530
|
+
|
|
531
|
+
- 代理远程服务器的 HTML
|
|
532
|
+
- 清除远程的脚本和样式
|
|
533
|
+
- 注入本地开发的脚本
|
|
534
|
+
- 处理 Cookie 和重定向问题
|
|
535
|
+
|
|
536
|
+
### 2. `remotePrefixes` 和 `clearScriptCssPrefixes` 有什么区别?
|
|
537
|
+
|
|
538
|
+
- **`remotePrefixes`**:控制哪些**资源**从远程加载
|
|
539
|
+
- **`clearScriptCssPrefixes`**:控制哪些 HTML **标签**被清除
|
|
540
|
+
|
|
541
|
+
**示例**:
|
|
542
|
+
|
|
543
|
+
```javascript
|
|
544
|
+
{
|
|
545
|
+
// /static/component 下的资源从远程加载
|
|
546
|
+
remotePrefixes: '/static/component',
|
|
547
|
+
// 但清除 HTML 中 /static 开头的 script/link 标签
|
|
548
|
+
clearScriptCssPrefixes: '/static',
|
|
549
|
+
}
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### 3. 如何调试配置是否生效?
|
|
553
|
+
|
|
554
|
+
开启 `debug: true`,查看控制台日志:
|
|
555
|
+
|
|
556
|
+
```javascript
|
|
557
|
+
VitePluginDevProxy({
|
|
558
|
+
appHost: "example.com",
|
|
559
|
+
debug: true, // 开启调试
|
|
560
|
+
remotePrefixes: (url) => {
|
|
561
|
+
const isRemote = url.startsWith("/static");
|
|
562
|
+
console.log(`[自定义] ${url} -> ${isRemote ? "远程" : "本地"}`);
|
|
563
|
+
return isRemote;
|
|
564
|
+
},
|
|
204
565
|
});
|
|
205
566
|
```
|
|
206
567
|
|
|
207
|
-
|
|
568
|
+
### 4. 支持哪些压缩格式?
|
|
208
569
|
|
|
209
|
-
|
|
210
|
-
2. The plugin will override `server.proxy` configuration in `vite.config.js`
|
|
211
|
-
3. Ensure the local development server port matches the port in redirect handling
|
|
212
|
-
4. Use `clearScriptCssPrefixes` to flexibly control which remote scripts and stylesheets to remove
|
|
213
|
-
5. Use `developmentAgentOccupancy` to specify a custom placeholder for script injection, or let the plugin automatically inject into `<div id="app">`
|
|
570
|
+
支持 3 种常见的 HTTP 压缩格式:
|
|
214
571
|
|
|
215
|
-
|
|
572
|
+
- **gzip** - `Content-Encoding: gzip`
|
|
573
|
+
- **deflate** - `Content-Encoding: deflate`
|
|
574
|
+
- **brotli** - `Content-Encoding: br`
|
|
216
575
|
|
|
217
|
-
|
|
218
|
-
|
|
576
|
+
### 5. 如何与其他 Vite 插件配合使用?
|
|
577
|
+
|
|
578
|
+
直接添加到 `plugins` 数组即可:
|
|
579
|
+
|
|
580
|
+
```javascript
|
|
581
|
+
export default defineConfig({
|
|
582
|
+
plugins: [vue(), vueJsx(), VitePluginDevProxy({ appHost: "example.com" })],
|
|
583
|
+
});
|
|
584
|
+
```
|
|
219
585
|
|
|
220
|
-
##
|
|
586
|
+
## 🤝 贡献
|
|
221
587
|
|
|
222
|
-
|
|
588
|
+
## 📄 许可证
|
|
223
589
|
|
|
224
|
-
|
|
590
|
+
MIT License © 2024
|
|
225
591
|
|
|
226
|
-
|
|
592
|
+
## 🔗 相关链接
|
|
227
593
|
|
|
228
|
-
|
|
594
|
+
- [npm 包](https://www.npmjs.com/package/@xysfe/vite-plugin-dev-proxy)
|
|
229
595
|
|
|
230
|
-
|
|
596
|
+
---
|