13f6b013ef713fa4812ea7a4d34cd19f919319fdaa4a5f8ed41048a95813b6e8daf07083b3a489c89e6fa02ef6592427d83d789d78f135253448b4beba8920 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var __defProp = Object.defineProperty;
  2. var __hasOwnProp = Object.prototype.hasOwnProperty;
  3. var __getOwnPropSymbols = Object.getOwnPropertySymbols;
  4. var __propIsEnum = Object.prototype.propertyIsEnumerable;
  5. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {enumerable: true, configurable: true, writable: true, value}) : obj[key] = value;
  6. var __assign = (a, b) => {
  7. for (var prop in b || (b = {}))
  8. if (__hasOwnProp.call(b, prop))
  9. __defNormalProp(a, prop, b[prop]);
  10. if (__getOwnPropSymbols)
  11. for (var prop of __getOwnPropSymbols(b)) {
  12. if (__propIsEnum.call(b, prop))
  13. __defNormalProp(a, prop, b[prop]);
  14. }
  15. return a;
  16. };
  17. // src/index.ts
  18. var _path = require('path'); var _path2 = _interopRequireDefault(_path);
  19. // src/utils.ts
  20. var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);
  21. var toString = Object.prototype.toString;
  22. function is(val, type) {
  23. return toString.call(val) === `[object ${type}]`;
  24. }
  25. function isFunction(val) {
  26. return is(val, "Function") || is(val, "AsyncFunction");
  27. }
  28. function isArray(val) {
  29. return val && Array.isArray(val);
  30. }
  31. function isRegExp(val) {
  32. return is(val, "RegExp");
  33. }
  34. function sleep(time) {
  35. return new Promise((resolve) => {
  36. setTimeout(() => {
  37. resolve("");
  38. }, time);
  39. });
  40. }
  41. function fileExists(f) {
  42. try {
  43. _fs2.default.accessSync(f, _fs2.default.constants.W_OK);
  44. return true;
  45. } catch (error) {
  46. return false;
  47. }
  48. }
  49. // src/index.ts
  50. var _vite = require('vite');
  51. // src/createMockServer.ts
  52. var _chokidar = require('chokidar'); var _chokidar2 = _interopRequireDefault(_chokidar);
  53. var _chalk = require('chalk'); var _chalk2 = _interopRequireDefault(_chalk);
  54. var _url = require('url'); var _url2 = _interopRequireDefault(_url);
  55. var _fastglob = require('fast-glob'); var _fastglob2 = _interopRequireDefault(_fastglob);
  56. var _mockjs = require('mockjs'); var _mockjs2 = _interopRequireDefault(_mockjs);
  57. var _esbuild = require('esbuild');
  58. var _pathtoregexp = require('path-to-regexp');
  59. var _module = require('module'); var _module2 = _interopRequireDefault(_module);
  60. var mockData = [];
  61. async function createMockServer(opt = {mockPath: "mock", configPath: "vite.mock.config"}) {
  62. opt = __assign({
  63. mockPath: "mock",
  64. watchFiles: true,
  65. supportTs: true,
  66. configPath: "vite.mock.config.ts",
  67. logger: true
  68. }, opt);
  69. if (mockData.length > 0)
  70. return;
  71. mockData = await getMockConfig(opt);
  72. await createWatch(opt);
  73. }
  74. async function requestMiddleware(opt) {
  75. const {logger = true} = opt;
  76. const middleware = async (req, res, next) => {
  77. let queryParams = {};
  78. if (req.url) {
  79. queryParams = _url2.default.parse(req.url, true);
  80. }
  81. const reqUrl = queryParams.pathname;
  82. const matchRequest = mockData.find((item) => {
  83. if (!reqUrl || !item || !item.url) {
  84. return false;
  85. }
  86. if (item.method && item.method.toUpperCase() !== req.method) {
  87. return false;
  88. }
  89. return _pathtoregexp.pathToRegexp.call(void 0, item.url).test(reqUrl);
  90. });
  91. if (matchRequest) {
  92. const isGet = req.method && req.method.toUpperCase() === "GET";
  93. const {response, rawResponse, timeout, statusCode, url: url2} = matchRequest;
  94. if (timeout) {
  95. await sleep(timeout);
  96. }
  97. const urlMatch = _pathtoregexp.match.call(void 0, url2, {decode: decodeURIComponent});
  98. let query = queryParams.query;
  99. if (reqUrl) {
  100. if (isGet && JSON.stringify(query) === "{}" || !isGet) {
  101. const params = urlMatch(reqUrl).params;
  102. if (JSON.stringify(params) !== "{}") {
  103. query = urlMatch(reqUrl).params || {};
  104. } else {
  105. query = queryParams.query || {};
  106. }
  107. }
  108. }
  109. const self = {req, res, parseJson: parseJson.bind(null, req)};
  110. if (isFunction(rawResponse)) {
  111. await rawResponse.bind(self)(req, res);
  112. } else {
  113. const body = await parseJson(req);
  114. res.setHeader("Content-Type", "application/json");
  115. res.statusCode = statusCode || 200;
  116. const mockResponse = isFunction(response) ? response.bind(self)({url: req.url, body, query, headers: req.headers}) : response;
  117. res.end(JSON.stringify(_mockjs2.default.mock(mockResponse)));
  118. }
  119. logger && loggerOutput("request invoke", req.url);
  120. return;
  121. }
  122. next();
  123. };
  124. return middleware;
  125. }
  126. function createWatch(opt) {
  127. const {configPath, logger, watchFiles} = opt;
  128. if (!watchFiles) {
  129. return;
  130. }
  131. const {absConfigPath, absMockPath} = getPath(opt);
  132. if (process.env.VITE_DISABLED_WATCH_MOCK === "true") {
  133. return;
  134. }
  135. const watchDir = [];
  136. const exitsConfigPath = _fs2.default.existsSync(absConfigPath);
  137. exitsConfigPath && configPath ? watchDir.push(absConfigPath) : watchDir.push(absMockPath);
  138. const watcher = _chokidar2.default.watch(watchDir, {
  139. ignoreInitial: true
  140. });
  141. watcher.on("all", async (event, file) => {
  142. logger && loggerOutput(`mock file ${event}`, file);
  143. mockData = await getMockConfig(opt);
  144. });
  145. }
  146. function cleanRequireCache(opt) {
  147. if (!require.cache) {
  148. return;
  149. }
  150. const {absConfigPath, absMockPath} = getPath(opt);
  151. Object.keys(require.cache).forEach((file) => {
  152. if (file === absConfigPath || file.indexOf(absMockPath) > -1) {
  153. delete require.cache[file];
  154. }
  155. });
  156. }
  157. function parseJson(req) {
  158. return new Promise((resolve) => {
  159. let body = "";
  160. let jsonStr = "";
  161. req.on("data", function(chunk) {
  162. body += chunk;
  163. });
  164. req.on("end", function() {
  165. try {
  166. jsonStr = JSON.parse(body);
  167. } catch (err) {
  168. jsonStr = "";
  169. }
  170. resolve(jsonStr);
  171. return;
  172. });
  173. });
  174. }
  175. async function getMockConfig(opt) {
  176. cleanRequireCache(opt);
  177. const {absConfigPath, absMockPath} = getPath(opt);
  178. const {ignore, configPath, logger} = opt;
  179. let ret = [];
  180. if (configPath && _fs2.default.existsSync(absConfigPath)) {
  181. logger && loggerOutput(`load mock data from`, absConfigPath);
  182. ret = await resolveModule(absConfigPath);
  183. return ret;
  184. }
  185. const mockFiles = _fastglob2.default.sync(`**/*.{ts,js}`, {
  186. cwd: absMockPath
  187. }).filter((item) => {
  188. if (!ignore) {
  189. return true;
  190. }
  191. if (isFunction(ignore)) {
  192. return ignore(item);
  193. }
  194. if (isRegExp(ignore)) {
  195. return !ignore.test(_path2.default.basename(item));
  196. }
  197. return true;
  198. });
  199. try {
  200. ret = [];
  201. const resolveModulePromiseList = [];
  202. for (let index = 0; index < mockFiles.length; index++) {
  203. const mockFile = mockFiles[index];
  204. resolveModulePromiseList.push(resolveModule(_path2.default.join(absMockPath, mockFile)));
  205. }
  206. const loadAllResult = await Promise.all(resolveModulePromiseList);
  207. for (const resultModule of loadAllResult) {
  208. let mod = resultModule;
  209. if (!isArray(mod)) {
  210. mod = [mod];
  211. }
  212. ret = [...ret, ...mod];
  213. }
  214. } catch (error) {
  215. loggerOutput(`mock reload error`, error);
  216. ret = [];
  217. }
  218. return ret;
  219. }
  220. async function resolveModule(p) {
  221. const result = await _esbuild.build.call(void 0, {
  222. entryPoints: [p],
  223. outfile: "out.js",
  224. write: false,
  225. platform: "node",
  226. bundle: true,
  227. format: "cjs",
  228. metafile: true,
  229. target: "es2015"
  230. });
  231. const {text} = result.outputFiles[0];
  232. return await loadConfigFromBundledFile(p, text);
  233. }
  234. function getPath(opt) {
  235. const {mockPath, configPath} = opt;
  236. const cwd = process.cwd();
  237. const absMockPath = _path2.default.join(cwd, mockPath || "");
  238. const absConfigPath = _path2.default.join(cwd, configPath || "");
  239. return {
  240. absMockPath,
  241. absConfigPath
  242. };
  243. }
  244. function loggerOutput(title, msg, type = "info") {
  245. const tag = type === "info" ? _chalk2.default.cyan.bold(`[vite:mock]`) : _chalk2.default.red.bold(`[vite:mock-server]`);
  246. return console.log(`${_chalk2.default.dim(new Date().toLocaleTimeString())} ${tag} ${_chalk2.default.green(title)} ${_chalk2.default.dim(msg)}`);
  247. }
  248. async function loadConfigFromBundledFile(fileName, bundledCode) {
  249. const extension = _path2.default.extname(fileName);
  250. const extensions = _module2.default.Module._extensions;
  251. let defaultLoader;
  252. const isJs = extension === ".js";
  253. if (isJs) {
  254. defaultLoader = extensions[extension];
  255. }
  256. extensions[extension] = (module2, filename) => {
  257. if (filename === fileName) {
  258. ;
  259. module2._compile(bundledCode, filename);
  260. } else {
  261. if (!isJs) {
  262. extensions[extension](module2, filename);
  263. } else {
  264. defaultLoader(module2, filename);
  265. }
  266. }
  267. };
  268. let config;
  269. try {
  270. if (isJs && require && require.cache) {
  271. delete require.cache[fileName];
  272. }
  273. const raw = require(fileName);
  274. config = raw.__esModule ? raw.default : raw;
  275. if (defaultLoader && isJs) {
  276. extensions[extension] = defaultLoader;
  277. }
  278. } catch (error) {
  279. console.error(error);
  280. }
  281. return config;
  282. }
  283. // src/index.ts
  284. (async () => {
  285. try {
  286. await Promise.resolve().then(() => _interopRequireWildcard(require("mockjs")));
  287. } catch (e) {
  288. throw new Error("vite-plugin-vue-mock requires mockjs to be present in the dependency tree.");
  289. }
  290. })();
  291. function getDefaultPath(supportTs = true) {
  292. return _path2.default.resolve(process.cwd(), `src/main.${supportTs ? "ts" : "js"}`);
  293. }
  294. function viteMockServe(opt = {}) {
  295. let defaultPath = getDefaultPath();
  296. if (!fileExists(defaultPath)) {
  297. defaultPath = getDefaultPath(false);
  298. if (!fileExists(defaultPath)) {
  299. defaultPath = "";
  300. }
  301. }
  302. const defaultEnter = _vite.normalizePath.call(void 0, defaultPath);
  303. const {injectFile = defaultEnter} = opt;
  304. let isDev = false;
  305. let config;
  306. let needSourcemap = false;
  307. return {
  308. name: "vite:mock",
  309. enforce: "pre",
  310. configResolved(resolvedConfig) {
  311. config = resolvedConfig;
  312. isDev = config.command === "serve";
  313. needSourcemap = !!resolvedConfig.build.sourcemap;
  314. isDev && createMockServer(opt);
  315. },
  316. configureServer: async ({middlewares}) => {
  317. const {localEnabled = isDev} = opt;
  318. if (!localEnabled) {
  319. return;
  320. }
  321. const middleware = await requestMiddleware(opt);
  322. middlewares.use(middleware);
  323. },
  324. async transform(code, id) {
  325. if (isDev || !injectFile || !id.endsWith(injectFile)) {
  326. return null;
  327. }
  328. const {prodEnabled = true, injectCode = ""} = opt;
  329. if (!prodEnabled) {
  330. return null;
  331. }
  332. return {
  333. map: needSourcemap ? this.getCombinedSourcemap() : null,
  334. code: `${code}
  335. ${injectCode}`
  336. };
  337. }
  338. };
  339. }
  340. exports.viteMockServe = viteMockServe;