rspack-plugin-mock 2.0.0 → 2.1.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
@@ -41,6 +41,7 @@ Implement a mock-dev-server in `rspack` and `rsbuild` that is fully consistent w
41
41
  - 📤 Support `multipart` content-type, mock upload file.
42
42
  - 📥 Support mock download file.
43
43
  - ⚜️ Support `WebSocket Mock` and `Server-Sent Events Mock`
44
+ - 📝 Support **recording** and **replay requests**
44
45
  - 🗂 Support building small independent deployable mock services.
45
46
 
46
47
  ## Install
@@ -211,7 +212,15 @@ export default defineMock({
211
212
 
212
213
  ## Plugin Options
213
214
 
214
- ### options.prefix
215
+ ### enabled
216
+
217
+ - **Type:** `boolean`
218
+ - **Default:** `true`
219
+ - **Details:**
220
+
221
+ Whether to enable mock server, if set to `false`, the plugin will not work.
222
+
223
+ ### prefix
215
224
 
216
225
  - **Type:** `string | string[]`
217
226
  - **Details:**
@@ -220,7 +229,7 @@ export default defineMock({
220
229
  any request path starting with prefix will be intercepted and proxied.
221
230
  If the prefix starts with `^`, it will be recognized as a `RegExp`.
222
231
 
223
- ### options.wsPrefix
232
+ ### wsPrefix
224
233
 
225
234
  - **Type:** `string | string[]`
226
235
  - **Details:**
@@ -232,7 +241,7 @@ export default defineMock({
232
241
 
233
242
  Please avoid having the configurations in `wsPrefix` appear in `devServer.proxy` / `server.proxy`, as this may lead to conflicts in the rules.
234
243
 
235
- ### options.cwd
244
+ ### cwd
236
245
 
237
246
  - **Type:** `string`
238
247
  - **Default:** `process.cwd()`
@@ -240,31 +249,31 @@ export default defineMock({
240
249
 
241
250
  Configure the matching context for `include` and `exclude`.
242
251
 
243
- ### options.dir
252
+ ### dir
244
253
 
245
254
  - **Type:** `string`
246
- - **Default:** `mock` (relative to [`options.cwd`](#optionscwd))
255
+ - **Default:** `mock` (relative to [`cwd`](#cwd))
247
256
  - **Details:**
248
257
 
249
258
  Configure the directory where mock files are located
250
259
 
251
- ### options.include
260
+ ### include
252
261
 
253
262
  - **Type:** `string | string[]`
254
- - **Default:** `['**/*.mock.{js,ts,cjs,mjs,json,json5}']` (relative to [`options.dir`](#optionsdir))
263
+ - **Default:** `['**/*.mock.{js,ts,cjs,mjs,json,json5}']` (relative to [`dir`](#dir))
255
264
  - **Details:**
256
265
 
257
266
  glob string matching mock includes files. see [picomatch](https://github.com/micromatch/picomatch#globbing-features)
258
267
 
259
- ### options.exclude
268
+ ### exclude
260
269
 
261
270
  - **Type:** `string | string[]`
262
- - **Default:** `[]` (relative to [`options.dir`](#optionsdir))
271
+ - **Default:** `[]` (relative to [`dir`](#dir))
263
272
  - **Details:**
264
273
 
265
274
  glob string matching mock excluded files. see [picomatch](https://github.com/micromatch/picomatch#globbing-features)
266
275
 
267
- ### options.log
276
+ ### log
268
277
 
269
278
  - **Type:** `boolean | 'info' | 'warn' | 'error' | 'silent' | 'debug'`
270
279
  - **Default:** `info`
@@ -272,7 +281,7 @@ export default defineMock({
272
281
 
273
282
  Enable log and configure log level
274
283
 
275
- ### options.reload
284
+ ### reload
276
285
 
277
286
  - **Type:** `boolean`
278
287
  - **Default:** `false`
@@ -281,7 +290,17 @@ export default defineMock({
281
290
  If you want to refresh the page every time you modify a mock file,
282
291
  you can open this option.
283
292
 
284
- ### options.cors
293
+ ### activeScene
294
+
295
+ - **Type:** `string | string[]`
296
+ - **Default:** `''`
297
+ - **Details:**
298
+
299
+ Active scenario(s) for filtering mocks.
300
+
301
+ Only mocks whose [`scene`](#optionsscene) intersects with this value (or have no `scene` configured) will be considered for matching. Can be overridden per-request via the `X-Mock-Scene` header.
302
+
303
+ ### cors
285
304
 
286
305
  - **Type:** `boolean | CorsOptions`
287
306
  - **Default:** `true`
@@ -289,7 +308,7 @@ export default defineMock({
289
308
 
290
309
  Configure to [cors](https://github.com/expressjs/cors#configuration-options)
291
310
 
292
- ### options.formidableOptions
311
+ ### formidableOptions
293
312
 
294
313
  - **Type:** `FormidableOptions`
295
314
  - **Default:** `{ multiples: true }`
@@ -297,21 +316,21 @@ export default defineMock({
297
316
 
298
317
  Configure to [formidable](https://github.com/node-formidable/formidable#options)
299
318
 
300
- ### options.cookiesOptions
319
+ ### cookiesOptions
301
320
 
302
321
  - **Type:** `CookiesOptions`
303
322
  - **Details:**
304
323
 
305
324
  Configure to [cookies](https://github.com/pillarjs/cookies#new-cookiesrequest-response--options)
306
325
 
307
- ### options.bodyParserOptions
326
+ ### bodyParserOptions
308
327
 
309
328
  - **Type:** `BodyParserOptions`
310
329
  - **Details:**
311
330
 
312
331
  Configure to [co-body](https://github.com/cojs/co-body#options)
313
332
 
314
- ## options.build
333
+ ## build
315
334
 
316
335
  - **Type:** `boolean | ServerBuildOption`
317
336
 
@@ -341,8 +360,143 @@ export default defineMock({
341
360
 
342
361
  When you need to build a small mock service, you can configure this option.
343
362
 
363
+ ### record
364
+
365
+ - **Type:** `false | RecordOptions`
366
+ - **Default:** `false`
367
+ - **Details:**
368
+
369
+ Whether to enable the request recording feature. Once enabled, the plugin will record all request data for subsequent request playback.
370
+
371
+ Based on `proxy`, the plugin records request data proxied by `http-proxy`.
372
+ After receiving a response, the plugin will record the request data and response data to the specified directory.
373
+
374
+ ```ts
375
+ interface RecordOptions {
376
+ /**
377
+ * Whether to enable the record feature
378
+ * - true: Enable, automatically record proxy responses
379
+ * - false: Disable (default)
380
+ * @default false
381
+ */
382
+ enabled?: boolean
383
+ /**
384
+ * Filter requests to record
385
+ * - Function: Custom filter function, return true to record
386
+ * - Object: Include/exclude patterns with glob or path-to-regexp mode
387
+ * @example
388
+ * ```ts
389
+ * // Record all requests
390
+ * filter: (req) => true
391
+ * // Record requests using glob pattern
392
+ * filter: { mode: 'glob', include: '/api/**' }
393
+ * // Record requests using path-to-regexp pattern
394
+ * filter: { mode: 'path-to-regexp', include: '/api/:id' }
395
+ * ```
396
+ */
397
+ filter?: ((req: RecordedReq) => boolean) | {
398
+ /**
399
+ * Include the request links that need to be recorded
400
+ *
401
+ * String: Glob pattern or path-to-regexp pattern
402
+ * (Use the mode option to set the mode, default is glob)
403
+ */
404
+ include?: string | string[]
405
+ /**
406
+ * Exclude request links that do not need to be recorded
407
+ *
408
+ * String: Glob pattern or path-to-regexp pattern
409
+ * (Use the mode option to set the mode, default is glob)
410
+ */
411
+ exclude?: string | string[]
412
+ /**
413
+ * Matching mode for include/exclude patterns
414
+ * - 'glob': Glob pattern matching (default)
415
+ * - 'path-to-regexp': Path-to-regexp pattern matching
416
+ */
417
+ mode: 'glob' | 'path-to-regexp'
418
+ }
419
+
420
+ /**
421
+ * Directory to store recorded data
422
+ * Relative to project root
423
+ * @default 'mock/.recordings'
424
+ */
425
+ dir?: string
426
+ /**
427
+ * Whether to overwrite existing recorded data
428
+ * - true: Overwrite old data for the same request (default)
429
+ * - false: Keep old data, do not record new data
430
+ * @default true
431
+ */
432
+ overwrite?: boolean
433
+ /**
434
+ * Expiration time for recorded data in seconds
435
+ * - 0: Never expire (default)
436
+ * - Positive number: Expire after specified seconds
437
+ * @default 0
438
+ */
439
+ expires?: number
440
+ /**
441
+ * Status codes to record
442
+ * - Empty array: Record all status codes (default)
443
+ * - Specify one or more status codes to filter
444
+ * @default []
445
+ */
446
+ status?: number | number[]
447
+ /**
448
+ * Should a .gitignore be added to the recording directory
449
+ * - true: Add (default)
450
+ * - false: Do not add
451
+ * @default true
452
+ */
453
+ gitignore?: boolean
454
+ }
455
+ ```
456
+
457
+ ### replay
458
+
459
+ - **Type:** `boolean`
460
+ - **Default:** `false`
461
+ - **Details:**
462
+
463
+ Whether to enable the request playback feature. Once enabled, the plugin will simulate responses based on the recorded request data.
464
+
465
+ ### priority
466
+
467
+ - **Type:** `MockMatchPriority`
468
+ - **Details:**
469
+
470
+ Custom path matching rule priority。[read more](#custom-path-matching-priority)
471
+
344
472
  ## Mock Options
345
473
 
474
+ **http mock**
475
+
476
+ ```ts
477
+ import { defineMock } from 'rspack-plugin-mock/helper'
478
+ export default defineMock({
479
+ url: '/api/test',
480
+ body: { message: 'hello world' }
481
+ })
482
+ ```
483
+
484
+ **websocket mock**
485
+
486
+ ```ts
487
+ import { defineMock } from 'rspack-plugin-mock/helper'
488
+
489
+ export default defineMock({
490
+ url: '/socket.io',
491
+ ws: true,
492
+ setup(wss) {
493
+ wss.on('connection', (ws, req) => {
494
+ console.log('connected')
495
+ })
496
+ }
497
+ })
498
+ ```
499
+
346
500
  ### options.url
347
501
 
348
502
  - **Type:** `string`
@@ -359,6 +513,16 @@ export default defineMock({
359
513
  Whether to enable mock for this interface. In most scenarios, we only need to mock some interfaces instead of all requests that have been configured with mock.
360
514
  Therefore, it is important to be able to configure whether to enable it or not.
361
515
 
516
+ ### options.scene
517
+
518
+ - **Type:** `string | string[]`
519
+ - **Default:** `''`
520
+ - **Details:**
521
+
522
+ Scenario identifier for this mock.
523
+
524
+ When not configured, the mock is universal and always matches regardless of active scenario.When configured, the mock only matches when at least one of its scenarios matches one of the active scenarios.
525
+
362
526
  ### options.method
363
527
 
364
528
  - **Type:** `Method | Method[]`
@@ -524,55 +688,181 @@ interface WebSocketSetupContext {
524
688
  }
525
689
  ```
526
690
 
527
- ### Types
691
+ ### options.error
528
692
 
529
- ```ts
530
- export type MockRequest = http.IncomingMessage & ExtraRequest
693
+ - **Type:** `MockErrorConfig | undefined`
694
+ - **Details:**
531
695
 
532
- export type MockResponse = http.ServerResponse<http.IncomingMessage> & {
533
- /**
534
- * Set cookie in response
535
- * @see [cookies](https://github.com/pillarjs/cookies#cookiessetname--values--options)
536
- */
537
- setCookie: (
538
- name: string,
539
- value?: string | null,
540
- option?: Cookies.SetOption,
541
- ) => void
542
- }
696
+ Configure error simulation, including error probability, error status code, error status text, and custom error response body.
543
697
 
544
- interface ExtraRequest {
545
- /**
546
- * The query string located after `?` in the request address has been parsed into JSON.
547
- */
548
- query: Record<string, any>
549
- /**
550
- * The queryString located after `?` in the referer request has been parsed as JSON.
551
- */
552
- refererQuery: Record<string, any>
698
+ ```ts
699
+ interface MockErrorConfig {
553
700
  /**
554
- * Body data in the request
701
+ * Error probability (0-1), default is 0.5
702
+ * @default 0.5
555
703
  */
556
- body: Record<string, any>
704
+ probability?: number
557
705
  /**
558
- * The params parameter parsed from the `/api/id/:id` in the request address.
706
+ * Error status code, default is 500
707
+ * @default 500
559
708
  */
560
- params: Record<string, any>
709
+ status?: number
561
710
  /**
562
- * headers data in the request
711
+ * Error status text
563
712
  */
564
- headers: Headers
713
+ statusText?: string
565
714
  /**
566
- * Get the cookie carried in the request.
567
- * @see [cookies](https://github.com/pillarjs/cookies#cookiesgetname--options)
715
+ * Custom error response body, suitable for when the status is 200, but the response body needs to simulate an error scenario
716
+ * @example
717
+ * { code: 500, msg: 'Internal Server Error', result: null }
568
718
  */
719
+ body?: ResponseBody | ResponseBodyFn
720
+ }
721
+ ```
722
+
723
+ ## Request/Response Enhance
724
+
725
+ When defining methods using `headers`, `body`, and `response`, the plugin adds new content to the `request` and `response` parameters.
726
+
727
+ **In Request:**
728
+
729
+ The original type of `request` is [`http.IncomingMessage`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/connect/index.d.ts). The plugin adds data such as `query`, `params`, `body`, `refererQuery`, and the `getCookie(name)` method for obtaining cookie information on this basis.
730
+
731
+ ```ts
732
+ type Request = http.IncomingMessage & {
733
+ query: object
734
+ params: object
735
+ body: any
736
+ refererQuery: object
569
737
  getCookie: (name: string, option?: Cookies.GetOption) => string | undefined
570
738
  }
571
739
  ```
572
740
 
741
+ **In Response:**
742
+
743
+ The original type of `response` is `http.ServerResponse<http.IncomingMessage>`. The plugin adds `setCookie(name, value)` method for configuration cookies on this basis.
744
+
745
+ ``` ts
746
+ type Response = http.ServerResponse<http.IncomingMessage> & {
747
+ setCookie: (
748
+ name: string,
749
+ value?: string | null,
750
+ option?: Cookies.SetOption,
751
+ ) => void
752
+ }
753
+ ```
754
+
755
+ ## Share Mock Data
756
+
757
+ Due to each `mock` file being compiled as a separate entry point, the local files they depend on are also compiled within. Additionally, each mock file has an independent scope. This means that even if multiple mock files collectively depend on a `data.ts` file, they cannot share data. If one mock file modifies the data in `data.ts`, other mock files will not receive the updated data.
758
+
759
+ To address this, the plugin offers a `defineMockData` function, which allows using `data.ts` as a shared data source within mock files.
760
+
761
+ ```ts
762
+ type defineMockData<T> = (
763
+ key: string, // key
764
+ initialData: T, // initial data
765
+ options?: {
766
+ persistOnHMR?: boolean // persist the data value on HMR
767
+ } // options
768
+ ) => [getter, setter] & { value: T }
769
+ ```
770
+
771
+ ### Examples
772
+
773
+ `data.ts`
774
+
775
+ ```ts
776
+ import { defineMockData } from 'rspack-plugin-mock/helper'
777
+
778
+ export default defineMockData('posts', [
779
+ { id: '1', title: 'title1', content: 'content1' },
780
+ { id: '2', title: 'title2', content: 'content2' },
781
+ ])
782
+ ```
783
+
784
+ `*.mock.ts`
785
+
786
+ ```ts
787
+ import { defineMock } from 'rspack-plugin-mock/helper'
788
+ import posts from './data'
789
+
790
+ export default defineMock([
791
+ {
792
+ url: '/api/posts',
793
+ body: () => posts.value
794
+ },
795
+ {
796
+ url: '/api/posts/delete/:id',
797
+ body: (params) => {
798
+ const id = params.id
799
+ posts.value = posts.value.filter(post => post.id !== id)
800
+ return { success: true }
801
+ }
802
+ }
803
+ ])
804
+ ```
805
+
806
+ > **Tips:**
807
+ >
808
+ > The `defineMockData` function relies solely on the shared data support provided by `memory`.
809
+ > If persistent mock data is required, it is recommended to use a `nosql` database like `lowdb` or `level`.
810
+
811
+ ## Custom-Path-Matching-Priority
812
+
813
+ > Custom rules only affect links with dynamic parameters, such as: `/api/user/:id`
814
+
815
+ The priority of the path matching rules built into the plugin can already meet most needs, but if you need more flexible customization of the matching rule priority, you can use the `priority` parameter.
816
+
817
+ Exp:
818
+
819
+ ```ts
820
+ import { MockServerPlugin } from 'rspack-plugin-mock'
821
+
822
+ export default {
823
+ plugins: [
824
+ new MockServerPlugin({
825
+ priority: {
826
+ // The priority of matching rules is global.
827
+ // The rules declared in this option will take priority over the default rules.
828
+ // The higher the position of the rule in the array, the higher the priority.
829
+ global: ['/api/:a/b/c', '/api/a/:b/c', '/api/a/b/:c'],
830
+ // For some special cases where the priority of certain rules needs to be adjusted,
831
+ // this option can be used. For example, when a request matches both Rule A and Rule B,
832
+ // and Rule A has a higher priority than Rule B, but it is desired for Rule B to take effect.
833
+ special: {
834
+ // When both A and B or C match, and B or C is at the top of the sort order,
835
+ // insert A into the top position.
836
+ // The `when` option is used to further constrain the priority adjustment to
837
+ // be effective only for certain requests.
838
+ '/api/:a/:b/c': {
839
+ rules: ['/api/a/:b/:c', '/api/a/b/:c'],
840
+ when: ['/api/a/b/c']
841
+ },
842
+ // If no `when` is specified, it means that all requests matching the rules need to have their priorities adjusted. It can be abbreviated as `[key]: [...rules]`
843
+ '/api/:a/b': ['/api/a/:b'],
844
+ }
845
+ }
846
+ })
847
+ ]
848
+ }
849
+ ```
850
+
851
+ > **Tip:**
852
+ >
853
+ > `priority` although it can adjust the priority,
854
+ > most of the time you do not need to do so. For some special requests,
855
+ > you can use static rules instead of `priority`,
856
+ > as static rules always have the highest priority.
857
+
573
858
  ## Examples
574
859
 
575
- **exp:** Match `/api/test`, And returns a response body content with empty data
860
+ `mock/**/*.mock.{ts,js,mjs,cjs,json,json5}`
861
+
862
+ See more examples: [example](/example/)
863
+
864
+ <details>
865
+ <summary>Match <code>/api/test</code>, And returns a response body content with empty data</summary>
576
866
 
577
867
  ``` ts
578
868
  export default defineMock({
@@ -580,7 +870,10 @@ export default defineMock({
580
870
  })
581
871
  ```
582
872
 
583
- **exp:** Match `/api/test` , And returns a static content data
873
+ </details>
874
+
875
+ <details>
876
+ <summary>Match <code>/api/test</code> , And returns a static content data</summary>
584
877
 
585
878
  ``` ts
586
879
  export default defineMock({
@@ -589,7 +882,10 @@ export default defineMock({
589
882
  })
590
883
  ```
591
884
 
592
- **exp:** Only Support `GET` Method
885
+ </details>
886
+
887
+ <details>
888
+ <summary>Only Support <code>GET</code> Method</summary>
593
889
 
594
890
  ``` ts
595
891
  export default defineMock({
@@ -598,7 +894,10 @@ export default defineMock({
598
894
  })
599
895
  ```
600
896
 
601
- **exp:** In the response header, add a custom header and cookie
897
+ </details>
898
+
899
+ <details>
900
+ <summary>In the response header, add a custom header and cookie</summary>
602
901
 
603
902
  ``` ts
604
903
  export default defineMock({
@@ -620,7 +919,10 @@ export default defineMock({
620
919
  })
621
920
  ```
622
921
 
623
- **exp:** Define multiple mock requests for the same URL and match valid rules with validators
922
+ </details>
923
+
924
+ <details>
925
+ <summary>Define multiple mock requests for the same URL and match valid rules with validators</summary>
624
926
 
625
927
  ``` ts
626
928
  export default defineMock([
@@ -655,7 +957,10 @@ export default defineMock([
655
957
  ])
656
958
  ```
657
959
 
658
- **exp:** Response Delay
960
+ </details>
961
+
962
+ <details>
963
+ <summary>Response Delay</summary>
659
964
 
660
965
  ``` ts
661
966
  export default defineMock({
@@ -664,7 +969,10 @@ export default defineMock({
664
969
  })
665
970
  ```
666
971
 
667
- **exp:** The interface request failed
972
+ </details>
973
+
974
+ <details>
975
+ <summary>The interface request failed</summary>
668
976
 
669
977
  ``` ts
670
978
  export default defineMock({
@@ -674,7 +982,10 @@ export default defineMock({
674
982
  })
675
983
  ```
676
984
 
677
- **exp:** Dynamic route matching
985
+ </details>
986
+
987
+ <details>
988
+ <summary>Dynamic route matching</summary>
678
989
 
679
990
  ``` ts
680
991
  export default defineMock({
@@ -687,7 +998,10 @@ export default defineMock({
687
998
 
688
999
  The `userId` in the route will be resolved into the `request.params` object.
689
1000
 
690
- **exp:** Use the buffer to respond data
1001
+ </details>
1002
+
1003
+ <details>
1004
+ <summary>Use the buffer to respond data</summary>
691
1005
 
692
1006
  ```ts
693
1007
  import { Buffer } from 'node:buffer'
@@ -712,7 +1026,10 @@ export default defineMock({
712
1026
  })
713
1027
  ```
714
1028
 
715
- **exp:** Response file type
1029
+ </details>
1030
+
1031
+ <details>
1032
+ <summary>Response file type</summary>
716
1033
 
717
1034
  Simulate file download, and pass in the file reading stream.
718
1035
 
@@ -731,7 +1048,10 @@ export default defineMock({
731
1048
  <a href="/api/download" download="my-app.dmg">Download File</a>
732
1049
  ```
733
1050
 
734
- **exp:** Use `mockjs`:
1051
+ </details>
1052
+
1053
+ <details>
1054
+ <summary>Use <code>mockjs</code></summary>
735
1055
 
736
1056
  ``` ts
737
1057
  import Mock from 'mockjs'
@@ -748,7 +1068,11 @@ export default defineMock({
748
1068
 
749
1069
  You need install `mockjs`
750
1070
 
751
- **exp:** Use `response` to customize the response
1071
+ </details>
1072
+
1073
+ <details>
1074
+
1075
+ <summary>Use <code>response</code> to customize the response</summary>
752
1076
 
753
1077
  ``` ts
754
1078
  export default defineMock({
@@ -768,7 +1092,10 @@ export default defineMock({
768
1092
  })
769
1093
  ```
770
1094
 
771
- **exp:** Use json / json5
1095
+ </details>
1096
+
1097
+ <details>
1098
+ <summary>Use json / json5</summary>
772
1099
 
773
1100
  ``` json
774
1101
  {
@@ -779,7 +1106,10 @@ export default defineMock({
779
1106
  }
780
1107
  ```
781
1108
 
782
- **exp:** multipart, upload files.
1109
+ </details>
1110
+
1111
+ <details>
1112
+ <summary>multipart, upload files.</summary>
783
1113
 
784
1114
  use [`formidable`](https://www.npmjs.com/package/formidable#readme) to support.
785
1115
 
@@ -815,7 +1145,10 @@ export default defineMock({
815
1145
  })
816
1146
  ```
817
1147
 
818
- **exp:** Graphql
1148
+ </details>
1149
+
1150
+ <details>
1151
+ <summary>Graphql</summary>
819
1152
 
820
1153
  ``` ts
821
1154
  import { buildSchema, graphql } from 'graphql'
@@ -845,7 +1178,10 @@ fetch('/api/graphql', {
845
1178
  })
846
1179
  ```
847
1180
 
848
- **exp:** WebSocket Mock
1181
+ </details>
1182
+
1183
+ <details>
1184
+ <summary>WebSocket Mock</summary>
849
1185
 
850
1186
  ``` ts
851
1187
  // ws.mock.ts
@@ -878,7 +1214,7 @@ export default defineMock({
878
1214
 
879
1215
  ``` ts
880
1216
  // app.ts
881
- const ws = new WebSocket('ws://localhost:3000/socket.io')
1217
+ const ws = new WebSocket('ws://localhost:5173/socket.io')
882
1218
  ws.addEventListener('open', () => {
883
1219
  setInterval(() => {
884
1220
  // heartbeat
@@ -890,7 +1226,10 @@ ws.addEventListener('message', (raw) => {
890
1226
  })
891
1227
  ```
892
1228
 
893
- **exp:** EventSource Mock
1229
+ </details>
1230
+
1231
+ <details>
1232
+ <summary>EventSource Mock</summary>
894
1233
 
895
1234
  ```ts
896
1235
  // sse.mock.ts
@@ -924,6 +1263,8 @@ es.addEventListener('count', (e) => {
924
1263
  })
925
1264
  ```
926
1265
 
1266
+ </details>
1267
+
927
1268
  ## Mock Services
928
1269
 
929
1270
  In some scenarios, it may be necessary to use the data provided by mock services for display purposes, but the project may have already been packaged, built and deployed without support from `rspack/rsbuild` and this plugin's mock service. Since this plugin supports importing various node modules in mock files at the design stage, the mock file cannot be inline into client build code.