UNPKG

rspack-plugin-mock

Version:
203 lines (201 loc) 6.65 kB
import { buildMockServer, createMockCompiler, createMockMiddleware, resolvePluginOptions } from "./chunk-HV5L72CY.js"; import { mockWebSocket, rewriteRequest } from "./chunk-OGWV5ZGG.js"; // src/rsbuild.ts import { createServer } from "node:http"; import path from "node:path"; import process from "node:process"; import { isArray, toArray } from "@pengzhanbo/utils"; import rspack from "@rspack/core"; import color from "picocolors"; import { getPortPromise } from "portfinder"; function pluginMockServer(options = {}) { return { name: "plugin-mock-server", setup(api) { const rsbuildConfig = api.getRsbuildConfig(); const resolvedOptions = resolvePluginOptions(options, { proxies: resolveConfigProxies(rsbuildConfig), alias: {}, context: api.context.rootPath, plugins: [new rspack.DefinePlugin(rsbuildConfig.source?.define || {})] }); if (process.env.NODE_ENV === "production") { if (resolvedOptions.build) { api.onAfterBuild(async () => { const config = api.getNormalizedConfig(); await buildMockServer( resolvedOptions, path.resolve(process.cwd(), config.output.distPath.root || "dist") ); }); } return; } const mockCompiler = createMockCompiler(resolvedOptions); api.modifyRsbuildConfig((config) => { updateServerProxyConfigByHttpMock(config); const mockMiddleware = createMockMiddleware(mockCompiler, resolvedOptions); config.dev ??= {}; config.dev.setupMiddlewares ??= []; config.dev.setupMiddlewares.push((middlewares, server2) => { mockMiddleware(middlewares, () => server2.sockWrite("static-changed")); }); }); let port = 3079; const shouldMockWs = toArray(resolvedOptions.wsPrefix).length > 0; if (shouldMockWs) { api.modifyRsbuildConfig(async (config) => { const defaultPort = (config.server?.port || port) + 1; port = await getPortPromise({ port: defaultPort }); updateServerProxyConfigByWSMock(config, options.wsPrefix || [], port); }); } let server; function startMockServer() { mockCompiler.run(); if (shouldMockWs) { server = createServer(); mockWebSocket(mockCompiler, server, resolvedOptions); server.listen(port); } } function close() { mockCompiler.close(); server?.close(); } api.onAfterCreateCompiler(({ compiler }) => { if ("compilers" in compiler) { compiler.compilers.forEach((compiler2) => { mockCompiler.updateAlias(compiler2.options.resolve?.alias || {}); }); } else { mockCompiler.updateAlias(compiler.options.resolve?.alias || {}); } }); api.onAfterStartDevServer(startMockServer); api.onAfterStartProdServer(startMockServer); api.onExit(close); } }; } function onProxyError(err, _req, res) { console.error(color.red(err?.stack || err.message)); res.statusCode = 500; res.end(); } function updateServerProxyConfigByHttpMock(config) { if (!config.server?.proxy) return; if (isArray(config.server.proxy)) { config.server.proxy = config.server.proxy.map((item) => { if (typeof item !== "function" && !item.ws) { const onProxyReq = item.onProxyReq; const onError = item.onError; return { ...item, onError: onError || onProxyError, onProxyReq: (proxyReq, req, ...args) => { onProxyReq?.(proxyReq, req, ...args); rewriteRequest(proxyReq, req); } }; } return item; }); } else if ("target" in config.server.proxy) { const onProxyReq = config.server.proxy.onProxyReq; config.server.proxy.onProxyReq = (proxyReq, req, ...args) => { onProxyReq?.(proxyReq, req, ...args); rewriteRequest(proxyReq, req); }; config.server.proxy.onError ??= onProxyError; } else if (config.server.proxy) { const proxy = config.server.proxy; Object.keys(proxy).forEach((key) => { const target = proxy[key]; const options = typeof target === "string" ? { target } : target; if (options.ws) return; const { onProxyReq, onError, ...rest } = options; proxy[key] = { ...rest, onProxyReq: (proxyReq, req, ...args) => { onProxyReq?.(proxyReq, req, ...args); rewriteRequest(proxyReq, req); }, onError: onError || onProxyError }; }); } } function updateServerProxyConfigByWSMock(config, wsPrefix, port) { config.server ??= {}; const proxy = config.server.proxy ??= {}; const wsTarget = `ws://localhost:${port}`; const prefix = toArray(wsPrefix); const has = (context) => typeof context === "string" && prefix.includes(context); const used = /* @__PURE__ */ new Set(); function updateProxy(item) { if (isArray(item.context)) { item.context = item.context.filter(has); } else if (has(item.context)) { used.add(item.context); item.target = wsTarget; } } if (isArray(proxy)) { for (const item of proxy) { if (typeof item !== "function" && item.context && item.ws) { updateProxy(item); } } prefix.filter((context) => !used.has(context)).forEach((context) => proxy.push({ context, target: wsTarget })); } else if ("target" in proxy) { if (proxy.ws) { updateProxy(proxy); const list = config.server.proxy = [proxy]; prefix.filter((context) => !used.has(context)).forEach((context) => list.push({ context, target: wsTarget })); } } else { Object.entries(proxy).forEach(([, opt]) => { if (typeof opt !== "string" && opt.ws) { updateProxy(opt); } }); prefix.filter((context) => !used.has(context)).forEach((context) => { proxy[context] = { target: wsTarget, ws: true }; }); } } function resolveConfigProxies(config) { config.server ??= {}; const proxy = config.server.proxy ??= {}; const proxies = []; if (isArray(proxy)) { for (const item of proxy) { if (typeof item !== "function" && item.context && !item.ws) { proxies.push(...toArray(item.context)); } } } else if ("target" in proxy) { if (!proxy.ws) proxies.push(...toArray(proxy.context)); } else { Object.entries(proxy).forEach(([context, opt]) => { if (typeof opt === "string" || !opt.ws) proxies.push(context); }); } return proxies; } export { pluginMockServer };