@xysfe/vite-plugin-dev-proxy 1.0.2 → 1.0.5

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/dist/index.cjs CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
3
5
  const zlib = require('zlib');
4
6
  const path = require('path');
5
7
  const fs = require('fs');
@@ -9,205 +11,305 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
9
11
  const zlib__default = /*#__PURE__*/_interopDefaultCompat(zlib);
10
12
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
11
13
 
12
- function createProxyConfig(options) {
13
- const {
14
+ const SCRIPT_LINK_REGEX = /<(?:script[^>]*>.*?<\/script>|link[^>]*>)/g;
15
+ const ASSET_REGEX = /\.(js|mjs|ts|tsx|jsx|css|scss|sass|less|vue|json|woff2?|ttf|eot|ico|png|jpe?g|gif|svg|webp)(\?.*)?$/i;
16
+ const STATIC_PATH_REGEX = /^\/(static|assets|public|images|css|js)\//i;
17
+ const BYPASS_REGEX = /\.(vue|js|mjs|ts|tsx|jsx|css|scss|sass|less|json|png|jpe?g|gif|svg|webp|ico|woff2?|ttf|eot)$/i;
18
+ const REDIRECT_STATUS_MIN = 300;
19
+ const REDIRECT_STATUS_MAX = 400;
20
+ const DEFAULT_APP_DIV_REGEX = /<div[^>]*id=["']app["'][^>]*><\/div>/g;
21
+ const HTTPS_TO_HTTP_REGEX = /https:\/\/(localhost|127\.0\.0\.1|192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3})(:\d+)?/gi;
22
+ function createLogger(debug) {
23
+ return {
24
+ log: debug ? console.log.bind(console) : () => {
25
+ },
26
+ logError: debug ? console.error.bind(console) : () => {
27
+ }
28
+ };
29
+ }
30
+ function normalizePath(path) {
31
+ return path.endsWith("/") ? path.slice(0, -1) : path;
32
+ }
33
+ function generateEntryScript(entry, staticPrefix) {
34
+ if (Array.isArray(entry)) {
35
+ return entry.map(
36
+ (e) => `<script crossorigin type="module" src="${staticPrefix + e}"><\/script>`
37
+ ).join("\n");
38
+ }
39
+ return `<script crossorigin type="module" src="${staticPrefix + entry}"><\/script>`;
40
+ }
41
+ function rewriteCookies(headers, log2) {
42
+ const setCookie = headers["set-cookie"];
43
+ if (setCookie) {
44
+ headers["set-cookie"] = setCookie.map((cookie) => {
45
+ const rewrittenCookie = cookie.replace(/;\s*secure\s*(;|$)/gi, "$1").replace(/;\s*domain\s*=[^;]+(;|$)/gi, "$1").replace(/;\s*samesite\s*=[^;]+(;|$)/gi, "$1").replace(/;+/g, ";").replace(/;\s*$/g, "");
46
+ log2("[rewrittenCookie]", rewrittenCookie);
47
+ return rewrittenCookie;
48
+ });
49
+ }
50
+ return headers;
51
+ }
52
+ function decompressBuffer(buffer, encoding) {
53
+ if (encoding === "gzip") {
54
+ return zlib__default.gunzipSync(buffer);
55
+ } else if (encoding === "deflate") {
56
+ return zlib__default.inflateSync(buffer);
57
+ } else if (encoding === "br") {
58
+ return zlib__default.brotliDecompressSync(buffer);
59
+ }
60
+ return buffer;
61
+ }
62
+ function shouldClearScriptCss(match, clearRule) {
63
+ const srcMatch = match.match(/src="([^"]+)"/i);
64
+ const hrefMatch = match.match(/href="([^"]+)"/i);
65
+ const srcOrHref = srcMatch ? srcMatch[1] : hrefMatch ? hrefMatch[1] : null;
66
+ if (clearRule === "") {
67
+ return false;
68
+ }
69
+ if (typeof clearRule === "string") {
70
+ return srcOrHref?.startsWith(clearRule) ?? false;
71
+ }
72
+ if (Array.isArray(clearRule)) {
73
+ return clearRule.some((prefix) => srcOrHref?.startsWith(prefix));
74
+ }
75
+ if (clearRule instanceof RegExp) {
76
+ return clearRule.test(match);
77
+ }
78
+ if (typeof clearRule === "function") {
79
+ return clearRule(match);
80
+ }
81
+ return false;
82
+ }
83
+ function injectEntryScript(html, fullEntry, developmentAgentOccupancy) {
84
+ if (developmentAgentOccupancy) {
85
+ return html.replace(developmentAgentOccupancy, fullEntry);
86
+ }
87
+ return html.replace(DEFAULT_APP_DIV_REGEX, (match) => `${match}${fullEntry}`);
88
+ }
89
+ function clearScriptCssTags(html, clearRule, log2) {
90
+ return html.replace(SCRIPT_LINK_REGEX, (match) => {
91
+ const isClear = shouldClearScriptCss(match, clearRule);
92
+ if (isClear) {
93
+ log2?.(`[clearScriptCssTags]: ${match}`);
94
+ }
95
+ return isClear ? "" : match;
96
+ });
97
+ }
98
+ function isRedirectResponse(proxyRes) {
99
+ return proxyRes.statusCode >= REDIRECT_STATUS_MIN && proxyRes.statusCode < REDIRECT_STATUS_MAX && !!proxyRes.headers.location;
100
+ }
101
+ function shouldProcessAsHtml(contentType, acceptHeader, requestUrl, isRedirect) {
102
+ const isNavigationRequest = acceptHeader.includes("text/html");
103
+ const isAssetRequest = ASSET_REGEX.test(requestUrl);
104
+ const isStaticPath = STATIC_PATH_REGEX.test(requestUrl);
105
+ return contentType.includes("text/html") && isNavigationRequest && !isAssetRequest && !isStaticPath && !isRedirect;
106
+ }
107
+ function matchesRemoteResource(url, remoteRule) {
108
+ if (typeof remoteRule === "string") {
109
+ return url.startsWith(remoteRule);
110
+ }
111
+ if (Array.isArray(remoteRule)) {
112
+ return remoteRule.some((prefix) => url.startsWith(prefix));
113
+ }
114
+ if (remoteRule instanceof RegExp) {
115
+ return remoteRule.test(url);
116
+ }
117
+ if (typeof remoteRule === "function") {
118
+ return remoteRule(url);
119
+ }
120
+ return false;
121
+ }
122
+ function shouldUseLocal(url, normalizedStaticPrefix, remotePrefixes) {
123
+ const pathname = url.split("?")[0];
124
+ const isLocalResource = normalizedStaticPrefix && url.startsWith(normalizedStaticPrefix) || url.startsWith("/@") || url.startsWith("/src") || url.startsWith("/node_modules") || url.includes(".hot-update.") || url.startsWith("/sockjs-node") || // Vue CLI/Webpack 热更新 WebSocket (3.x)
125
+ url.startsWith("/ws") || // Vue CLI/Webpack 热更新 WebSocket (4.x+/Vite)
126
+ url === "/" || BYPASS_REGEX.test(pathname);
127
+ const isRemoteResource = matchesRemoteResource(url, remotePrefixes);
128
+ return isLocalResource && !isRemoteResource;
129
+ }
130
+ function handleRedirect(proxyRes, req, res, appHost, log2, startTime) {
131
+ const redirectUrl = proxyRes.headers.location;
132
+ const host = req.headers.host;
133
+ const regex = new RegExp(appHost, "gi");
134
+ let location = redirectUrl.replace(regex, host || "");
135
+ location = location.replace(HTTPS_TO_HTTP_REGEX, "http://$1$2");
136
+ const headers = rewriteCookies({ ...proxyRes.headers }, log2);
137
+ headers.location = location;
138
+ res.writeHead(proxyRes.statusCode, headers);
139
+ res.end();
140
+ log2(
141
+ `Redirect handled: ${redirectUrl} -> ${location} (${Date.now() - startTime}ms)`
142
+ );
143
+ }
144
+ function handleLibModeHtml(localIndexHtml, res, log2, logError, startTime) {
145
+ try {
146
+ const indexHtml = fs__default.readFileSync(
147
+ path.resolve(__dirname, localIndexHtml),
148
+ "utf-8"
149
+ );
150
+ res.writeHead(200, {
151
+ "Content-Type": "text/html; charset=utf-8"
152
+ });
153
+ res.end(indexHtml);
154
+ log2(`Local HTML served: ${localIndexHtml} (${Date.now() - startTime}ms)`);
155
+ } catch (err) {
156
+ logError("Failed to read local HTML:", err);
157
+ res.writeHead(500);
158
+ res.end("Failed to read local HTML");
159
+ }
160
+ }
161
+ function handleHtmlResponse(proxyRes, req, res, context) {
162
+ const encoding = proxyRes.headers["content-encoding"];
163
+ const requestUrl = req.url || "";
164
+ const chunks = [];
165
+ proxyRes.on("data", (chunk) => {
166
+ if (chunk) {
167
+ chunks.push(chunk);
168
+ }
169
+ });
170
+ proxyRes.on("end", () => {
171
+ try {
172
+ const buffer = Buffer.concat(chunks);
173
+ const decompressed = decompressBuffer(buffer, encoding);
174
+ let html = decompressed.toString("utf-8");
175
+ html = clearScriptCssTags(
176
+ html,
177
+ context.clearScriptCssPrefixes,
178
+ context.log
179
+ );
180
+ html = injectEntryScript(
181
+ html,
182
+ context.fullEntry,
183
+ context.developmentAgentOccupancy
184
+ );
185
+ const headers = rewriteCookies({ ...proxyRes.headers }, context.log);
186
+ headers["content-type"] = "text/html; charset=utf-8";
187
+ delete headers["content-encoding"];
188
+ delete headers["content-length"];
189
+ res.writeHead(200, headers);
190
+ res.end(html);
191
+ context.log(
192
+ `[HTML processed]: ${requestUrl} (${Date.now() - context.startTime}ms)`
193
+ );
194
+ } catch (err) {
195
+ context.logError("Decompress error:", err);
196
+ context.logError("Request URL:", requestUrl);
197
+ context.logError("Response headers:", proxyRes.headers);
198
+ res.writeHead(500);
199
+ res.end("Decompress error");
200
+ }
201
+ });
202
+ }
203
+ function validateOptions(options, pluginName) {
204
+ const { appHost } = options;
205
+ if (!appHost) {
206
+ throw new Error(`${pluginName}: appHost is required`);
207
+ }
208
+ }
209
+ function processOptions(options, isVite) {
210
+ let {
14
211
  https = true,
15
212
  appHost = "",
16
- isLib = false,
17
- localIndexHtml = "index.html",
18
- staticPrefix = "",
19
- bypassPrefixes = ["/static"],
20
- // scriptCssPrefix = "",
213
+ localIndexHtml = "",
214
+ staticPrefix = "/dev/static",
215
+ remotePrefixes = ["/static/component"],
21
216
  developmentAgentOccupancy = "",
22
217
  clearScriptCssPrefixes = "",
23
- entry = "/src/main.js",
218
+ entry = isVite ? "/src/main.js" : ["/js/chunk-vendors.js", "/js/app.js"],
24
219
  debug = false
25
220
  } = options;
26
- if (!appHost) {
27
- throw new Error("vite-plugin-dev-proxy: appHost is required");
28
- }
29
- if (!Array.isArray(bypassPrefixes)) {
30
- throw new Error("vite-plugin-dev-proxy: bypassPrefixes must be an array");
31
- }
32
- const log = debug ? console.log : () => {
33
- };
34
- const logError = debug ? console.error : () => {
221
+ appHost = normalizePath(appHost);
222
+ const normalizedStaticPrefix = normalizePath(staticPrefix);
223
+ const fullEntry = generateEntryScript(entry, normalizedStaticPrefix);
224
+ const { log: log2, logError } = createLogger(debug);
225
+ return {
226
+ https,
227
+ appHost,
228
+ localIndexHtml,
229
+ normalizedStaticPrefix,
230
+ remotePrefixes,
231
+ developmentAgentOccupancy,
232
+ clearScriptCssPrefixes,
233
+ fullEntry,
234
+ log: log2,
235
+ logError
35
236
  };
36
- const normalizedStaticPrefix = staticPrefix.endsWith("/") ? staticPrefix.slice(0, -1) : staticPrefix;
237
+ }
238
+
239
+ function createProxyConfig(options) {
240
+ validateOptions(options, "vite-plugin-dev-proxy");
241
+ const {
242
+ https,
243
+ appHost,
244
+ localIndexHtml,
245
+ normalizedStaticPrefix,
246
+ remotePrefixes,
247
+ developmentAgentOccupancy,
248
+ clearScriptCssPrefixes,
249
+ fullEntry,
250
+ log,
251
+ logError
252
+ } = processOptions(options, true);
37
253
  log("vite-plugin-dev-proxy: staticPrefix", normalizedStaticPrefix);
38
- const fullEntry = normalizedStaticPrefix + entry;
39
- const scriptLinkRegex = /<(?:script[^>]*>.*?<\/script>|link[^>]*>)/g;
40
- const assetRegex = /\.(js|mjs|ts|tsx|jsx|css|scss|sass|less|vue|json|woff2?|ttf|eot|ico|png|jpe?g|gif|svg|webp)(\?.*)?$/i;
41
- const staticPathRegex = /^\/(static|assets|public|images|css|js)\//i;
42
- const bypassRegex = /\.(vue|js|mjs|ts|tsx|jsx|css|scss|sass|less|json|png|jpe?g|gif|svg|webp|ico|woff2?|ttf|eot)$/i;
254
+ const protocol = https ? "https://" : "http://";
43
255
  return {
44
256
  "/": {
45
- target: `${https ? "https" : "http"}://${appHost}`,
257
+ target: `${protocol}${appHost}`,
46
258
  changeOrigin: true,
47
259
  secure: false,
48
260
  cookieDomainRewrite: { "*": "localhost" },
49
261
  selfHandleResponse: true,
50
- configure: (proxy, options2) => {
51
- const rewriteCookies = (headers) => {
52
- const setCookie = headers["set-cookie"];
53
- if (setCookie) {
54
- headers["set-cookie"] = setCookie.map((cookie) => {
55
- let rewrittenCookie = cookie.replace(/;\s*secure\s*(;|$)/gi, "$1").replace(/;\s*domain\s*=[^;]+(;|$)/gi, "$1").replace(/;\s*samesite\s*=[^;]+(;|$)/gi, "$1").replace(/;+/g, ";").replace(/;\s*$/g, "");
56
- log("vite-plugin-dev-proxy: rewrittenCookie", rewrittenCookie);
57
- return rewrittenCookie;
58
- });
59
- }
60
- return headers;
61
- };
262
+ configure: (proxy, _options) => {
62
263
  proxy.on(
63
264
  "proxyRes",
64
265
  (proxyRes, req, res) => {
65
266
  const startTime = Date.now();
66
267
  const contentType = proxyRes.headers["content-type"] || "";
67
- const redirectUrl = proxyRes.headers.location;
68
268
  const requestUrl = req.url || "";
69
269
  const acceptHeader = req.headers.accept || "";
70
- const isRedirect = proxyRes.statusCode >= 300 && proxyRes.statusCode < 400 && redirectUrl;
270
+ const isRedirect = isRedirectResponse(proxyRes);
71
271
  if (isRedirect) {
72
- const host = req.headers.host;
73
- const regex = new RegExp(appHost, "gi");
74
- let location = redirectUrl.replace(regex, host || "");
75
- location = location.replace(
76
- /https:\/\/(localhost|127\.0\.0\.1)(:\d+)?/gi,
77
- "http://$1$2"
78
- );
79
- const headers2 = rewriteCookies({ ...proxyRes.headers });
80
- headers2.location = location;
81
- res.writeHead(proxyRes.statusCode, headers2);
82
- res.end();
83
- log(
84
- `Redirect handled: ${redirectUrl} -> ${location} (${Date.now() - startTime}ms)`
85
- );
272
+ handleRedirect(proxyRes, req, res, appHost, log, startTime);
86
273
  return;
87
274
  }
88
- const isNavigationRequest = acceptHeader.includes("text/html");
89
- const isAssetRequest = assetRegex.test(requestUrl);
90
- const isStaticPath = staticPathRegex.test(requestUrl);
91
- const shouldProcessHtml = contentType.includes("text/html") && isNavigationRequest && !isAssetRequest && !isStaticPath && !isRedirect;
275
+ const shouldProcessHtml = shouldProcessAsHtml(
276
+ contentType,
277
+ acceptHeader,
278
+ requestUrl,
279
+ isRedirect
280
+ );
92
281
  if (shouldProcessHtml) {
93
- if (isLib) {
94
- try {
95
- const indexHtml = fs__default.readFileSync(
96
- path.resolve(__dirname, localIndexHtml),
97
- "utf-8"
98
- );
99
- res.writeHead(200, {
100
- "Content-Type": "text/html; charset=utf-8"
101
- });
102
- res.end(indexHtml);
103
- log(
104
- `Local HTML served: ${localIndexHtml}\uFF09 (${Date.now() - startTime}ms)`
105
- );
106
- } catch (err) {
107
- logError("Failed to read local HTML:", err);
108
- res.writeHead(500);
109
- res.end("Failed to read local HTML");
110
- }
282
+ if (localIndexHtml) {
283
+ handleLibModeHtml(
284
+ localIndexHtml,
285
+ res,
286
+ log,
287
+ logError,
288
+ startTime
289
+ );
111
290
  return;
112
291
  }
113
- const encoding = proxyRes.headers["content-encoding"];
114
- const chunks = [];
115
- proxyRes.on(
116
- "data",
117
- (chunk) => {
118
- if (chunk) {
119
- chunks.push(chunk);
120
- }
121
- }
122
- );
123
- proxyRes.on("end", () => {
124
- try {
125
- let buffer = Buffer.concat(chunks);
126
- const decompress = () => {
127
- if (encoding === "gzip") {
128
- return zlib__default.gunzipSync(buffer);
129
- } else if (encoding === "deflate") {
130
- return zlib__default.inflateSync(buffer);
131
- } else if (encoding === "br") {
132
- return zlib__default.brotliDecompressSync(buffer);
133
- }
134
- return buffer;
135
- };
136
- const decompressed = decompress();
137
- let html = decompressed.toString("utf-8");
138
- if (developmentAgentOccupancy) {
139
- html = html.replace(
140
- developmentAgentOccupancy,
141
- `<script crossorigin type="module" src="${fullEntry}"><\/script>`
142
- );
143
- } else {
144
- html = html.replace(
145
- /<div[^>]*id=["']app["'][^>]*><\/div>/g,
146
- (match) => `${match}<script crossorigin type="module" src="${fullEntry}"><\/script>`
147
- );
148
- }
149
- clearScriptCssPrefixes;
150
- html = html.replace(scriptLinkRegex, (match) => {
151
- const srcMatch = match.match(/src="([^"]+)"/i);
152
- const hrefMatch = match.match(/href="([^"]+)"/i);
153
- const srcOrHref = srcMatch ? srcMatch[1] : hrefMatch ? hrefMatch[1] : null;
154
- if (typeof clearScriptCssPrefixes === "string") {
155
- if (srcOrHref?.startsWith(clearScriptCssPrefixes)) {
156
- return "";
157
- }
158
- }
159
- if (Array.isArray(clearScriptCssPrefixes)) {
160
- if (clearScriptCssPrefixes.some(
161
- (prefix) => srcOrHref?.startsWith(prefix)
162
- )) {
163
- return "";
164
- }
165
- }
166
- if (clearScriptCssPrefixes instanceof RegExp) {
167
- return clearScriptCssPrefixes.test(match) ? "" : match;
168
- }
169
- if (typeof clearScriptCssPrefixes === "function") {
170
- return clearScriptCssPrefixes(match) ? "" : match;
171
- }
172
- return match;
173
- });
174
- if (html.indexOf(fullEntry) === -1) {
175
- html = html.replace(
176
- /<!--\sS 公共组件 提示信息\s-->/g,
177
- `<script crossorigin type="module" src="${fullEntry}"><\/script>`
178
- );
179
- }
180
- const headers2 = rewriteCookies({ ...proxyRes.headers });
181
- headers2["content-type"] = "text/html; charset=utf-8";
182
- delete headers2["content-encoding"];
183
- delete headers2["content-length"];
184
- res.writeHead(200, headers2);
185
- res.end(html);
186
- log(
187
- `HTML processed: ${requestUrl} (${Date.now() - startTime}ms)`
188
- );
189
- } catch (err) {
190
- logError("Decompress error:", err);
191
- logError("Request URL:", requestUrl);
192
- logError("Response headers:", proxyRes.headers);
193
- res.writeHead(500);
194
- res.end("Decompress error");
195
- }
292
+ handleHtmlResponse(proxyRes, req, res, {
293
+ fullEntry,
294
+ developmentAgentOccupancy,
295
+ clearScriptCssPrefixes,
296
+ log,
297
+ logError,
298
+ startTime
196
299
  });
197
300
  return;
198
301
  }
199
- const headers = rewriteCookies({ ...proxyRes.headers });
302
+ const headers = rewriteCookies({ ...proxyRes.headers }, log);
200
303
  res.writeHead(proxyRes.statusCode, headers);
201
304
  proxyRes.pipe(res);
202
- log(`Proxy request: ${requestUrl} (${Date.now() - startTime}ms)`);
305
+ log(`[Proxy request] ${requestUrl} (${Date.now() - startTime}ms)`);
203
306
  }
204
307
  );
205
308
  },
206
309
  bypass: (req) => {
207
310
  const url = req.url || "";
208
- const pathname = url.split("?")[0];
209
- if ((normalizedStaticPrefix && url.startsWith(`${normalizedStaticPrefix}`) || url.startsWith("/@") || url.startsWith("/src") || url.startsWith("/node_modules") || url.includes(".hot-update.") || url === "/" || bypassRegex.test(pathname)) && !bypassPrefixes.some((prefix) => url.startsWith(prefix))) {
210
- log(`Bypass proxy: ${url}`);
311
+ if (shouldUseLocal(url, normalizedStaticPrefix, remotePrefixes)) {
312
+ log(`shouldUseLocal: ${url}`);
211
313
  return url;
212
314
  }
213
315
  }
@@ -236,4 +338,129 @@ function viteDevProxy(options = {}) {
236
338
  };
237
339
  }
238
340
 
239
- module.exports = viteDevProxy;
341
+ function createVueCliProxyConfig(options) {
342
+ validateOptions(options, "vue-cli-plugin-dev-proxy");
343
+ const {
344
+ https,
345
+ appHost,
346
+ localIndexHtml,
347
+ normalizedStaticPrefix,
348
+ remotePrefixes,
349
+ developmentAgentOccupancy,
350
+ clearScriptCssPrefixes,
351
+ fullEntry,
352
+ log,
353
+ logError
354
+ } = processOptions(options);
355
+ log("vue-cli-plugin-dev-proxy: staticPrefix", normalizedStaticPrefix);
356
+ const protocol = https ? "https://" : "http://";
357
+ return {
358
+ "/": {
359
+ target: `${protocol}${appHost}`,
360
+ changeOrigin: true,
361
+ secure: false,
362
+ ws: false,
363
+ //5.x 版本需要设置,否则会报错 Invalid frame header,4.x 版本不需要设置
364
+ cookieDomainRewrite: { "*": "localhost" },
365
+ selfHandleResponse: true,
366
+ onProxyReq: (proxyReq, req, res) => {
367
+ const upgradeHeader = req.headers.upgrade;
368
+ const isWebSocket = upgradeHeader && upgradeHeader.toLowerCase() === "websocket";
369
+ if (isWebSocket) {
370
+ log(
371
+ `[WebSocket] ${req.method} ${req.url} -> ${protocol}${proxyReq.getHeader("host")}${proxyReq.path}`
372
+ );
373
+ } else {
374
+ log(
375
+ `[proxyReq] ${req.method} ${req.url} -> ${protocol}${proxyReq.getHeader("host")}${proxyReq.path}`
376
+ );
377
+ }
378
+ },
379
+ onError: (err, req, res) => {
380
+ const upgradeHeader = req.headers.upgrade;
381
+ const isWebSocket = upgradeHeader && upgradeHeader.toLowerCase() === "websocket";
382
+ if (isWebSocket) {
383
+ logError(`[WebSocket Error] ${req.url}:`, err.message);
384
+ } else {
385
+ logError(`[proxyError] ${req.url}:`, err.message);
386
+ }
387
+ if (!res.headersSent && !isWebSocket) {
388
+ res.writeHead(500, { "Content-Type": "text/plain" });
389
+ res.end("Proxy Error: " + err.message);
390
+ }
391
+ },
392
+ onProxyRes: (proxyRes, req, res) => {
393
+ const startTime = Date.now();
394
+ const contentType = proxyRes.headers["content-type"] || "";
395
+ const requestUrl = req.url || "";
396
+ const acceptHeader = req.headers.accept || "";
397
+ log(
398
+ `[proxyRes] ${requestUrl} - Status: ${proxyRes.statusCode}, ContentType: ${contentType}`
399
+ );
400
+ const isRedirect = isRedirectResponse(proxyRes);
401
+ if (isRedirect) {
402
+ handleRedirect(proxyRes, req, res, appHost, log, startTime);
403
+ return;
404
+ }
405
+ const shouldProcessHtml = shouldProcessAsHtml(
406
+ contentType,
407
+ acceptHeader,
408
+ requestUrl,
409
+ isRedirect
410
+ );
411
+ log(
412
+ `[shouldProcessHtml] ${shouldProcessHtml}, requestUrl: ${requestUrl}`
413
+ );
414
+ if (shouldProcessHtml) {
415
+ if (localIndexHtml) {
416
+ handleLibModeHtml(localIndexHtml, res, log, logError, startTime);
417
+ return;
418
+ }
419
+ handleHtmlResponse(proxyRes, req, res, {
420
+ fullEntry,
421
+ developmentAgentOccupancy,
422
+ clearScriptCssPrefixes,
423
+ log,
424
+ logError,
425
+ startTime
426
+ });
427
+ return;
428
+ }
429
+ const headers = rewriteCookies({ ...proxyRes.headers }, log);
430
+ res.writeHead(proxyRes.statusCode, headers);
431
+ proxyRes.pipe(res);
432
+ log(`[Proxy request]: ${requestUrl} (${Date.now() - startTime}ms)`);
433
+ },
434
+ bypass: (req) => {
435
+ const url = req.url || "";
436
+ if (shouldUseLocal(url, normalizedStaticPrefix, remotePrefixes)) {
437
+ log(`[shouldUseLocal] ${url}`);
438
+ return url;
439
+ }
440
+ log(`[Proxy] ${url}`);
441
+ return null;
442
+ }
443
+ }
444
+ };
445
+ }
446
+ function vueCliDevProxy(options = {}) {
447
+ if (process.env.NODE_ENV !== "development") {
448
+ return {};
449
+ }
450
+ const proxyConfig = createVueCliProxyConfig(options);
451
+ return {
452
+ devServer: {
453
+ proxy: proxyConfig
454
+ }
455
+ };
456
+ }
457
+
458
+ const index = {
459
+ VitePluginDevProxy: viteDevProxy,
460
+ VueCliPluginDevProxy: vueCliDevProxy
461
+ };
462
+
463
+ exports.VitePluginDevProxy = viteDevProxy;
464
+ exports.VueCliPluginDevProxy = vueCliDevProxy;
465
+ exports.createVueCliProxyConfig = createVueCliProxyConfig;
466
+ exports.default = index;