mock-switch-webpack-plugin 1.0.4 → 1.0.6

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 CHANGED
@@ -1,4 +1,4 @@
1
- # Webpack Mock Switch Plugin
1
+ # Mock Switch Webpack Plugin
2
2
 
3
3
  <div align="center">
4
4
 
@@ -26,7 +26,7 @@
26
26
 
27
27
  ## 🆚 与其他方案对比
28
28
 
29
- | 功能 | webpack-mock-switch-plugin | mocker-api | webpack-api-mocker | mockjs |
29
+ | 功能 | mock-switch-webpack-plugin | mocker-api | webpack-api-mocker | mockjs |
30
30
  |------|---------------------------|------------|-------------------|--------|
31
31
  | 浏览器端一键切换 | ✅ | ❌ | ❌ | ❌ |
32
32
  | Mock数据热更新 | ✅ | ✅ | ✅ | ❌ |
@@ -43,11 +43,11 @@
43
43
  ## 📦 安装
44
44
 
45
45
  ```bash
46
- npm install webpack-mock-switch-plugin --save-dev
46
+ npm install mock-switch-webpack-plugin --save-dev
47
47
  # or
48
- yarn add webpack-mock-switch-plugin -D
48
+ yarn add mock-switch-webpack-plugin -D
49
49
  # or
50
- pnpm add webpack-mock-switch-plugin -D
50
+ pnpm add mock-switch-webpack-plugin -D
51
51
  ```
52
52
 
53
53
  ## 🚀 快速开始
@@ -55,7 +55,7 @@ pnpm add webpack-mock-switch-plugin -D
55
55
  ### 1. 配置 webpack.config.js
56
56
 
57
57
  ```javascript
58
- const WebpackMockSwitchPlugin = require('webpack-mock-switch-plugin');
58
+ const WebpackMockSwitchPlugin = require('mock-switch-webpack-plugin');
59
59
 
60
60
  module.exports = {
61
61
  // ... 其他配置
@@ -269,7 +269,7 @@ npm version major
269
269
  npm link
270
270
 
271
271
  # 在测试项目
272
- npm link webpack-mock-switch-plugin
272
+ npm link mock-switch-webpack-plugin
273
273
  ```
274
274
 
275
275
  ## ❓ 常见问题
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e={497(e,t,o){const n=o(928),r=o(896),s=o(231);let i=null;const a="__MOCK_SWITCH_INSTANCE__";function c(){return global[a]||(global[a]={currentEnv:"mock"}),global[a]}class d{constructor(e={}){var t,o,r,s,i,a;const d=e.environments||{},p={};p.mock={name:"🟢 "+((null===(t=d.mock)||void 0===t||null===(t=t.name)||void 0===t?void 0:t.replace(/^[^\s]+\s*/,""))||"Mock环境"),target:(null===(o=d.mock)||void 0===o?void 0:o.target)??null},p.dev={name:"🟡 "+((null===(r=d.dev)||void 0===r||null===(r=r.name)||void 0===r?void 0:r.replace(/^[^\s]+\s*/,""))||"开发环境"),target:(null===(s=d.dev)||void 0===s?void 0:s.target)??"http://localhost:3000"},p.prod={name:"🔴 "+((null===(i=d.prod)||void 0===i||null===(i=i.name)||void 0===i?void 0:i.replace(/^[^\s]+\s*/,""))||"生产环境"),target:(null===(a=d.prod)||void 0===a?void 0:a.target)??"https://api.example.com"},this.options={mockDir:n.resolve(process.cwd(),"./mock"),apiPrefix:"/api",environments:p,hotReload:!0,autoRegisterMiddleware:!0,...e,environments:p};const l=c();this.currentEnv=l.currentEnv,this.watcher=null,console.log("%s","\n╔══════════════════════════════════════════════════════════════╗\n║ Webpack Mock Switch ║\n║ Version: 2.0.5 ║\n║ 修复: pathRewrite配置错误 ║\n╚══════════════════════════════════════════════════════════════╝\n ")}apply(e){const{webpack:t}=e,{RawSource:o}=t.sources;this.ensureMockDir(),e.hooks.emit.tap("WebpackMockSwitchPlugin",t=>{if("development"!==e.options.mode)return;const n=this.generateClientCode();let r=0;for(const[e,s]of Object.entries(t.assets))if(e.endsWith(".js")&&!e.includes(".hot-update"))try{const i=s.source()+"\n;"+n;t.assets[e]=new o(i),r++}catch(e){}console.log("%s",`[Mock Switch] ✓ 客户端UI已注入 (${r}个文件)`)}),this.options.autoRegisterMiddleware&&e.hooks.afterEnvironment.tap("WebpackMockSwitchPlugin",()=>{e.options.devServer||(e.options.devServer={});const t=e.options.devServer;t.historyApiFallback||(t.historyApiFallback={}),"object"==typeof t.historyApiFallback&&(t.historyApiFallback.rewrites=t.historyApiFallback.rewrites||[],t.historyApiFallback.rewrites.unshift({from:/^\/(__mock_switch__|api)\//,to:e=>e.parsedUrl.pathname}));const o=this;if("function"!=typeof t.setupMiddlewares&&t.setupMiddlewares)if("function"!=typeof t.onBeforeSetupMiddleware&&t.onBeforeSetupMiddleware)if("function"!=typeof t.before&&t.before)console.log("%s","[Mock Switch] 请使用 createMockMiddleware() 手动注册");else{const e=t.before;t.before=(t,n,r)=>{console.log("%s","[Mock Switch] 使用 before (v3)"),o.registerRoutesWithBodyParser(t),"function"==typeof e&&e(t,n,r)},console.log("%s","[Mock Switch] ✓ before 注册成功")}else{const e=t.onBeforeSetupMiddleware;t.onBeforeSetupMiddleware=t=>{console.log("%s","[Mock Switch] 使用 onBeforeSetupMiddleware (v4)"),o.registerRoutesWithBodyParser(t.app),"function"==typeof e&&e(t)},console.log("%s","[Mock Switch] ✓ onBeforeSetupMiddleware 注册成功")}else{const e=t.setupMiddlewares;t.setupMiddlewares=(t,n)=>(console.log("%s","[Mock Switch] 使用 setupMiddlewares (v5+)"),t.unshift((e,t,n)=>{if(e.path.startsWith("/__mock_switch__"))return o.handleControlApi(e,t,n);if(e.path.startsWith(o.options.apiPrefix))switch(o.setNoCacheHeaders(t),o.currentEnv){case"mock":return o.parseBodyThenMock(e,t,n);case"dev":case"prod":return o.serveProxyRequestDirect(e,t,n);default:return n()}n()}),"function"==typeof e?e(t,n):t),console.log("%s","[Mock Switch] ✓ setupMiddlewares 注册成功")}}),this.options.hotReload&&this.startFileWatcher(),console.log("%s","[Mock Switch] 插件初始化完成!")}registerRoutesWithBodyParser(e){const t=this;try{const t=o(Object(function(){var e=new Error("Cannot find module 'express'");throw e.code="MODULE_NOT_FOUND",e}()));e.use(t.json({limit:"50mb"})),e.use(t.urlencoded({extended:!0,limit:"50mb"})),console.log("%s","[Mock Switch] ✓ Body解析中间件已加载")}catch(e){console.log("%s","[Mock Switch] 使用内置body解析")}e.options("/__mock_switch__/*",(e,o)=>{t.setNoCacheHeaders(o),o.setHeader("Access-Control-Allow-Origin","*"),o.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),o.setHeader("Access-Control-Allow-Headers","Content-Type"),o.sendStatus(200)}),e.get("/__mock_switch__/env",(e,o)=>{t.setNoCacheHeaders(o),o.json({currentEnv:t.currentEnv,environments:Object.entries(t.options.environments).map(([e,t])=>({key:e,name:t.name,target:t.target}))})}),e.post("/__mock_switch__/env",(e,o)=>{t.setNoCacheHeaders(o);try{const{env:n}=e.body||{};t.options.environments[n]?(t.currentEnv=n,c().currentEnv=n,console.log("%s",`[Mock Switch] 切换到环境: ${n}`),o.json({success:!0,currentEnv:t.currentEnv})):o.status(400).json({success:!1,error:"无效环境"})}catch(e){o.status(400).json({success:!1,error:e.message})}}),e.all(`${t.options.apiPrefix}/*`,(e,o,n)=>{switch(t.setNoCacheHeaders(o),t.currentEnv){case"mock":t.serveMockFile(e,o,n);break;case"dev":case"prod":t.serveProxyRequest(e,o,n);break;default:n()}}),console.log("%s","[Mock Switch] 所有路由已注册")}handleControlApi(e,t,o){const n=this;if(n.setNoCacheHeaders(t),t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type"),"OPTIONS"===e.method)return t.sendStatus(200);if("/__mock_switch__/env"===e.path&&"GET"===e.method)return t.json({currentEnv:n.currentEnv,environments:Object.entries(n.options.environments).map(([e,t])=>({key:e,name:t.name,target:t.target}))});if("/__mock_switch__/env"===e.path&&"POST"===e.method){if(e.body){const{env:o}=e.body;return n.options.environments[o]?(n.currentEnv=o,c().currentEnv=o,t.json({success:!0,currentEnv:n.currentEnv})):t.status(400).json({success:!1,error:"无效环境"})}let o="";return e.on("data",e=>o+=e),void e.on("end",()=>{try{const{env:e}=JSON.parse(o);n.options.environments[e]?(n.currentEnv=e,c().currentEnv=e,t.json({success:!0,currentEnv:n.currentEnv})):t.status(400).json({success:!1,error:"无效环境"})}catch(e){t.status(400).json({success:!1,error:e.message})}})}o()}parseBodyThenMock(e,t,o){const n=this;if(e.body)n.serveMockFile(e,t,o);else if("POST"===e.method||"PUT"===e.method||"PATCH"===e.method){let r="";e.on("data",e=>r+=e),e.on("end",()=>{try{e.body=r?JSON.parse(r):{}}catch(t){e.body={}}n.serveMockFile(e,t,o)})}else e.body={},n.serveMockFile(e,t,o)}serveProxyRequestDirect(e,t,n){const r=this,s=r.options.environments[r.currentEnv];if(!s||!s.target)return n();const{createProxyMiddleware:i}=o(16),a=i({target:s.target,changeOrigin:!0,pathRewrite:{[`^${r.options.apiPrefix}`]:""},onProxyReq:(e,t,o)=>{if(t.body&&Object.keys(t.body).length>0){const o=JSON.stringify(t.body);e.setHeader("Content-Type","application/json"),e.setHeader("Content-Length",Buffer.byteLength(o)),e.write(o)}},onProxyRes:(e,t,o)=>{delete e.headers.etag,delete e.headers["last-modified"],console.log("%s",`[Proxy] ${t.method} ${t.path} → ${s.target}${t.path.replace(r.options.apiPrefix,"")}`)},onError:(e,t,o)=>{o.status(500).json({error:"代理请求失败",message:e.message,target:s.target})}});a(e,t,n)}setNoCacheHeaders(e){e.setHeader("Cache-Control","no-cache, no-store, must-revalidate, max-age=0"),e.setHeader("Pragma","no-cache"),e.setHeader("Expires","0"),e.setHeader("Access-Control-Allow-Origin","*"),e.removeHeader("ETag"),e.removeHeader("Last-Modified")}ensureMockDir(){r.existsSync(this.options.mockDir)||r.mkdirSync(this.options.mockDir,{recursive:!0})}startFileWatcher(){this.watcher||(this.watcher=s.watch(this.options.mockDir,{ignored:/(^|[\/\\])\../,persistent:!0,ignoreInitial:!0}),this.watcher.on("change",e=>{o.c[o(589).resolve(e)]&&delete o.c[o(589).resolve(e)]}))}async serveMockFile(e,t,n){const s=this,i=s.findMockFile(e.path,e.method);if(i&&r.existsSync(i))try{o.c[o(589).resolve(i)]&&delete o.c[o(589).resolve(i)];let n=o(589)(i);"function"==typeof n&&(n=await n(e,t));const r=n._delay||0;return delete n._delay,void setTimeout(()=>{s.setNoCacheHeaders(t),t.setHeader("Content-Type","application/json"),t.json(n)},r)}catch(e){}s.serveProxyRequestDirect(e,t,n)}async serveProxyRequest(e,t,n){const r=this,s=r.options.environments[r.currentEnv];if(!s||!s.target)return n();const{createProxyMiddleware:i}=o(16),a=i({target:s.target,changeOrigin:!0,pathRewrite:{[`^${r.options.apiPrefix}`]:""},onProxyReq:(e,t,o)=>{if(t.body&&Object.keys(t.body).length>0){const o=JSON.stringify(t.body);e.setHeader("Content-Type","application/json"),e.setHeader("Content-Length",Buffer.byteLength(o)),e.write(o)}},onProxyRes:(e,t,o)=>{delete e.headers.etag,delete e.headers["last-modified"]}});a(e,t,n)}findMockFile(e,t){const o=this,s=e.replace(o.options.apiPrefix,""),i=[n.join(o.options.mockDir,`${t.toUpperCase()}${s.replace(/\//g,"_")}.json`),n.join(o.options.mockDir,`${s.replace(/\//g,"_")}.json`),n.join(o.options.mockDir,`${t.toUpperCase()}${s.replace(/\//g,"_")}.js`),n.join(o.options.mockDir,`${s.replace(/\//g,"_")}.js`),n.join(o.options.mockDir,`${s}.json`),n.join(o.options.mockDir,`${s}.js`)];for(const e of i)if(r.existsSync(e))return e;return null}generateClientCode(){return';(function(){if(typeof window!==\'undefined\'&&!window.__MOCK_SWITCH_INITIALIZED__){window.__MOCK_SWITCH_INITIALIZED__=!0;const e=document.createElement("style");e.textContent=".mock-switch-panel{position:fixed!important;right:20px!important;bottom:20px!important;z-index:999999!important;font-family:-apple-system,BlinkMacSystemFont,\'Segoe UI\',sans-serif!important}.mock-switch-btn{width:56px!important;height:56px!important;border-radius:50%!important;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)!important;border:3px solid white!important;cursor:pointer!important;box-shadow:0 8px 25px rgba(102,126,234,.5)!important;display:flex!important;align-items:center!important;justify-content:center!important;color:white!important;font-size:24px!important;position:relative!important;animation:mockPulse 2s infinite!important}.mock-switch-btn:hover{transform:scale(1.15)!important}@keyframes mockPulse{0%,100%{box-shadow:0 8px 25px rgba(102,126,234,.5)}50%{box-shadow:0 8px 35px rgba(102,126,234,.7)}}.mock-switch-dropdown{position:absolute!important;bottom:70px!important;right:0!important;background:white!important;border-radius:16px!important;box-shadow:0 15px 50px rgba(0,0,0,.25)!important;min-width:260px!important;display:none!important;animation:mockSlideUp .25s ease}.mock-switch-dropdown.show{display:block!important}@keyframes mockSlideUp{from{opacity:0;transform:translateY(20px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.mock-switch-header{padding:18px 24px!important;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)!important;color:white!important;font-weight:600!important}.mock-switch-env-item{padding:14px 24px!important;cursor:pointer!important;display:flex!important;align-items:center!important;gap:14px!important;transition:all .2s ease}.mock-switch-env-item:hover{background:#f8f9fa!important}.mock-switch-env-item.active{background:#f0f4ff!important;color:#667eea!important}.mock-switch-env-item.active .dot{background:#667eea!important;box-shadow:0 0 0 4px rgba(102,126,234,.2)!important}.mock-switch-env-item .dot{width:10px!important;height:10px!important;border-radius:50%!important;background:#ddd!important;transition:all .2s ease}.mock-switch-status{position:absolute!important;top:-2px!important;right:-2px!important;width:18px!important;height:18px!important;border-radius:50%!important;border:3px solid white!important}.mock-switch-status.mock{background:#10b981!important}.mock-switch-status.dev{background:#f59e0b!important}.mock-switch-status.prod{background:#ef4444!important}",document.head.appendChild(e);const t=document.createElement("div");t.className="mock-switch-panel",t.innerHTML=\'<button class="mock-switch-btn" id="mockSwitchToggle" title="Mock环境切换">🎭<span class="mock-switch-status mock" id="mockSwitchStatus"></span></button><div class="mock-switch-dropdown" id="mockSwitchDropdown"><div class="mock-switch-header">🎯 环境切换面板</div><div id="mockSwitchEnvList"></div></div>\',document.body.appendChild(t);let n="mock";async function o(){try{const e=await fetch("/__mock_switch__/env?t="+Date.now(),{cache:"no-store"}),t=await e.json();n=t.currentEnv,i(t.environments),s()}catch(e){}}function i(e){const t=document.getElementById("mockSwitchEnvList");t.innerHTML=e.map(e=>\'<div class="mock-switch-env-item \'+(e.key===n?"active":"")+\'" data-env="\'+e.key+\'"><span class="dot"></span><span>\'+e.name+"</span></div>").join(""),t.querySelectorAll(".mock-switch-env-item").forEach(t=>{t.addEventListener("click",()=>c(t.dataset.env))})}async function c(e){try{await fetch("/__mock_switch__/env",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({env:e})}),n=e,s(),o()}catch(e){}}function s(){const e=document.getElementById("mockSwitchStatus");e.className="mock-switch-status "+n}document.getElementById("mockSwitchToggle").addEventListener("click",e=>{e.stopPropagation();document.getElementById("mockSwitchDropdown").classList.toggle("show")}),document.addEventListener("click",()=>{document.getElementById("mockSwitchDropdown").classList.remove("show")}),document.getElementById("mockSwitchDropdown").addEventListener("click",e=>{e.stopPropagation()}),o()}})();'}}e.exports=d,e.exports.default=d,e.exports.createMockMiddleware=function(e,t={}){return i?(console.log("%s","[Mock Switch] 复用已有单例实例(热重载)"),i):(i=new d({...t,autoRegisterMiddleware:!1,hotReload:!0}),i.registerRoutesWithBodyParser(e),console.log("%s","[Mock Switch] ✓ CRA中间件已注册成功(单例模式)"),i)}},589(e){function t(e){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}t.keys=()=>[],t.resolve=t,t.id=589,e.exports=t},231(e){"use strict";e.exports=require("chokidar")},16(e){"use strict";e.exports=require("http-proxy-middleware")},896(e){"use strict";e.exports=require("fs")},928(e){"use strict";e.exports=require("path")}},t={};function o(n){var r=t[n];if(void 0!==r)return r.exports;var s=t[n]={id:n,loaded:!1,exports:{}};return e[n](s,s.exports,o),s.loaded=!0,s.exports}o.c=t,o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n=o(497);module.exports=n})();
1
+ (()=>{var e={497(e,t,o){const n="undefined"!=typeof require?require:o(589),r=n("path"),s=n("fs"),i=n("chokidar");let a=null;const c="__MOCK_SWITCH_INSTANCE__";function d(){return global[c]||(global[c]={currentEnv:"mock"}),global[c]}class p{constructor(e={}){var t,o,n,s,i,a;const c=e.environments||{},p={};p.mock={name:"🟢 "+((null===(t=c.mock)||void 0===t||null===(t=t.name)||void 0===t?void 0:t.replace(/^[^\s]+\s*/,""))||"Mock环境"),target:(null===(o=c.mock)||void 0===o?void 0:o.target)??null},p.dev={name:"🟡 "+((null===(n=c.dev)||void 0===n||null===(n=n.name)||void 0===n?void 0:n.replace(/^[^\s]+\s*/,""))||"开发环境"),target:(null===(s=c.dev)||void 0===s?void 0:s.target)??"http://localhost:3000"},p.prod={name:"🔴 "+((null===(i=c.prod)||void 0===i||null===(i=i.name)||void 0===i?void 0:i.replace(/^[^\s]+\s*/,""))||"生产环境"),target:(null===(a=c.prod)||void 0===a?void 0:a.target)??"https://api.example.com"},this.options={mockDir:r.resolve(process.cwd(),"./mock"),apiPrefix:"/api",environments:p,hotReload:!0,autoRegisterMiddleware:!0,...e,environments:p};const l=d();this.currentEnv=l.currentEnv,this.watcher=null,console.log("%s","\n╔══════════════════════════════════════════════════════════════╗\n║ Webpack Mock Switch ║\n║ Version: 2.0.5 ║\n║ 修复: pathRewrite配置错误 ║\n╚══════════════════════════════════════════════════════════════╝\n ")}apply(e){const{webpack:t}=e,{RawSource:o}=t.sources;this.ensureMockDir(),e.hooks.emit.tap("WebpackMockSwitchPlugin",t=>{if("development"!==e.options.mode)return;const n=this.generateClientCode();let r=0;for(const[e,s]of Object.entries(t.assets))if(e.endsWith(".js")&&!e.includes(".hot-update"))try{const i=s.source()+"\n;"+n;t.assets[e]=new o(i),r++}catch(e){}console.log("%s",`[Mock Switch] ✓ 客户端UI已注入 (${r}个文件)`)}),this.options.autoRegisterMiddleware&&e.hooks.afterEnvironment.tap("WebpackMockSwitchPlugin",()=>{e.options.devServer||(e.options.devServer={});const t=e.options.devServer;t.historyApiFallback||(t.historyApiFallback={}),"object"==typeof t.historyApiFallback&&(t.historyApiFallback.rewrites=t.historyApiFallback.rewrites||[],t.historyApiFallback.rewrites.unshift({from:/^\/(__mock_switch__|api)\//,to:e=>e.parsedUrl.pathname}));const o=this;if("function"!=typeof t.setupMiddlewares&&t.setupMiddlewares)if("function"!=typeof t.onBeforeSetupMiddleware&&t.onBeforeSetupMiddleware)if("function"!=typeof t.before&&t.before)console.log("%s","[Mock Switch] 请使用 createMockMiddleware() 手动注册");else{const e=t.before;t.before=(t,n,r)=>{console.log("%s","[Mock Switch] 使用 before (v3)"),o.registerRoutesWithBodyParser(t),"function"==typeof e&&e(t,n,r)},console.log("%s","[Mock Switch] ✓ before 注册成功")}else{const e=t.onBeforeSetupMiddleware;t.onBeforeSetupMiddleware=t=>{console.log("%s","[Mock Switch] 使用 onBeforeSetupMiddleware (v4)"),o.registerRoutesWithBodyParser(t.app),"function"==typeof e&&e(t)},console.log("%s","[Mock Switch] ✓ onBeforeSetupMiddleware 注册成功")}else{const e=t.setupMiddlewares;t.setupMiddlewares=(t,n)=>(console.log("%s","[Mock Switch] 使用 setupMiddlewares (v5+)"),t.unshift((e,t,n)=>{if(e.path.startsWith("/__mock_switch__"))return o.handleControlApi(e,t,n);if(e.path.startsWith(o.options.apiPrefix))switch(o.setNoCacheHeaders(t),o.currentEnv){case"mock":return o.parseBodyThenMock(e,t,n);case"dev":case"prod":return o.serveProxyRequestDirect(e,t,n);default:return n()}n()}),"function"==typeof e?e(t,n):t),console.log("%s","[Mock Switch] ✓ setupMiddlewares 注册成功")}}),this.options.hotReload&&this.startFileWatcher(),console.log("%s","[Mock Switch] 插件初始化完成!")}registerRoutesWithBodyParser(e){const t=this;try{const t=n("express");e.use(t.json({limit:"50mb"})),e.use(t.urlencoded({extended:!0,limit:"50mb"})),console.log("%s","[Mock Switch] ✓ Body解析中间件已加载")}catch(e){console.log("%s","[Mock Switch] 使用内置body解析")}e.options("/__mock_switch__/*",(e,o)=>{t.setNoCacheHeaders(o),o.setHeader("Access-Control-Allow-Origin","*"),o.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),o.setHeader("Access-Control-Allow-Headers","Content-Type"),o.sendStatus(200)}),e.get("/__mock_switch__/env",(e,o)=>{t.setNoCacheHeaders(o),o.json({currentEnv:t.currentEnv,environments:Object.entries(t.options.environments).map(([e,t])=>({key:e,name:t.name,target:t.target}))})}),e.post("/__mock_switch__/env",(e,o)=>{t.setNoCacheHeaders(o);try{const{env:n}=e.body||{};t.options.environments[n]?(t.currentEnv=n,d().currentEnv=n,console.log("%s",`[Mock Switch] 切换到环境: ${n}`),o.json({success:!0,currentEnv:t.currentEnv})):o.status(400).json({success:!1,error:"无效环境"})}catch(e){o.status(400).json({success:!1,error:e.message})}}),e.all(`${t.options.apiPrefix}/*`,(e,o,n)=>{switch(t.setNoCacheHeaders(o),t.currentEnv){case"mock":t.serveMockFile(e,o,n);break;case"dev":case"prod":t.serveProxyRequest(e,o,n);break;default:n()}}),console.log("%s","[Mock Switch] 所有路由已注册")}handleControlApi(e,t,o){const n=this;if(n.setNoCacheHeaders(t),t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type"),"OPTIONS"===e.method)return t.sendStatus(200);if("/__mock_switch__/env"===e.path&&"GET"===e.method)return t.json({currentEnv:n.currentEnv,environments:Object.entries(n.options.environments).map(([e,t])=>({key:e,name:t.name,target:t.target}))});if("/__mock_switch__/env"===e.path&&"POST"===e.method){if(e.body){const{env:o}=e.body;return n.options.environments[o]?(n.currentEnv=o,d().currentEnv=o,t.json({success:!0,currentEnv:n.currentEnv})):t.status(400).json({success:!1,error:"无效环境"})}let o="";return e.on("data",e=>o+=e),void e.on("end",()=>{try{const{env:e}=JSON.parse(o);n.options.environments[e]?(n.currentEnv=e,d().currentEnv=e,t.json({success:!0,currentEnv:n.currentEnv})):t.status(400).json({success:!1,error:"无效环境"})}catch(e){t.status(400).json({success:!1,error:e.message})}})}o()}parseBodyThenMock(e,t,o){const n=this;if(e.body)n.serveMockFile(e,t,o);else if("POST"===e.method||"PUT"===e.method||"PATCH"===e.method){let r="";e.on("data",e=>r+=e),e.on("end",()=>{try{e.body=r?JSON.parse(r):{}}catch(t){e.body={}}n.serveMockFile(e,t,o)})}else e.body={},n.serveMockFile(e,t,o)}serveProxyRequestDirect(e,t,o){const r=this,s=r.options.environments[r.currentEnv];if(!s||!s.target)return o();const{createProxyMiddleware:i}=n("http-proxy-middleware"),a=i({target:s.target,changeOrigin:!0,pathRewrite:{[`^${r.options.apiPrefix}`]:""},onProxyReq:(e,t,o)=>{if(t.body&&Object.keys(t.body).length>0){const o=JSON.stringify(t.body);e.setHeader("Content-Type","application/json"),e.setHeader("Content-Length",Buffer.byteLength(o)),e.write(o)}},onProxyRes:(e,t,o)=>{delete e.headers.etag,delete e.headers["last-modified"],console.log("%s",`[Proxy] ${t.method} ${t.path} → ${s.target}${t.path.replace(r.options.apiPrefix,"")}`)},onError:(e,t,o)=>{o.status(500).json({error:"代理请求失败",message:e.message,target:s.target})}});a(e,t,o)}setNoCacheHeaders(e){e.setHeader("Cache-Control","no-cache, no-store, must-revalidate, max-age=0"),e.setHeader("Pragma","no-cache"),e.setHeader("Expires","0"),e.setHeader("Access-Control-Allow-Origin","*"),e.removeHeader("ETag"),e.removeHeader("Last-Modified")}ensureMockDir(){s.existsSync(this.options.mockDir)||s.mkdirSync(this.options.mockDir,{recursive:!0})}startFileWatcher(){this.watcher||(this.watcher=i.watch(this.options.mockDir,{ignored:/(^|[\/\\])\../,persistent:!0,ignoreInitial:!0}),this.watcher.on("change",e=>{n.cache[n.resolve(e)]&&delete n.cache[n.resolve(e)]}))}async serveMockFile(e,t,o){const r=this,i=r.findMockFile(e.path,e.method);if(i&&s.existsSync(i))try{n.cache[n.resolve(i)]&&delete n.cache[n.resolve(i)];let o=n(i);"function"==typeof o&&(o=await o(e,t));const s=o._delay||0;return delete o._delay,void setTimeout(()=>{r.setNoCacheHeaders(t),t.setHeader("Content-Type","application/json"),t.json(o)},s)}catch(e){}r.serveProxyRequestDirect(e,t,o)}async serveProxyRequest(e,t,o){const r=this,s=r.options.environments[r.currentEnv];if(!s||!s.target)return o();const{createProxyMiddleware:i}=n("http-proxy-middleware"),a=i({target:s.target,changeOrigin:!0,pathRewrite:{[`^${r.options.apiPrefix}`]:""},onProxyReq:(e,t,o)=>{if(t.body&&Object.keys(t.body).length>0){const o=JSON.stringify(t.body);e.setHeader("Content-Type","application/json"),e.setHeader("Content-Length",Buffer.byteLength(o)),e.write(o)}},onProxyRes:(e,t,o)=>{delete e.headers.etag,delete e.headers["last-modified"]}});a(e,t,o)}findMockFile(e,t){const o=this,n=e.replace(o.options.apiPrefix,""),i=[r.join(o.options.mockDir,`${t.toUpperCase()}${n.replace(/\//g,"_")}.json`),r.join(o.options.mockDir,`${n.replace(/\//g,"_")}.json`),r.join(o.options.mockDir,`${t.toUpperCase()}${n.replace(/\//g,"_")}.js`),r.join(o.options.mockDir,`${n.replace(/\//g,"_")}.js`),r.join(o.options.mockDir,`${n}.json`),r.join(o.options.mockDir,`${n}.js`)];for(const e of i)if(s.existsSync(e))return e;return null}generateClientCode(){return';(function(){if(typeof window!==\'undefined\'&&!window.__MOCK_SWITCH_INITIALIZED__){window.__MOCK_SWITCH_INITIALIZED__=!0;const e=document.createElement("style");e.textContent=".mock-switch-panel{position:fixed!important;right:20px!important;bottom:20px!important;z-index:999999!important;font-family:-apple-system,BlinkMacSystemFont,\'Segoe UI\',sans-serif!important}.mock-switch-btn{width:56px!important;height:56px!important;border-radius:50%!important;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)!important;border:3px solid white!important;cursor:pointer!important;box-shadow:0 8px 25px rgba(102,126,234,.5)!important;display:flex!important;align-items:center!important;justify-content:center!important;color:white!important;font-size:24px!important;position:relative!important;animation:mockPulse 2s infinite!important}.mock-switch-btn:hover{transform:scale(1.15)!important}@keyframes mockPulse{0%,100%{box-shadow:0 8px 25px rgba(102,126,234,.5)}50%{box-shadow:0 8px 35px rgba(102,126,234,.7)}}.mock-switch-dropdown{position:absolute!important;bottom:70px!important;right:0!important;background:white!important;border-radius:16px!important;box-shadow:0 15px 50px rgba(0,0,0,.25)!important;min-width:260px!important;display:none!important;animation:mockSlideUp .25s ease}.mock-switch-dropdown.show{display:block!important}@keyframes mockSlideUp{from{opacity:0;transform:translateY(20px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.mock-switch-header{padding:18px 24px!important;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)!important;color:white!important;font-weight:600!important}.mock-switch-env-item{padding:14px 24px!important;cursor:pointer!important;display:flex!important;align-items:center!important;gap:14px!important;transition:all .2s ease}.mock-switch-env-item:hover{background:#f8f9fa!important}.mock-switch-env-item.active{background:#f0f4ff!important;color:#667eea!important}.mock-switch-env-item.active .dot{background:#667eea!important;box-shadow:0 0 0 4px rgba(102,126,234,.2)!important}.mock-switch-env-item .dot{width:10px!important;height:10px!important;border-radius:50%!important;background:#ddd!important;transition:all .2s ease}.mock-switch-status{position:absolute!important;top:-2px!important;right:-2px!important;width:18px!important;height:18px!important;border-radius:50%!important;border:3px solid white!important}.mock-switch-status.mock{background:#10b981!important}.mock-switch-status.dev{background:#f59e0b!important}.mock-switch-status.prod{background:#ef4444!important}",document.head.appendChild(e);const t=document.createElement("div");t.className="mock-switch-panel",t.innerHTML=\'<button class="mock-switch-btn" id="mockSwitchToggle" title="Mock环境切换">🎭<span class="mock-switch-status mock" id="mockSwitchStatus"></span></button><div class="mock-switch-dropdown" id="mockSwitchDropdown"><div class="mock-switch-header">🎯 环境切换面板</div><div id="mockSwitchEnvList"></div></div>\',document.body.appendChild(t);let n="mock";async function o(){try{const e=await fetch("/__mock_switch__/env?t="+Date.now(),{cache:"no-store"}),t=await e.json();n=t.currentEnv,i(t.environments),s()}catch(e){}}function i(e){const t=document.getElementById("mockSwitchEnvList");t.innerHTML=e.map(e=>\'<div class="mock-switch-env-item \'+(e.key===n?"active":"")+\'" data-env="\'+e.key+\'"><span class="dot"></span><span>\'+e.name+"</span></div>").join(""),t.querySelectorAll(".mock-switch-env-item").forEach(t=>{t.addEventListener("click",()=>c(t.dataset.env))})}async function c(e){try{await fetch("/__mock_switch__/env",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({env:e})}),n=e,s(),o()}catch(e){}}function s(){const e=document.getElementById("mockSwitchStatus");e.className="mock-switch-status "+n}document.getElementById("mockSwitchToggle").addEventListener("click",e=>{e.stopPropagation();document.getElementById("mockSwitchDropdown").classList.toggle("show")}),document.addEventListener("click",()=>{document.getElementById("mockSwitchDropdown").classList.remove("show")}),document.getElementById("mockSwitchDropdown").addEventListener("click",e=>{e.stopPropagation()}),o()}})();'}}e.exports=p,e.exports.default=p,e.exports.createMockMiddleware=function(e,t={}){return a?(console.log("%s","[Mock Switch] 复用已有单例实例(热重载)"),a):(a=new p({...t,autoRegisterMiddleware:!1,hotReload:!0}),a.registerRoutesWithBodyParser(e),console.log("%s","[Mock Switch] ✓ CRA中间件已注册成功(单例模式)"),a)}},589(e){function t(e){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}t.keys=()=>[],t.resolve=t,t.id=589,e.exports=t}},t={};function o(n){var r=t[n];if(void 0!==r)return r.exports;var s=t[n]={exports:{}};return e[n](s,s.exports,o),s.exports}o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n=o(497);module.exports=n})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mock-switch-webpack-plugin",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "前端Mock神器!浏览器端一键切换Mock/开发/生产环境的Webpack插件,支持接口代理、Mock数据热更新、POST请求自动转发等特性,零配置接入React/Vue等所有Webpack项目,彻底告别需手动修改代码来切换环境的低效开发方式",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {