mock-service-cli 3.3.1 → 3.3.3

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
@@ -24,6 +24,8 @@
24
24
 
25
25
  #### Mock Server - 本地 Mock 服务器
26
26
 
27
+ **支持热更新,即 Mock 文件改动后自动重启服务**
28
+
27
29
  > Mock File 仅支持 commonjs 规范的 js、cjs 文件,不支持 ES Module
28
30
 
29
31
  支持以下常见业务场景:
@@ -9,6 +9,7 @@ const argv = require('minimist')(process.argv.slice(2));
9
9
  const { logger } = require('../lib/utils');
10
10
  const spawn = require('child_process').spawn;
11
11
  const node = process.execPath;
12
+
12
13
  process.title = 'mock-service-cli';
13
14
 
14
15
  if (argv.h || argv.help) {
@@ -113,6 +114,7 @@ if (proxyArg) {
113
114
  }
114
115
  process.env.PROXY_OPTIONS = JSON.stringify(proxyTable);
115
116
  }
117
+ // whether to start Web server or not
116
118
  if (argv.D || argv['web-dir']) {
117
119
  // 解析SPA应用参数:SPA Web目录
118
120
  process.env.WEB_ROOT = resolve(process.cwd(), argv.D || argv['web-dir']);
@@ -122,24 +124,38 @@ if (argv.D || argv['web-dir']) {
122
124
  }
123
125
  // Web Server port
124
126
  portfinder.basePort = argv.P || argv['web-port'] || 9090;
127
+ portfinder.getPort(function (err, webPort) {
128
+ if (err) {
129
+ throw err;
130
+ }
131
+ process.env.WEB_PORT = webPort;
132
+ // Mock Server port
133
+ portfinder.basePort = port || 8090;
134
+ portfinder.getPort(function (err, port) {
135
+ if (err) {
136
+ throw err;
137
+ }
138
+ process.env.PORT = port;
139
+ initServe();
140
+ });
141
+ });
142
+ } else {
143
+ // Mock Server port
144
+ portfinder.basePort = port || 8090;
125
145
  portfinder.getPort(function (err, port) {
126
146
  if (err) {
127
147
  throw err;
128
148
  }
129
- process.env.WEB_PORT = port;
149
+ process.env.PORT = port;
150
+ initServe();
130
151
  });
131
152
  }
132
153
 
133
- // Mock Server port
134
- portfinder.basePort = port || 8090;
135
- portfinder.getPort(function (err, port) {
136
- if (err) {
137
- throw err;
138
- }
139
- process.env.PORT = port;
140
- });
141
-
142
- const watchMockFiles = function (watchDir) {
154
+ /**
155
+ * Watch change of mock files, restart serve
156
+ * @param watchDir
157
+ */
158
+ function watchMockFiles(watchDir) {
143
159
  /**
144
160
  * script 重启的脚本
145
161
  * ext 检测的文件
@@ -164,50 +180,62 @@ const watchMockFiles = function (watchDir) {
164
180
  [colors.green('\nnodemon: mockServer restarted due to: '), files, colors.green(' have changed'), '\n'].join('')
165
181
  );
166
182
  });
167
- };
183
+ }
168
184
 
169
185
  // Node子进程启动MockServer
170
- const startMockServer = function () {
186
+ function startMockServer() {
171
187
  spawn(node, [resolve(__dirname, '../lib/mockServer.js')], {
172
188
  stdio: 'inherit'
173
189
  });
174
- };
190
+ }
175
191
 
176
192
  // Node子进程启动StaticServer
177
- const startStaticServer = function () {
193
+ function startStaticServer() {
178
194
  spawn(node, [resolve(__dirname, '../lib/staticServer.js')], {
179
195
  stdio: 'inherit'
180
196
  });
181
- };
182
-
183
- if (specifiedFile) {
184
- // Mock服务器:指定文件
185
- process.env.SPECIFIED_FILE = resolve(process.cwd(), specifiedFile);
186
- if (isStartSocketServer) {
187
- startMockServer();
188
- } else {
189
- watchMockFiles(process.env.SPECIFIED_FILE);
190
- }
191
- } else if (watchDir) {
192
- // Mock服务器:指定目录
193
- process.env.SPECIFIED_DIR = resolve(process.cwd(), watchDir);
194
- // log.info('SPECIFIED_DIR::', process.env.SPECIFIED_DIR);
195
- if (isStartSocketServer) {
196
- startMockServer();
197
- } else {
198
- watchMockFiles(process.env.SPECIFIED_DIR);
199
- }
200
- } else if (process.env.STATIC_DIRECTORY) {
201
- // 静态服务器
202
- process.env.STATIC_DIRECTORY = resolve(process.cwd(), process.env.STATIC_DIRECTORY);
203
- startStaticServer();
204
- } else {
205
- // Mock服务:使用默认目录
206
- watchDir = process.env.SPECIFIED_DIR = resolve(process.cwd(), './mock');
207
- // log.info('SPECIFIED_DIR::', process.env.SPECIFIED_DIR);
208
- if (isStartSocketServer) {
209
- startMockServer();
197
+ }
198
+ /**
199
+ * 初始化服务
200
+ */
201
+ function initServe() {
202
+ if (specifiedFile) {
203
+ // Mock服务器:指定文件
204
+ process.env.SPECIFIED_FILE = resolve(process.cwd(), specifiedFile);
205
+ if (isStartSocketServer) {
206
+ startMockServer();
207
+ } else {
208
+ watchMockFiles(process.env.SPECIFIED_FILE);
209
+ }
210
+ } else if (watchDir) {
211
+ // Mock服务器:指定目录
212
+ process.env.SPECIFIED_DIR = resolve(process.cwd(), watchDir);
213
+ // log.info('SPECIFIED_DIR::', process.env.SPECIFIED_DIR);
214
+ if (isStartSocketServer) {
215
+ startMockServer();
216
+ } else {
217
+ watchMockFiles(process.env.SPECIFIED_DIR);
218
+ }
219
+ } else if (process.env.STATIC_DIRECTORY) {
220
+ // 静态服务器
221
+ process.env.STATIC_DIRECTORY = resolve(process.cwd(), process.env.STATIC_DIRECTORY);
222
+ startStaticServer();
210
223
  } else {
211
- watchMockFiles(watchDir);
224
+ // Mock服务:使用默认目录
225
+ watchDir = process.env.SPECIFIED_DIR = resolve(process.cwd(), './mock');
226
+ // log.info('SPECIFIED_DIR::', process.env.SPECIFIED_DIR);
227
+ if (isStartSocketServer) {
228
+ startMockServer();
229
+ } else {
230
+ // whether include web serve or not
231
+ const includesWebServe = process.env.STATIC_DIRECTORY || process.env.WEB_ROOT;
232
+
233
+ if (includesWebServe && !existsSync(resolve(process.cwd(), watchDir))) {
234
+ // 若包含web服务,则允许不启动mock服务
235
+ startMockServer();
236
+ } else {
237
+ watchMockFiles(watchDir);
238
+ }
239
+ }
212
240
  }
213
241
  }
@@ -2,13 +2,13 @@
2
2
  * @description: 生成Mock文件、获取mock数据统计
3
3
  * @Date: 2021-12-22 16:57:08
4
4
  * @LastEditors: chendq
5
- * @LastEditTime: 2022-01-06 13:41:12
5
+ * @LastEditTime: 2025-06-15 22:25:45
6
6
  * @Author: chendq
7
7
  */
8
8
  const fsa = require('fs-extra'),
9
9
  fs = require('fs'),
10
10
  path = require('path'),
11
- _ = require('lodash'),
11
+ isEqual = require('lodash/isEqual'),
12
12
  colors = require('colors/safe');
13
13
  const {
14
14
  getFileLatestContent,
@@ -96,7 +96,7 @@ const genMockFiles = async function ({ url: apiUrl, method, data: resJsonData, d
96
96
  if (fsa.pathExistsSync(mockFilePath)) {
97
97
  const mockFileContent = getFileLatestContent(mockFilePath);
98
98
  // 内容一样不作修改
99
- if (mockFileContent.hasOwnProperty(method) && _.isEqual(mockFileContent[method], resJsonData)) {
99
+ if (mockFileContent.hasOwnProperty(method) && isEqual(mockFileContent[method], resJsonData)) {
100
100
  // log.assert(
101
101
  // !_.isEqual(mockFileContent[method], resJsonData),
102
102
  // colors.bgYellow(`${method} ${apiUrl}, Mock data is same`)
package/lib/mockServer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const express = require('express'), // 引入express
2
2
  bodyParser = require('body-parser'),
3
- fs = require('fs'),
3
+ { readdirSync, existsSync } = require('fs'),
4
4
  os = require('os'),
5
5
  path = require('path'),
6
6
  colors = require('colors/safe'),
@@ -25,15 +25,20 @@ const app = express();
25
25
  const log = logger(process.env.SILENT);
26
26
  const argv = JSON.parse(process.env.ARGV);
27
27
  let socketServer = null; // Socket server instance
28
- const AsyncTaskQueue = require('./asyncTaskQueue');
29
- const saveDataAsyncTask = new AsyncTaskQueue();
28
+ let corsOrigin = [],
29
+ corsHeaders = '';
30
30
 
31
31
  const httpsRE = /^https:\/\//;
32
32
  let count = 0,
33
33
  fileCount = 0, // 记录mock api个数,mock file个数
34
34
  mockDirStat = {}, // 缓存mock目录的统计信息
35
35
  mockFileStat = {}; // 缓存mock文件的统计信息
36
- let done = false;
36
+
37
+ // whether include web serve or not
38
+ const includesWebServe = process.env.STATIC_DIRECTORY || process.env.WEB_ROOT;
39
+
40
+ const mockFileOrDir = process.env.SPECIFIED_FILE || process.env.SPECIFIED_DIR;
41
+
37
42
  if (!process.env.PORT) {
38
43
  portfinder.basePort = 8090;
39
44
  portfinder.getPort(function (err, port) {
@@ -41,53 +46,72 @@ if (!process.env.PORT) {
41
46
  throw err;
42
47
  }
43
48
  process.env.PORT = port;
44
- done = true;
49
+ init();
45
50
  });
46
51
  } else {
47
- done = true;
52
+ init();
48
53
  }
49
- // 将异步函数转换为同步代码代码执行
50
- require('deasync').loopWhile(function () {
51
- return !done;
52
- });
53
- let corsOrigin = [],
54
- corsHeaders = '';
55
- if (process.env.CORS_ORIGIN) {
56
- process.env.CORS_ORIGIN.split(/\s*,\s*/).forEach(function (h) {
57
- corsOrigin.push(h);
58
- }, this);
59
54
 
60
- corsHeaders = DefaultHeaders;
61
- }
62
- if (process.env.CORS_HEADERS) {
63
- process.env.CORS_HEADERS.split(/\s*,\s*/).forEach(function (h) {
64
- corsHeaders += corsHeaders ? ', ' + h : h;
65
- }, this);
55
+ /**
56
+ * Init mock server
57
+ */
58
+ function init() {
59
+ if (process.env.CORS_ORIGIN) {
60
+ process.env.CORS_ORIGIN.split(/\s*,\s*/).forEach(function (h) {
61
+ corsOrigin.push(h);
62
+ }, this);
63
+
64
+ corsHeaders = DefaultHeaders;
65
+ }
66
+ if (process.env.CORS_HEADERS) {
67
+ process.env.CORS_HEADERS.split(/\s*,\s*/).forEach(function (h) {
68
+ corsHeaders += corsHeaders ? ', ' + h : h;
69
+ }, this);
70
+ }
71
+
72
+ app.use(crossDomain()); // 允许跨域
73
+ app.use(bodyParser.json()); // 解析body
74
+
75
+ let requireMockServe = true;
76
+ if (process.env.SPECIFIED_FILE) {
77
+ composeRouteFromJsFile(process.env.SPECIFIED_FILE);
78
+ } else if (includesWebServe && !existsSync(path.resolve(process.cwd(), process.env.SPECIFIED_DIR))) {
79
+ // 若包含web服务,则允许不启动mock服务
80
+ requireMockServe = false;
81
+ } else {
82
+ parseMockFiles(process.env.SPECIFIED_DIR);
83
+ }
84
+ requireMockServe && argv.a && log.info(colors.yellow(`${fileCount} mock file are parsed in total.`));
85
+
86
+ startServer();
66
87
  }
88
+
67
89
  /**
68
90
  * @description: 跨域设置
69
91
  * @param {*}
70
92
  * @return {*}
71
93
  */
72
- const crossDomain = () => (req, res, next) => {
73
- // 设置withCredentials: true时,需设置以下两项
74
- res.header('Access-Control-Allow-Credentials', true);
75
- // withCredentials, must be specified value instead of *
76
- res.header('Access-Control-Allow-Origin', corsOrigin.includes(req.headers.origin) ? req.headers.origin : '*');
77
- // res.header('Access-Control-Allow-Origin', '*');
78
- res.header('Access-Control-Allow-Methods', SupportMethods.join(','));
79
- res.header('Access-Control-Allow-Headers', corsHeaders ? corsHeaders : '*');
80
- // res.header('Access-Control-Allow-Headers', '*');
81
- if (req.method === 'OPTIONS') res.status(200); // 让OPTIONS快速返回
82
- next();
83
- };
94
+ function crossDomain() {
95
+ return (req, res, next) => {
96
+ // 设置withCredentials: true时,需设置以下两项
97
+ res.header('Access-Control-Allow-Credentials', true);
98
+ // withCredentials, must be specified value instead of *
99
+ res.header('Access-Control-Allow-Origin', corsOrigin.includes(req.headers.origin) ? req.headers.origin : '*');
100
+ // res.header('Access-Control-Allow-Origin', '*');
101
+ res.header('Access-Control-Allow-Methods', SupportMethods.join(','));
102
+ res.header('Access-Control-Allow-Headers', corsHeaders ? corsHeaders : '*');
103
+ // res.header('Access-Control-Allow-Headers', '*');
104
+ if (req.method === 'OPTIONS') res.status(200); // 让OPTIONS快速返回
105
+ next();
106
+ };
107
+ }
84
108
 
85
109
  /**
86
110
  * @description: 构建本地服务的路由请求
87
111
  * @param {*} file
88
112
  * @returns {*}
89
113
  */
90
- const composeRouteFromJsFile = function (file) {
114
+ function composeRouteFromJsFile(file) {
91
115
  // 先删除require之前导入的缓存文件,否则获取到的文件内容还是旧内容
92
116
  const fileObject = getFileLatestContent(file);
93
117
 
@@ -121,14 +145,14 @@ const composeRouteFromJsFile = function (file) {
121
145
  });
122
146
  }
123
147
  });
124
- };
148
+ }
125
149
  /**
126
150
  * @description: 解析mock目录下的js文件,为构建路由请求做准备
127
151
  * @param {string} specialDir 目录路径
128
152
  * @return {void}
129
153
  */
130
- const parseMockFiles = function (specialDir = '../mock') {
131
- const files = fs.readdirSync(path.resolve(process.cwd(), specialDir), { withFileTypes: true });
154
+ function parseMockFiles(specialDir = '../mock') {
155
+ const files = readdirSync(path.resolve(process.cwd(), specialDir), { withFileTypes: true });
132
156
  const curFilesSize = files.length;
133
157
  for (let index = 0; index < curFilesSize; index++) {
134
158
  const el = files[index];
@@ -171,66 +195,60 @@ const parseMockFiles = function (specialDir = '../mock') {
171
195
  }
172
196
  composeRouteFromJsFile(filePath);
173
197
  }
174
- };
175
-
176
- app.use(crossDomain()); // 允许跨域
177
- app.use(bodyParser.json()); // 解析body
178
-
179
- if (process.env.SPECIFIED_FILE) {
180
- composeRouteFromJsFile(process.env.SPECIFIED_FILE);
181
- } else {
182
- parseMockFiles(process.env.SPECIFIED_DIR);
183
198
  }
184
- argv.a && log.info(colors.yellow(`${fileCount} mock file are parsed in total.`));
185
199
 
186
- let webApp = null,
187
- webPublicPath = '/',
188
- proxyTable = {};
189
- // Enable Web Server
190
- if (process.env.WEB_ROOT) {
191
- webApp = express();
192
- // Enable web proxy
193
- if (process.env.PROXY_OPTIONS) {
194
- try {
195
- const options = JSON.parse(process.env.PROXY_OPTIONS);
196
- Object.keys(options).forEach(function (prefix) {
197
- proxyTable[prefix] = options[prefix];
198
- const opts = {
199
- target: options[prefix],
200
- changeOrigin: true,
201
- ws: true
202
- };
203
- if (httpsRE.test(options[prefix])) {
204
- // https is require secure=false
205
- opts.secure = false;
206
- }
207
- if (process.env.PREFIX_REWRITE) {
208
- opts.pathRewrite = path => path.replace(new RegExp(`^${prefix}`), '');
209
- }
210
- // 接口代理
211
- // https://github.com/http-party/node-http-proxy#options
212
- webApp.use(prefix, createProxyMiddleware(opts));
213
- }, this);
214
- } catch (error) {
215
- console.warn(colors.yellow('\nEnable web proxy Failed:', error));
200
+ /**
201
+ * Start web server、socket server
202
+ */
203
+ function startServer() {
204
+ let webApp = null,
205
+ webPublicPath = '/',
206
+ proxyTable = {};
207
+ // Enable Web Server
208
+ if (process.env.WEB_ROOT) {
209
+ webApp = express();
210
+ // Enable web proxy
211
+ if (process.env.PROXY_OPTIONS) {
212
+ try {
213
+ const options = JSON.parse(process.env.PROXY_OPTIONS);
214
+ Object.keys(options).forEach(function (prefix) {
215
+ proxyTable[prefix] = options[prefix];
216
+ const opts = {
217
+ target: options[prefix],
218
+ changeOrigin: true,
219
+ ws: true
220
+ };
221
+ if (httpsRE.test(options[prefix])) {
222
+ // https is require secure=false
223
+ opts.secure = false;
224
+ }
225
+ if (process.env.PREFIX_REWRITE) {
226
+ opts.pathRewrite = path => path.replace(new RegExp(`^${prefix}`), '');
227
+ }
228
+ // 接口代理
229
+ // https://github.com/http-party/node-http-proxy#options
230
+ webApp.use(prefix, createProxyMiddleware(opts));
231
+ }, this);
232
+ } catch (error) {
233
+ console.warn(colors.yellow('\nEnable web proxy Failed:', error));
234
+ }
216
235
  }
217
- }
218
- // console.log(process.env.WEB_PUBLIC_PATH, process.env.WEB_ROOT);
219
- if (process.env.WEB_PUBLIC_PATH) {
220
- webPublicPath = process.env.WEB_PUBLIC_PATH;
221
- }
222
- webApp.use(webPublicPath, express.static(process.env.WEB_ROOT)); // 将dist目录下所有文件作为静态文件来管理
223
- const defaultStaticEntry = `${process.env.WEB_ROOT}/index.html`;
224
- if (fs.existsSync(defaultStaticEntry)) {
225
- // Used as static HTTP server for SPA
226
- webApp.get('*', (req, res) => {
227
- res.sendFile(defaultStaticEntry);
228
- });
229
- } else {
230
- // Used as api server for test on browser console or api request tools
231
- webApp.use(webPublicPath, (req, res) => {
232
- res.status(200)
233
- .send(`Hi, welcome to web server entrance ui, you can test http proxy on browser console or api request tools. Examples as follows:<br />
236
+ // console.log(process.env.WEB_PUBLIC_PATH, process.env.WEB_ROOT);
237
+ if (process.env.WEB_PUBLIC_PATH) {
238
+ webPublicPath = process.env.WEB_PUBLIC_PATH;
239
+ }
240
+ webApp.use(webPublicPath, express.static(process.env.WEB_ROOT)); // 将dist目录下所有文件作为静态文件来管理
241
+ const defaultStaticEntry = `${process.env.WEB_ROOT}/index.html`;
242
+ if (existsSync(defaultStaticEntry)) {
243
+ // Used as static HTTP server for SPA
244
+ webApp.get('*', (req, res) => {
245
+ res.sendFile(defaultStaticEntry);
246
+ });
247
+ } else {
248
+ // Used as api server for test on browser console or api request tools
249
+ webApp.use(webPublicPath, (req, res) => {
250
+ res.status(200)
251
+ .send(`Hi, welcome to web server entrance ui, you can test http proxy on browser console or api request tools. Examples as follows:<br />
234
252
  fetch("http://localhost:${process.env.WEB_PORT}/api/permission/auth/login", {
235
253
  method: 'post',
236
254
  headers: {
@@ -240,101 +258,108 @@ if (process.env.WEB_ROOT) {
240
258
  body:JSON.stringify({"loginName":"admin","password":"admin"})
241
259
  })
242
260
  `);
243
- });
261
+ });
262
+ }
244
263
  }
245
- }
246
- const http = require('http').createServer(app);
247
- if (process.env.SOCKET_SERVER) {
248
- socketServer = new Server(http, { path: '/ws/mock-service' });
249
- log.info(colors.bgBlue(`Socket server has started. path: /ws/mock-service, `));
250
- socketServer.of('/mock-data').on('connection', function (socket) {
251
- const { headers, address } = socket.handshake;
252
- const clientIp = headers.hasOwnProperty('x-forwarded-for') ? headers['x-forwarded-for'] : address;
253
- log.info(
254
- colors.green(`Socket client ${clientIp} has connected. --- ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`)
255
- );
256
- socket.on('mock-dir-stat', function (dir) {
257
- socket.emit('mock-dir-stat', isEmptyObj(mockDirStat) ? (mockDirStat = getMockStatFromDir(dir)) : mockDirStat);
258
- });
259
- socket.on('mock-file-stat', function (filePath) {
260
- socket.emit(
261
- 'mock-file-stat',
262
- isEmptyObj(mockFileStat) ? (mockFileStat = getMockStatFromFile(filePath)) : mockFileStat
263
- );
264
- });
265
- const async = args => {
266
- return async next => {
267
- await genMockFiles(args);
268
- next();
269
- };
270
- };
271
- socket.on('save-data', function (data) {
272
- // console.log('lis save-data:', data);
273
- saveDataAsyncTask.add(async(data));
264
+ const http = require('http').createServer(app);
265
+ if (process.env.SOCKET_SERVER) {
266
+ const AsyncTaskQueue = require('./asyncTaskQueue');
267
+ const saveDataAsyncTask = new AsyncTaskQueue();
274
268
 
275
- if (saveDataAsyncTask.list.length === 1) {
276
- saveDataAsyncTask.run();
277
- } else {
278
- saveDataAsyncTask.next();
279
- }
280
- // await genMockFiles(data);
281
- });
282
-
283
- socket.on('disconnect', function () {
269
+ socketServer = new Server(http, { path: '/ws/mock-service' });
270
+ log.info(colors.bgBlue(`Socket server has started. path: /ws/mock-service, `));
271
+ socketServer.of('/mock-data').on('connection', function (socket) {
272
+ const { headers, address } = socket.handshake;
273
+ const clientIp = headers.hasOwnProperty('x-forwarded-for') ? headers['x-forwarded-for'] : address;
284
274
  log.info(
285
- colors.gray(
286
- `Socket client ${clientIp} has disconnected. --- ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`
275
+ colors.green(
276
+ `Socket client ${clientIp} has connected. --- ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`
287
277
  )
288
278
  );
289
- });
290
- });
291
- }
292
-
293
- http.listen(Number.parseInt(process.env.PORT, 10), () => {
294
- console.info(colors.red('\n Mock File仅支持commonjs规范的js、cjs文件,不支持ES Module'));
279
+ socket.on('mock-dir-stat', function (dir) {
280
+ socket.emit('mock-dir-stat', isEmptyObj(mockDirStat) ? (mockDirStat = getMockStatFromDir(dir)) : mockDirStat);
281
+ });
282
+ socket.on('mock-file-stat', function (filePath) {
283
+ socket.emit(
284
+ 'mock-file-stat',
285
+ isEmptyObj(mockFileStat) ? (mockFileStat = getMockStatFromFile(filePath)) : mockFileStat
286
+ );
287
+ });
288
+ const async = args => {
289
+ return async next => {
290
+ await genMockFiles(args);
291
+ next();
292
+ };
293
+ };
294
+ socket.on('save-data', function (data) {
295
+ // console.log('lis save-data:', data);
296
+ saveDataAsyncTask.add(async(data));
295
297
 
296
- console.info(
297
- [
298
- colors.yellow(`\n${process.env.RESTARTED ? 'Restarting' : 'Starting'} up mock-server, serving `),
299
- colors.cyan(process.env.SPECIFIED_FILE || process.env.SPECIFIED_DIR),
300
- colors.yellow(` ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`)
301
- ].join('')
302
- );
303
- if (!process.env.RESTARTED) {
304
- console.info(
305
- [colors.yellow('\n🌍 mock-server version: '), colors.cyan(require('../package.json').version), '\n'].join('')
306
- );
307
- console.info(colors.yellow(`\n Mock server available on:\n`));
308
- console.info(' http://localhost:' + colors.green(process.env.PORT));
309
- Object.keys(ifaces).forEach(function (dev) {
310
- ifaces[dev].forEach(function (details) {
311
- if (details.family === 'IPv4') {
312
- console.info(' http://' + details.address + ':' + colors.green(process.env.PORT));
298
+ if (saveDataAsyncTask.list.length === 1) {
299
+ saveDataAsyncTask.run();
300
+ } else {
301
+ saveDataAsyncTask.next();
313
302
  }
303
+ // await genMockFiles(data);
304
+ });
305
+
306
+ socket.on('disconnect', function () {
307
+ log.info(
308
+ colors.gray(
309
+ `Socket client ${clientIp} has disconnected. --- ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`
310
+ )
311
+ );
314
312
  });
315
313
  });
316
314
  }
317
- });
318
315
 
319
- if (webApp && !process.env.RESTARTED) {
320
- console.info(colors.red('\n Mock File仅支持commonjs规范的js、cjs文件,不支持ES Module'));
321
- webApp.listen(Number.parseInt(process.env.WEB_PORT, 10), () => {
322
- console.info(colors.yellow(`\n Web server available on:\n`));
323
- console.info(' http://localhost:' + colors.green(process.env.WEB_PORT) + webPublicPath);
324
- Object.keys(ifaces).forEach(function (dev) {
325
- ifaces[dev].forEach(function (details) {
326
- if (details.family === 'IPv4') {
327
- console.info(' http://' + details.address + ':' + colors.green(process.env.WEB_PORT) + webPublicPath);
328
- }
329
- });
316
+ if (existsSync(mockFileOrDir)) {
317
+ http.listen(Number.parseInt(process.env.PORT, 10), () => {
318
+ console.info(colors.red('\n Mock File仅支持commonjs规范的js、cjs文件,不支持ES Module'));
319
+
320
+ console.info(
321
+ [
322
+ colors.yellow(`\n${process.env.RESTARTED ? 'Restarting' : 'Starting'} up mock-server, serving `),
323
+ colors.cyan(process.env.SPECIFIED_FILE || process.env.SPECIFIED_DIR),
324
+ colors.yellow(` ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`)
325
+ ].join('')
326
+ );
327
+ if (!process.env.RESTARTED) {
328
+ console.info(
329
+ [colors.yellow('\n🌍 mock-server version: '), colors.cyan(require('../package.json').version), '\n'].join('')
330
+ );
331
+ console.info(colors.yellow(`\n Mock server available on:\n`));
332
+ console.info(' http://localhost:' + colors.green(process.env.PORT));
333
+ Object.keys(ifaces).forEach(function (dev) {
334
+ ifaces[dev].forEach(function (details) {
335
+ if (details.family === 'IPv4') {
336
+ console.info(' http://' + details.address + ':' + colors.green(process.env.PORT));
337
+ }
338
+ });
339
+ });
340
+ }
330
341
  });
331
- if (!isEmptyObj(proxyTable)) {
332
- console.info(colors.yellow(`\n Enable proxy at web server on:`));
333
- Object.keys(proxyTable).forEach(prefix => {
334
- console.info(` ${prefix} -> ${proxyTable[prefix]}`);
342
+ }
343
+
344
+ if (webApp && !process.env.RESTARTED) {
345
+ webApp.listen(Number.parseInt(process.env.WEB_PORT, 10), () => {
346
+ console.info(colors.yellow(`\n Web server available on:\n`));
347
+ console.info(' http://localhost:' + colors.green(process.env.WEB_PORT) + webPublicPath);
348
+ Object.keys(ifaces).forEach(function (dev) {
349
+ ifaces[dev].forEach(function (details) {
350
+ if (details.family === 'IPv4') {
351
+ console.info(' http://' + details.address + ':' + colors.green(process.env.WEB_PORT) + webPublicPath);
352
+ }
353
+ });
335
354
  });
336
- }
337
- });
355
+ if (!isEmptyObj(proxyTable)) {
356
+ console.info(colors.yellow(`\n Enable proxy at web server on:`));
357
+ Object.keys(proxyTable).forEach(prefix => {
358
+ console.info(` ${prefix} -> ${proxyTable[prefix]}`);
359
+ });
360
+ }
361
+ });
362
+ }
338
363
  }
339
364
 
340
365
  if (process.platform === 'win32') {
@@ -2,7 +2,7 @@
2
2
  * Static Server
3
3
  * @Date: 2023-12-03 18:02:24
4
4
  * @LastEditors: chendq
5
- * @LastEditTime: 2023-12-03 18:44:33
5
+ * @LastEditTime: 2025-06-15 22:16:36
6
6
  * @Author : chendq
7
7
  */
8
8
  const express = require('express'), // 引入express
@@ -13,7 +13,6 @@ const { dateFormat, logger } = require('./utils');
13
13
  const ifaces = os.networkInterfaces();
14
14
  const log = logger(process.env.SILENT);
15
15
 
16
- let done = false;
17
16
  if (!process.env.PORT) {
18
17
  portfinder.basePort = 8090;
19
18
  portfinder.getPort(function (err, port) {
@@ -21,38 +20,40 @@ if (!process.env.PORT) {
21
20
  throw err;
22
21
  }
23
22
  process.env.PORT = port;
24
- done = true;
23
+ startServer();
25
24
  });
26
25
  } else {
27
- done = true;
26
+ startServer();
28
27
  }
29
- // 将异步函数转换为同步代码代码执行
30
- require('deasync').loopWhile(function () {
31
- return !done;
32
- });
33
- const app = express();
34
28
 
35
- app.use(express.static(process.env.STATIC_DIRECTORY)); // 将dist目录下所有文件作为静态文件来管理
29
+ /**
30
+ * Start server
31
+ */
32
+ function startServer() {
33
+ const app = express();
34
+
35
+ app.use(express.static(process.env.STATIC_DIRECTORY)); // 将dist目录下所有文件作为静态文件来管理
36
36
 
37
- app.listen(Number.parseInt(process.env.PORT, 10), () => {
38
- console.info(
39
- [
40
- colors.yellow(`\nStarting up Static Server, serving `),
41
- colors.cyan(process.env.STATIC_DIRECTORY),
42
- colors.yellow(` ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`)
43
- ].join('')
44
- );
37
+ app.listen(Number.parseInt(process.env.PORT, 10), () => {
38
+ console.info(
39
+ [
40
+ colors.yellow(`\nStarting up Static Server, serving `),
41
+ colors.cyan(process.env.STATIC_DIRECTORY),
42
+ colors.yellow(` ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`)
43
+ ].join('')
44
+ );
45
45
 
46
- console.info(colors.yellow(`\n Static Server available on:\n`));
47
- console.info(' http://localhost:' + colors.green(process.env.PORT));
48
- Object.keys(ifaces).forEach(function (dev) {
49
- ifaces[dev].forEach(function (details) {
50
- if (details.family === 'IPv4') {
51
- console.info(' http://' + details.address + ':' + colors.green(process.env.PORT));
52
- }
46
+ console.info(colors.yellow(`\n Static Server available on:\n`));
47
+ console.info(' http://localhost:' + colors.green(process.env.PORT));
48
+ Object.keys(ifaces).forEach(function (dev) {
49
+ ifaces[dev].forEach(function (details) {
50
+ if (details.family === 'IPv4') {
51
+ console.info(' http://' + details.address + ':' + colors.green(process.env.PORT));
52
+ }
53
+ });
53
54
  });
54
55
  });
55
- });
56
+ }
56
57
 
57
58
  if (process.platform === 'win32') {
58
59
  require('readline')
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mock-service-cli",
3
- "version": "3.3.1",
4
- "description": "🦅 Local mock server",
3
+ "version": "3.3.3",
4
+ "description": "🦅 Local mock server, Static server, SPA server, Http?s request proxy",
5
5
  "main": "./lib/mockServer.js",
6
6
  "bin": {
7
7
  "mock-service-cli": "bin/mock-service-cli"
@@ -10,7 +10,6 @@
10
10
  "start": "node ./bin/mock-service-cli",
11
11
  "test:unit": "tap --reporter=spec test/*.test.js",
12
12
  "test": "tap --cov --coverage-report=lcov --reporter=spec test/*.test.js ",
13
- "coverage": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls -v",
14
13
  "test-watch": "tap --reporter=spec --watch test/*.test.js",
15
14
  "fix": "eslint --ext .js,.vue,.css --fix",
16
15
  "prettier": "prettier -c --write \"**/*.{ts,js,jsx,css,less,scss,json}\"",
@@ -29,16 +28,13 @@
29
28
  "node": ">=12"
30
29
  },
31
30
  "author": "chendq <deqiaochen@gmail.com>",
32
- "packageManager": "yarn@1.22.19",
33
31
  "keywords": [
34
- "MIT-licensed",
35
32
  "Static Server",
36
- "Mock",
33
+ "Web Server",
34
+ "Mock Server CLI",
37
35
  "MockServer",
38
36
  "mock-service-cli",
39
- "CLI",
40
- "Socket server",
41
- "socket.io"
37
+ "Socket server"
42
38
  ],
43
39
  "repository": {
44
40
  "type": "git",
@@ -49,7 +45,6 @@
49
45
  "dependencies": {
50
46
  "body-parser": "^1.20.2",
51
47
  "colors": "^1.4.0",
52
- "deasync": "^0.1.23",
53
48
  "express": "^4.17.1",
54
49
  "fs-extra": "^10.0.0",
55
50
  "http-proxy-middleware": "^2.0.6",