vite-plugin-mock-dev-server 0.2.2 → 0.3.0

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
@@ -8,7 +8,9 @@ vite mock开发服务(mock-dev-server)插件。
8
8
 
9
9
  - ⚡️ 轻量,灵活,快速
10
10
  - 🧲 非注入式,对客户端代码无侵入
11
+ - 💡 ESModule
11
12
  - 🦾 Typescript
13
+ - 🏷 支持 json / json5 编写 mock 数据
12
14
  - 📦 自动加载 mock 文件
13
15
  - 🎨 可选择你喜欢的任意用于生成mock数据库,如 `mockjs`,或者不是用其他库
14
16
  - 📥 路径规则匹配,请求参数匹配
@@ -101,7 +103,7 @@ export default defineConfig({
101
103
 
102
104
  配置读取 mock文件,可以是一个 目录,glob,或者一个数组
103
105
 
104
- 默认值: `['mock/**/*.mock.*']` (相对于根目录)
106
+ 默认值: `['mock/**/*.mock.{js,ts,cjs,mjs,json,json5}']` (相对于根目录)
105
107
 
106
108
  - `options.exclude`
107
109
 
@@ -232,7 +234,11 @@ export default defineMock({
232
234
 
233
235
  ```
234
236
 
235
- `mock/**/*.mock.ts`
237
+ > 注意:
238
+ >
239
+ > 如果使用 json/json5 编写 mock文件,则不支持使用 `response` 方法,以及不支持使用其他字段的函数形式。
240
+
241
+ `mock/**/*.mock.{ts,js,mjs,cjs,json,json5}`
236
242
 
237
243
  查看更多示例: [example](/example/)
238
244
 
@@ -369,3 +375,15 @@ export default defineMock({
369
375
  }
370
376
  })
371
377
  ```
378
+
379
+ ### 示例10:
380
+ 使用 json / json5
381
+ ```json
382
+ {
383
+ // 支持 comment
384
+ "url": "/api/test",
385
+ "body": {
386
+ "a": 1
387
+ }
388
+ }
389
+ ```
package/dist/index.cjs CHANGED
@@ -33,20 +33,23 @@ __export(src_exports, {
33
33
  module.exports = __toCommonJS(src_exports);
34
34
 
35
35
  // src/mockMiddleware.ts
36
- var import_node_url = require("url");
36
+ var import_node_url2 = require("url");
37
37
  var import_path_to_regexp = require("path-to-regexp");
38
38
 
39
39
  // src/MockLoader.ts
40
40
  var import_node_events = __toESM(require("events"), 1);
41
- var import_promises2 = __toESM(require("fs/promises"), 1);
41
+ var import_node_fs2 = __toESM(require("fs"), 1);
42
+ var import_node_module = require("module");
42
43
  var import_node_path2 = __toESM(require("path"), 1);
44
+ var import_node_url = require("url");
43
45
  var import_pluginutils = require("@rollup/pluginutils");
44
46
  var import_chokidar = __toESM(require("chokidar"), 1);
45
47
  var import_esbuild = require("esbuild");
46
48
  var import_fast_glob = __toESM(require("fast-glob"), 1);
49
+ var import_json5 = __toESM(require("json5"), 1);
47
50
 
48
51
  // src/utils.ts
49
- var import_promises = __toESM(require("fs/promises"), 1);
52
+ var import_node_fs = __toESM(require("fs"), 1);
50
53
  var import_node_path = __toESM(require("path"), 1);
51
54
  var import_debug = __toESM(require("debug"), 1);
52
55
  var isArray = (val) => Array.isArray(val);
@@ -55,25 +58,39 @@ function sleep(timeout) {
55
58
  return new Promise((resolve) => setTimeout(resolve, timeout));
56
59
  }
57
60
  var debug = (0, import_debug.default)("vite:plugin-mock-dev-server");
58
- async function getPackageDeps(cwd) {
59
- const filepath = import_node_path.default.resolve(cwd, "package.json");
60
- const content = await import_promises.default.readFile(filepath, "utf-8");
61
- const pkg = JSON.parse(content);
62
- const { dependencies = {}, devDependencies = {} } = pkg;
63
- const deps = [...Object.keys(dependencies), ...Object.keys(devDependencies)];
64
- return deps;
61
+ function lookupFile(dir, formats, options) {
62
+ for (const format of formats) {
63
+ const fullPath = import_node_path.default.join(dir, format);
64
+ if (import_node_fs.default.existsSync(fullPath) && import_node_fs.default.statSync(fullPath).isFile()) {
65
+ const result = (options == null ? void 0 : options.pathOnly) ? fullPath : import_node_fs.default.readFileSync(fullPath, "utf-8");
66
+ if (!(options == null ? void 0 : options.predicate) || options.predicate(result)) {
67
+ return result;
68
+ }
69
+ }
70
+ }
71
+ const parentDir = import_node_path.default.dirname(dir);
72
+ if (parentDir !== dir && (!(options == null ? void 0 : options.rootDir) || parentDir.startsWith(options == null ? void 0 : options.rootDir))) {
73
+ return lookupFile(parentDir, formats, options);
74
+ }
65
75
  }
66
76
 
67
77
  // src/MockLoader.ts
68
- var MockLoader = class extends import_node_events.default {
78
+ var import_meta = {};
79
+ var _require = (0, import_node_module.createRequire)(import_meta.url);
80
+ var _MockLoader = class extends import_node_events.default {
69
81
  constructor(options) {
70
82
  super();
71
83
  this.moduleCache = /* @__PURE__ */ new Map();
72
84
  this.moduleDeps = /* @__PURE__ */ new Map();
73
85
  this._mockList = [];
86
+ this.moduleType = "cjs";
74
87
  this.options = options;
75
88
  this.cwd = options.cwd || process.cwd();
76
- this.tempDir = options.tempDir || "node_modules/.cache/.mock_server";
89
+ try {
90
+ const pkg = lookupFile(this.cwd, ["package.json"]);
91
+ this.moduleType = !!pkg && JSON.parse(pkg).type === "module" ? "esm" : "cjs";
92
+ } catch (e) {
93
+ }
77
94
  }
78
95
  get mockList() {
79
96
  return this._mockList;
@@ -89,13 +106,13 @@ var MockLoader = class extends import_node_events.default {
89
106
  this.watchMockEntry();
90
107
  this.watchDeps();
91
108
  for (const filepath of includePaths.filter(includeFilter)) {
92
- await this.loadModule(filepath);
109
+ await this.loadMock(filepath);
93
110
  }
94
111
  this.updateMockList();
95
112
  this.on("mock:update", async (filepath) => {
96
113
  if (!includeFilter(filepath))
97
114
  return;
98
- await this.loadModule(filepath);
115
+ await this.loadMock(filepath);
99
116
  this.updateMockList();
100
117
  });
101
118
  this.on("mock:unlink", async (filepath) => {
@@ -180,44 +197,111 @@ var MockLoader = class extends import_node_events.default {
180
197
  });
181
198
  this.emit("update:deps");
182
199
  }
200
+ async loadMock(filepath) {
201
+ if (!filepath)
202
+ return;
203
+ if (_MockLoader.EXT_JSON.test(filepath)) {
204
+ await this.loadJson(filepath);
205
+ } else {
206
+ await this.loadModule(filepath);
207
+ }
208
+ }
209
+ async loadJson(filepath) {
210
+ const content = await import_node_fs2.default.promises.readFile(filepath, "utf-8");
211
+ try {
212
+ const mockConfig = import_json5.default.parse(content);
213
+ this.moduleCache.set(filepath, mockConfig);
214
+ } catch (e) {
215
+ }
216
+ }
183
217
  async loadModule(filepath) {
184
218
  if (!filepath)
185
219
  return;
186
- const { code, deps } = await this.transform(filepath);
187
- const tempFile = import_node_path2.default.join(
188
- this.cwd,
189
- this.tempDir,
190
- filepath.replace(/\.ts$/, ".mjs")
191
- );
192
- const tempBasename = import_node_path2.default.dirname(tempFile);
193
- await import_promises2.default.mkdir(tempBasename, { recursive: true });
194
- await import_promises2.default.writeFile(tempFile, code, "utf8");
195
- const handle = await import(`${tempFile}?${Date.now()}`);
196
- const mockConfig = handle && handle.default ? handle.default : Object.keys(handle || {}).map((key) => handle[key]);
197
- this.moduleCache.set(filepath, mockConfig);
198
- this.updateModuleDeps(filepath, deps);
220
+ let isESM = false;
221
+ if (/\.m[jt]s$/.test(filepath)) {
222
+ isESM = true;
223
+ } else if (/\.c[jt]s$/.test(filepath)) {
224
+ isESM = false;
225
+ } else {
226
+ isESM = this.moduleType === "esm";
227
+ }
228
+ const { code, deps } = await this.transformWithEsbuild(filepath, isESM);
229
+ try {
230
+ const raw = await this.loadFromCode(filepath, code, isESM);
231
+ const mockConfig = raw && raw.default ? raw.default : Object.keys(raw || {}).map((key) => raw[key]);
232
+ this.moduleCache.set(filepath, mockConfig);
233
+ this.updateModuleDeps(filepath, deps);
234
+ } catch (e) {
235
+ console.error(e);
236
+ }
199
237
  }
200
- async transform(filepath) {
238
+ async loadFromCode(filepath, code, isESM) {
239
+ if (isESM) {
240
+ const fileBase = `${filepath}.timestamp-${Date.now()}`;
241
+ const fileNameTmp = `${fileBase}.mjs`;
242
+ const fileUrl = `${(0, import_node_url.pathToFileURL)(fileBase)}.mjs`;
243
+ await import_node_fs2.default.promises.writeFile(fileNameTmp, code, "utf8");
244
+ try {
245
+ return await import(fileUrl);
246
+ } finally {
247
+ try {
248
+ import_node_fs2.default.unlinkSync(fileNameTmp);
249
+ } catch {
250
+ }
251
+ }
252
+ } else {
253
+ filepath = import_node_path2.default.resolve(this.cwd, filepath);
254
+ const extension = import_node_path2.default.extname(filepath);
255
+ const realFileName = import_node_fs2.default.realpathSync(filepath);
256
+ const loaderExt = extension in _require.extensions ? extension : ".js";
257
+ const defaultLoader = _require.extensions[loaderExt];
258
+ _require.extensions[loaderExt] = (module2, filename) => {
259
+ if (filename === realFileName) {
260
+ ;
261
+ module2._compile(code, filename);
262
+ } else {
263
+ defaultLoader(module2, filename);
264
+ }
265
+ };
266
+ delete _require.cache[_require.resolve(filepath)];
267
+ const raw = _require(filepath);
268
+ _require.extensions[loaderExt] = defaultLoader;
269
+ return raw.__esModule ? raw : { default: raw };
270
+ }
271
+ }
272
+ async transformWithEsbuild(filepath, isESM) {
201
273
  var _a;
202
274
  try {
203
275
  const result = await (0, import_esbuild.build)({
204
276
  entryPoints: [filepath],
205
277
  outfile: "out.js",
206
278
  write: false,
207
- target: "es2020",
279
+ target: ["node14.18", "node16"],
208
280
  platform: "node",
209
281
  bundle: true,
210
- external: this.options.external,
211
282
  metafile: true,
212
- format: "esm",
213
- define: this.options.define
283
+ format: isESM ? "esm" : "cjs",
284
+ define: this.options.define,
285
+ plugins: [
286
+ {
287
+ name: "externalize-deps",
288
+ setup(build2) {
289
+ build2.onResolve({ filter: /.*/ }, ({ path: id }) => {
290
+ if (id[0] !== "." && !import_node_path2.default.isAbsolute(id)) {
291
+ return {
292
+ external: true
293
+ };
294
+ }
295
+ });
296
+ }
297
+ }
298
+ ]
214
299
  });
215
300
  return {
216
301
  code: result.outputFiles[0].text,
217
302
  deps: ((_a = result.metafile) == null ? void 0 : _a.inputs) || {}
218
303
  };
219
304
  } catch (e) {
220
- console.error(e);
221
305
  }
222
306
  return {
223
307
  code: "",
@@ -225,6 +309,8 @@ var MockLoader = class extends import_node_events.default {
225
309
  };
226
310
  }
227
311
  };
312
+ var MockLoader = _MockLoader;
313
+ MockLoader.EXT_JSON = /\.json5?$/;
228
314
 
229
315
  // src/parseReqBody.ts
230
316
  var import_co_body = __toESM(require("co-body"), 1);
@@ -263,11 +349,9 @@ function equalObj(left, right) {
263
349
  async function mockServerMiddleware(httpServer, config, options) {
264
350
  const include = isArray(options.include) ? options.include : [options.include];
265
351
  const exclude = isArray(options.exclude) ? options.exclude : [options.exclude];
266
- const external = await getPackageDeps(process.cwd());
267
352
  const loader = new MockLoader({
268
353
  include,
269
354
  exclude,
270
- external,
271
355
  define: config.define || {}
272
356
  });
273
357
  await loader.load();
@@ -278,7 +362,7 @@ async function mockServerMiddleware(httpServer, config, options) {
278
362
  return next();
279
363
  }
280
364
  const method = req.method.toUpperCase();
281
- const { query, pathname } = (0, import_node_url.parse)(req.url, true);
365
+ const { query, pathname } = (0, import_node_url2.parse)(req.url, true);
282
366
  const reqBody = await parseReqBody(req);
283
367
  const currentMock = loader.mockList.find((mock) => {
284
368
  if (!pathname || !mock || !mock.url)
@@ -366,7 +450,7 @@ function doesProxyContextMatchUrl(context, url) {
366
450
 
367
451
  // src/plugin.ts
368
452
  function mockDevServerPlugin({
369
- include = ["mock/**/*.mock.*"],
453
+ include = ["mock/**/*.mock.{js,ts,cjs,mjs,json,json5}"],
370
454
  exclude = [
371
455
  "**/node_modules/**",
372
456
  "**/test/**",
package/dist/index.js CHANGED
@@ -4,15 +4,18 @@ import { match, pathToRegexp } from "path-to-regexp";
4
4
 
5
5
  // src/MockLoader.ts
6
6
  import EventEmitter from "events";
7
- import fs2 from "fs/promises";
7
+ import fs2 from "fs";
8
+ import { createRequire } from "module";
8
9
  import path2 from "path";
10
+ import { pathToFileURL } from "url";
9
11
  import { createFilter } from "@rollup/pluginutils";
10
12
  import chokidar from "chokidar";
11
13
  import { build } from "esbuild";
12
14
  import fastGlob from "fast-glob";
15
+ import JSON5 from "json5";
13
16
 
14
17
  // src/utils.ts
15
- import fs from "fs/promises";
18
+ import fs from "fs";
16
19
  import path from "path";
17
20
  import Debug from "debug";
18
21
  var isArray = (val) => Array.isArray(val);
@@ -21,25 +24,38 @@ function sleep(timeout) {
21
24
  return new Promise((resolve) => setTimeout(resolve, timeout));
22
25
  }
23
26
  var debug = Debug("vite:plugin-mock-dev-server");
24
- async function getPackageDeps(cwd) {
25
- const filepath = path.resolve(cwd, "package.json");
26
- const content = await fs.readFile(filepath, "utf-8");
27
- const pkg = JSON.parse(content);
28
- const { dependencies = {}, devDependencies = {} } = pkg;
29
- const deps = [...Object.keys(dependencies), ...Object.keys(devDependencies)];
30
- return deps;
27
+ function lookupFile(dir, formats, options) {
28
+ for (const format of formats) {
29
+ const fullPath = path.join(dir, format);
30
+ if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
31
+ const result = (options == null ? void 0 : options.pathOnly) ? fullPath : fs.readFileSync(fullPath, "utf-8");
32
+ if (!(options == null ? void 0 : options.predicate) || options.predicate(result)) {
33
+ return result;
34
+ }
35
+ }
36
+ }
37
+ const parentDir = path.dirname(dir);
38
+ if (parentDir !== dir && (!(options == null ? void 0 : options.rootDir) || parentDir.startsWith(options == null ? void 0 : options.rootDir))) {
39
+ return lookupFile(parentDir, formats, options);
40
+ }
31
41
  }
32
42
 
33
43
  // src/MockLoader.ts
34
- var MockLoader = class extends EventEmitter {
44
+ var _require = createRequire(import.meta.url);
45
+ var _MockLoader = class extends EventEmitter {
35
46
  constructor(options) {
36
47
  super();
37
48
  this.moduleCache = /* @__PURE__ */ new Map();
38
49
  this.moduleDeps = /* @__PURE__ */ new Map();
39
50
  this._mockList = [];
51
+ this.moduleType = "cjs";
40
52
  this.options = options;
41
53
  this.cwd = options.cwd || process.cwd();
42
- this.tempDir = options.tempDir || "node_modules/.cache/.mock_server";
54
+ try {
55
+ const pkg = lookupFile(this.cwd, ["package.json"]);
56
+ this.moduleType = !!pkg && JSON.parse(pkg).type === "module" ? "esm" : "cjs";
57
+ } catch (e) {
58
+ }
43
59
  }
44
60
  get mockList() {
45
61
  return this._mockList;
@@ -55,13 +71,13 @@ var MockLoader = class extends EventEmitter {
55
71
  this.watchMockEntry();
56
72
  this.watchDeps();
57
73
  for (const filepath of includePaths.filter(includeFilter)) {
58
- await this.loadModule(filepath);
74
+ await this.loadMock(filepath);
59
75
  }
60
76
  this.updateMockList();
61
77
  this.on("mock:update", async (filepath) => {
62
78
  if (!includeFilter(filepath))
63
79
  return;
64
- await this.loadModule(filepath);
80
+ await this.loadMock(filepath);
65
81
  this.updateMockList();
66
82
  });
67
83
  this.on("mock:unlink", async (filepath) => {
@@ -146,44 +162,111 @@ var MockLoader = class extends EventEmitter {
146
162
  });
147
163
  this.emit("update:deps");
148
164
  }
165
+ async loadMock(filepath) {
166
+ if (!filepath)
167
+ return;
168
+ if (_MockLoader.EXT_JSON.test(filepath)) {
169
+ await this.loadJson(filepath);
170
+ } else {
171
+ await this.loadModule(filepath);
172
+ }
173
+ }
174
+ async loadJson(filepath) {
175
+ const content = await fs2.promises.readFile(filepath, "utf-8");
176
+ try {
177
+ const mockConfig = JSON5.parse(content);
178
+ this.moduleCache.set(filepath, mockConfig);
179
+ } catch (e) {
180
+ }
181
+ }
149
182
  async loadModule(filepath) {
150
183
  if (!filepath)
151
184
  return;
152
- const { code, deps } = await this.transform(filepath);
153
- const tempFile = path2.join(
154
- this.cwd,
155
- this.tempDir,
156
- filepath.replace(/\.ts$/, ".mjs")
157
- );
158
- const tempBasename = path2.dirname(tempFile);
159
- await fs2.mkdir(tempBasename, { recursive: true });
160
- await fs2.writeFile(tempFile, code, "utf8");
161
- const handle = await import(`${tempFile}?${Date.now()}`);
162
- const mockConfig = handle && handle.default ? handle.default : Object.keys(handle || {}).map((key) => handle[key]);
163
- this.moduleCache.set(filepath, mockConfig);
164
- this.updateModuleDeps(filepath, deps);
185
+ let isESM = false;
186
+ if (/\.m[jt]s$/.test(filepath)) {
187
+ isESM = true;
188
+ } else if (/\.c[jt]s$/.test(filepath)) {
189
+ isESM = false;
190
+ } else {
191
+ isESM = this.moduleType === "esm";
192
+ }
193
+ const { code, deps } = await this.transformWithEsbuild(filepath, isESM);
194
+ try {
195
+ const raw = await this.loadFromCode(filepath, code, isESM);
196
+ const mockConfig = raw && raw.default ? raw.default : Object.keys(raw || {}).map((key) => raw[key]);
197
+ this.moduleCache.set(filepath, mockConfig);
198
+ this.updateModuleDeps(filepath, deps);
199
+ } catch (e) {
200
+ console.error(e);
201
+ }
165
202
  }
166
- async transform(filepath) {
203
+ async loadFromCode(filepath, code, isESM) {
204
+ if (isESM) {
205
+ const fileBase = `${filepath}.timestamp-${Date.now()}`;
206
+ const fileNameTmp = `${fileBase}.mjs`;
207
+ const fileUrl = `${pathToFileURL(fileBase)}.mjs`;
208
+ await fs2.promises.writeFile(fileNameTmp, code, "utf8");
209
+ try {
210
+ return await import(fileUrl);
211
+ } finally {
212
+ try {
213
+ fs2.unlinkSync(fileNameTmp);
214
+ } catch {
215
+ }
216
+ }
217
+ } else {
218
+ filepath = path2.resolve(this.cwd, filepath);
219
+ const extension = path2.extname(filepath);
220
+ const realFileName = fs2.realpathSync(filepath);
221
+ const loaderExt = extension in _require.extensions ? extension : ".js";
222
+ const defaultLoader = _require.extensions[loaderExt];
223
+ _require.extensions[loaderExt] = (module, filename) => {
224
+ if (filename === realFileName) {
225
+ ;
226
+ module._compile(code, filename);
227
+ } else {
228
+ defaultLoader(module, filename);
229
+ }
230
+ };
231
+ delete _require.cache[_require.resolve(filepath)];
232
+ const raw = _require(filepath);
233
+ _require.extensions[loaderExt] = defaultLoader;
234
+ return raw.__esModule ? raw : { default: raw };
235
+ }
236
+ }
237
+ async transformWithEsbuild(filepath, isESM) {
167
238
  var _a;
168
239
  try {
169
240
  const result = await build({
170
241
  entryPoints: [filepath],
171
242
  outfile: "out.js",
172
243
  write: false,
173
- target: "es2020",
244
+ target: ["node14.18", "node16"],
174
245
  platform: "node",
175
246
  bundle: true,
176
- external: this.options.external,
177
247
  metafile: true,
178
- format: "esm",
179
- define: this.options.define
248
+ format: isESM ? "esm" : "cjs",
249
+ define: this.options.define,
250
+ plugins: [
251
+ {
252
+ name: "externalize-deps",
253
+ setup(build2) {
254
+ build2.onResolve({ filter: /.*/ }, ({ path: id }) => {
255
+ if (id[0] !== "." && !path2.isAbsolute(id)) {
256
+ return {
257
+ external: true
258
+ };
259
+ }
260
+ });
261
+ }
262
+ }
263
+ ]
180
264
  });
181
265
  return {
182
266
  code: result.outputFiles[0].text,
183
267
  deps: ((_a = result.metafile) == null ? void 0 : _a.inputs) || {}
184
268
  };
185
269
  } catch (e) {
186
- console.error(e);
187
270
  }
188
271
  return {
189
272
  code: "",
@@ -191,6 +274,8 @@ var MockLoader = class extends EventEmitter {
191
274
  };
192
275
  }
193
276
  };
277
+ var MockLoader = _MockLoader;
278
+ MockLoader.EXT_JSON = /\.json5?$/;
194
279
 
195
280
  // src/parseReqBody.ts
196
281
  import bodyParser from "co-body";
@@ -229,11 +314,9 @@ function equalObj(left, right) {
229
314
  async function mockServerMiddleware(httpServer, config, options) {
230
315
  const include = isArray(options.include) ? options.include : [options.include];
231
316
  const exclude = isArray(options.exclude) ? options.exclude : [options.exclude];
232
- const external = await getPackageDeps(process.cwd());
233
317
  const loader = new MockLoader({
234
318
  include,
235
319
  exclude,
236
- external,
237
320
  define: config.define || {}
238
321
  });
239
322
  await loader.load();
@@ -332,7 +415,7 @@ function doesProxyContextMatchUrl(context, url) {
332
415
 
333
416
  // src/plugin.ts
334
417
  function mockDevServerPlugin({
335
- include = ["mock/**/*.mock.*"],
418
+ include = ["mock/**/*.mock.{js,ts,cjs,mjs,json,json5}"],
336
419
  exclude = [
337
420
  "**/node_modules/**",
338
421
  "**/test/**",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-mock-dev-server",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "keywords": [
5
5
  "vite",
6
6
  "plugin",
@@ -48,6 +48,7 @@
48
48
  "debug": "^4.3.4",
49
49
  "esbuild": "^0.15.12",
50
50
  "fast-glob": "^3.2.12",
51
+ "json5": "^2.2.1",
51
52
  "path-to-regexp": "^6.2.1",
52
53
  "vite": "^3.2.0"
53
54
  },