@rspack/dev-middleware 0.2.12 → 2.0.0-beta.1

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
@@ -1,18 +1,743 @@
1
- <picture>
2
- <source media="(prefers-color-scheme: dark)" srcset="https://lf3-static.bytednsdoc.com/obj/eden-cn/rjhwzy/ljhwZthlaukjlkulzlp/rspack-banner-1610-dark.png">
3
- <img alt="Rspack Banner" src="https://lf3-static.bytednsdoc.com/obj/eden-cn/rjhwzy/ljhwZthlaukjlkulzlp/rspack-banner-1610.png">
4
- </picture>
1
+ # @rspack/dev-middleware
5
2
 
6
- # DEPRECATED! Use [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) instead
3
+ <p>
4
+ <a href="https://npmjs.com/package/@rspack/dev-middleware?activeTab=readme"><img src="https://img.shields.io/npm/v/@rspack/dev-middleware?style=flat-square&colorA=564341&colorB=EDED91" alt="npm version" /></a>
5
+ <a href="https://npmcharts.com/compare/@rspack/dev-middleware?minimal=true"><img src="https://img.shields.io/npm/dm/@rspack/dev-middleware.svg?style=flat-square&colorA=564341&colorB=EDED91" alt="downloads" /></a>
6
+ <a href="https://nodejs.org/en/about/previous-releases"><img src="https://img.shields.io/node/v/@rspack/dev-middleware.svg?style=flat-square&colorA=564341&colorB=EDED91" alt="node version"></a>
7
+ <a href="https://github.com/rstackjs/rspack-dev-middleware/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square&colorA=564341&colorB=EDED91" alt="license" /></a>
8
+ </p>
7
9
 
8
- # @rspack/dev-middleware
10
+ An express-style development middleware for use with [Rspack](https://rspack.rs). It serves the files emitted by the compiler from memory.
11
+
12
+ This should be used for **development only**.
13
+
14
+ Some of the benefits of using this middleware include:
15
+
16
+ - No files are written to disk, rather it handles files in memory
17
+ - If files changed in watch mode, the middleware delays requests until compiling
18
+ has completed.
19
+ - Supports hot module reload (HMR).
20
+
21
+ ## Getting Started
22
+
23
+ Install the module:
24
+
25
+ ```bash
26
+ # npm
27
+ npm install @rspack/dev-middleware -D
28
+
29
+ # pnpm
30
+ pnpm add -D @rspack/dev-middleware
31
+
32
+ # yarn
33
+ yarn add -D @rspack/dev-middleware
34
+
35
+ # bun
36
+ bun add -D @rspack/dev-middleware
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ```js
42
+ const { devMiddleware } = require("@rspack/dev-middleware");
43
+ const express = require("express");
44
+ const { rspack } = require("@rspack/core");
45
+
46
+ const compiler = rspack({
47
+ // Rspack options
48
+ });
49
+
50
+ const app = express();
51
+
52
+ app.use(
53
+ devMiddleware(compiler, {
54
+ // options
55
+ }),
56
+ );
57
+
58
+ app.listen(3000, () => console.log("Example app listening on port 3000!"));
59
+ ```
60
+
61
+ See [below](#other-servers) for an example of use with fastify.
62
+
63
+ ## Options
64
+
65
+ | Name | Type | Default | Description |
66
+ | :---------------------------------------------: | :-------------------------------: | :-------------------------------------------: | :------------------------------------------------------------------------------------------------------------------- |
67
+ | **[`methods`](#methods)** | `Array` | `[ 'GET', 'HEAD' ]` | Allows to pass the list of HTTP request methods accepted by the middleware |
68
+ | **[`headers`](#headers)** | `Array\|Object\|Function` | `undefined` | Allows to pass custom HTTP headers on each request. |
69
+ | **[`index`](#index)** | `boolean\|string` | `index.html` | If `false` (but not `undefined`), the server will not respond to requests to the root URL. |
70
+ | **[`mimeTypes`](#mimetypes)** | `Object` | `undefined` | Allows to register custom mime types or extension mappings. |
71
+ | **[`mimeTypeDefault`](#mimetypedefault)** | `string` | `undefined` | Allows to register a default mime type when we can't determine the content type. |
72
+ | **[`etag`](#tag)** | `boolean\| "weak"\| "strong"` | `undefined` | Enable or disable etag generation. |
73
+ | **[`lastModified`](#lastmodified)** | `boolean` | `undefined` | Enable or disable `Last-Modified` header. Uses the file system's last modified value. |
74
+ | **[`cacheControl`](#cachecontrol)** | `boolean\|number\|string\|Object` | `undefined` | Enable or disable setting `Cache-Control` response header. |
75
+ | **[`cacheImmutable`](#cacheimmutable)** | `boolean\` | `undefined` | Enable or disable setting `Cache-Control: public, max-age=31536000, immutable` response header for immutable assets. |
76
+ | **[`publicPath`](#publicpath)** | `string` | `undefined` | The public path that the middleware is bound to. |
77
+ | **[`stats`](#stats)** | `boolean\|string\|Object` | `stats` (from a configuration) | Stats options object or preset name. |
78
+ | **[`serverSideRender`](#serversiderender)** | `boolean` | `undefined` | Instructs the module to enable or disable the server-side rendering mode. |
79
+ | **[`writeToDisk`](#writetodisk)** | `boolean\|Function` | `false` | Instructs the module to write files to the configured location on disk as specified in your Rspack configuration. |
80
+ | **[`outputFileSystem`](#outputfilesystem)** | `Object` | [`memfs`](https://github.com/streamich/memfs) | Set the default file system which will be used by Rspack as primary destination of generated files. |
81
+ | **[`modifyResponseData`](#modifyresponsedata)** | `Function` | `undefined` | Allows to set up a callback to change the response data. |
82
+
83
+ The middleware accepts an `options` Object. The following is a property reference for the Object.
84
+
85
+ ### methods
86
+
87
+ Type: `Array`
88
+ Default: `[ 'GET', 'HEAD' ]`
89
+
90
+ This property allows a user to pass the list of HTTP request methods accepted by the middleware\*\*.
91
+
92
+ ### headers
93
+
94
+ Type: `Array|Object|Function`
95
+ Default: `undefined`
96
+
97
+ This property allows a user to pass custom HTTP headers on each request.
98
+ eg. `{ "X-Custom-Header": "yes" }`
99
+
100
+ or
101
+
102
+ ```js
103
+ devMiddleware(compiler, {
104
+ headers: () => ({
105
+ "Last-Modified": new Date(),
106
+ }),
107
+ });
108
+ ```
109
+
110
+ or
111
+
112
+ ```js
113
+ devMiddleware(compiler, {
114
+ headers: (req, res, context) => {
115
+ res.setHeader("Last-Modified", new Date());
116
+ },
117
+ });
118
+ ```
119
+
120
+ or
121
+
122
+ ```js
123
+ devMiddleware(compiler, {
124
+ headers: [
125
+ {
126
+ key: "X-custom-header",
127
+ value: "foo",
128
+ },
129
+ {
130
+ key: "Y-custom-header",
131
+ value: "bar",
132
+ },
133
+ ],
134
+ });
135
+ ```
136
+
137
+ or
138
+
139
+ ```js
140
+ devMiddleware(compiler, {
141
+ headers: () => [
142
+ {
143
+ key: "X-custom-header",
144
+ value: "foo",
145
+ },
146
+ {
147
+ key: "Y-custom-header",
148
+ value: "bar",
149
+ },
150
+ ],
151
+ });
152
+ ```
153
+
154
+ ### index
155
+
156
+ Type: `Boolean|String`
157
+ Default: `index.html`
158
+
159
+ If `false` (but not `undefined`), the server will not respond to requests to the root URL.
160
+
161
+ ### mimeTypes
162
+
163
+ Type: `Object`
164
+ Default: `undefined`
165
+
166
+ This property allows a user to register custom mime types or extension mappings.
167
+ eg. `mimeTypes: { phtml: 'text/html' }`.
168
+
169
+ Please see the documentation for [`mrmime`](https://github.com/lukeed/mrmime) for more information.
170
+
171
+ ### mimeTypeDefault
172
+
173
+ Type: `String`
174
+ Default: `undefined`
175
+
176
+ This property allows a user to register a default mime type when we can't determine the content type.
177
+
178
+ ### etag
179
+
180
+ Type: `"weak" | "strong"`
181
+ Default: `undefined`
182
+
183
+ Enable or disable etag generation. Boolean value use
184
+
185
+ ### lastModified
186
+
187
+ Type: `Boolean`
188
+ Default: `undefined`
189
+
190
+ Enable or disable `Last-Modified` header. Uses the file system's last modified value.
191
+
192
+ ### cacheControl
193
+
194
+ Type: `Boolean | Number | String | { maxAge?: number, immutable?: boolean }`
195
+ Default: `undefined`
196
+
197
+ Depending on the setting, the following headers will be generated:
198
+
199
+ - `Boolean` - `Cache-Control: public, max-age=31536000000`
200
+ - `Number` - `Cache-Control: public, max-age=YOUR_NUMBER`
201
+ - `String` - `Cache-Control: YOUR_STRING`
202
+ - `{ maxAge?: number, immutable?: boolean }` - `Cache-Control: public, max-age=YOUR_MAX_AGE_or_31536000000`, also `, immutable` can be added if you set the `immutable` option to `true`
203
+
204
+ Enable or disable setting `Cache-Control` response header.
205
+
206
+ ### cacheImmutable
207
+
208
+ Type: `Boolean`
209
+ Default: `undefined`
210
+
211
+ Enable or disable setting `Cache-Control: public, max-age=31536000, immutable` response header for immutable assets (i.e. asset with a hash like `image.a4c12bde.jpg`).
212
+ Immutable assets are assets that have their hash in the file name therefore they can be cached, because if you change their contents the file name will be changed.
213
+ Take preference over the `cacheControl` option if the asset was defined as immutable.
214
+
215
+ ### publicPath
216
+
217
+ Type: `String`
218
+ Default: `output.publicPath` (from a configuration)
219
+
220
+ The public path that the middleware is bound to.
221
+
222
+ > Best Practice: use the same `publicPath` defined in your Rspack config.
223
+
224
+ ### stats
225
+
226
+ Type: `Boolean|String|Object`
227
+ Default: `stats` (from a configuration)
228
+
229
+ Stats options object or preset name.
230
+
231
+ ### serverSideRender
232
+
233
+ Type: `Boolean`
234
+ Default: `undefined`
235
+
236
+ Instructs the module to enable or disable the server-side rendering mode.
237
+ Please see [Server-Side Rendering](#server-side-rendering) for more information.
238
+
239
+ ### writeToDisk
240
+
241
+ Type: `Boolean|Function`
242
+ Default: `false`
243
+
244
+ If `true`, the option will instruct the module to write files to the configured location on disk as specified in your Rspack config file.
245
+
246
+ _Setting `writeToDisk: true` won't change the behavior of `@rspack/dev-middleware`, and bundle files accessed through the browser will still be served from memory._
247
+
248
+ This option also accepts a `Function` value, which can be used to filter which files are written to disk.
249
+ The function follows the same premise as [`Array#filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) in which a return value of `false` _will not_ write the file, and a return value of `true` _will_ write the file to disk. eg.
250
+
251
+ ```js
252
+ const { rspack } = require("@rspack/core");
253
+
254
+ const configuration = {
255
+ /* Rspack configuration */
256
+ };
257
+ const compiler = rspack(configuration);
258
+
259
+ devMiddleware(compiler, {
260
+ writeToDisk: (filePath) => /superman\.css$/.test(filePath),
261
+ });
262
+ ```
263
+
264
+ ### outputFileSystem
265
+
266
+ Type: `Object`
267
+ Default: [memfs](https://github.com/streamich/memfs)
268
+
269
+ Set the default file system which will be used by Rspack as primary destination of generated files.
270
+ This option isn't affected by the [writeToDisk](#writeToDisk) option.
271
+
272
+ This can be done simply by using `path.join`:
273
+
274
+ ```js
275
+ const path = require("node:path");
276
+ const mkdirp = require("mkdirp");
277
+ const myOutputFileSystem = require("my-fs");
278
+ const { rspack } = require("@rspack/core");
279
+
280
+ myOutputFileSystem.join = path.join.bind(path); // no need to bind
281
+ myOutputFileSystem.mkdirp = mkdirp.bind(mkdirp); // no need to bind
282
+
283
+ const compiler = rspack({
284
+ /* Rspack configuration */
285
+ });
286
+
287
+ devMiddleware(compiler, { outputFileSystem: myOutputFileSystem });
288
+ ```
289
+
290
+ ### modifyResponseData
291
+
292
+ Allows to set up a callback to change the response data.
293
+
294
+ ```js
295
+ const { rspack } = require("@rspack/core");
296
+
297
+ const configuration = {
298
+ /* Rspack configuration */
299
+ };
300
+ const compiler = rspack(configuration);
301
+
302
+ devMiddleware(compiler, {
303
+ // Note - if you send the `Range` header you will have `ReadStream`
304
+ // Also `data` can be `string` or `Buffer`
305
+ modifyResponseData: (req, res, data, byteLength) =>
306
+ // Your logic
307
+ // Don't use `res.end()` or `res.send()` here
308
+ ({ data, byteLength }),
309
+ });
310
+ ```
311
+
312
+ ## API
313
+
314
+ `@rspack/dev-middleware` also provides convenience methods that can be use to
315
+ interact with the middleware at runtime:
316
+
317
+ ### `close(callback)`
318
+
319
+ Instructs the `@rspack/dev-middleware` instance to stop watching for file changes.
320
+
321
+ #### Parameters
322
+
323
+ ##### `callback`
324
+
325
+ Type: `Function`
326
+ Required: `No`
327
+
328
+ A function executed once the middleware has stopped watching.
329
+
330
+ ```js
331
+ const { devMiddleware } = require("@rspack/dev-middleware");
332
+ const express = require("express");
333
+ const { rspack } = require("@rspack/core");
334
+
335
+ const compiler = rspack({
336
+ /* Rspack configuration */
337
+ });
338
+
339
+ const instance = devMiddleware(compiler);
340
+
341
+ // eslint-disable-next-line new-cap
342
+ const app = new express();
343
+
344
+ app.use(instance);
345
+
346
+ setTimeout(() => {
347
+ // Says Rspack to stop watch changes
348
+ instance.close();
349
+ }, 1000);
350
+ ```
351
+
352
+ ### `invalidate(callback)`
353
+
354
+ Instructs the `@rspack/dev-middleware` instance to recompile the bundle, e.g. after a change to the configuration.
355
+
356
+ #### Parameters
357
+
358
+ ##### `callback`
359
+
360
+ Type: `Function`
361
+ Required: `No`
362
+
363
+ A function executed once the middleware has invalidated.
364
+
365
+ ```js
366
+ const { devMiddleware } = require("@rspack/dev-middleware");
367
+ const express = require("express");
368
+ const { rspack } = require("@rspack/core");
369
+
370
+ const compiler = rspack({
371
+ /* Rspack configuration */
372
+ });
373
+
374
+ const instance = devMiddleware(compiler);
375
+
376
+ // eslint-disable-next-line new-cap
377
+ const app = new express();
378
+
379
+ app.use(instance);
380
+
381
+ setTimeout(() => {
382
+ // After a short delay the configuration is changed and a banner plugin is added to the config
383
+ new rspack.BannerPlugin("A new banner").apply(compiler);
384
+
385
+ // Recompile the bundle with the banner plugin:
386
+ instance.invalidate();
387
+ }, 1000);
388
+ ```
389
+
390
+ ### `waitUntilValid(callback)`
391
+
392
+ Executes a callback function when the compiler bundle is valid, typically after
393
+ compilation.
394
+
395
+ #### Parameters
396
+
397
+ ##### `callback`
398
+
399
+ Type: `Function`
400
+ Required: `No`
401
+
402
+ A function executed when the bundle becomes valid.
403
+ If the bundle is valid at the time of calling, the callback is executed immediately.
404
+
405
+ ```js
406
+ const { devMiddleware } = require("@rspack/dev-middleware");
407
+ const express = require("express");
408
+ const { rspack } = require("@rspack/core");
409
+
410
+ const compiler = rspack({
411
+ /* Rspack configuration */
412
+ });
413
+
414
+ const instance = devMiddleware(compiler);
415
+
416
+ // eslint-disable-next-line new-cap
417
+ const app = new express();
418
+
419
+ app.use(instance);
420
+
421
+ instance.waitUntilValid(() => {
422
+ console.log("Package is in a valid state");
423
+ });
424
+ ```
425
+
426
+ ### `getFilenameFromUrl(url)`
427
+
428
+ Get filename from URL.
429
+
430
+ #### Parameters
431
+
432
+ ##### `url`
433
+
434
+ Type: `String`
435
+ Required: `Yes`
436
+
437
+ URL for the requested file.
438
+
439
+ ```js
440
+ const { devMiddleware } = require("@rspack/dev-middleware");
441
+ const express = require("express");
442
+ const { rspack } = require("@rspack/core");
443
+
444
+ const compiler = rspack({
445
+ /* Rspack configuration */
446
+ });
447
+
448
+ const instance = devMiddleware(compiler);
449
+
450
+ // eslint-disable-next-line new-cap
451
+ const app = new express();
452
+
453
+ app.use(instance);
454
+
455
+ instance.waitUntilValid(() => {
456
+ const filename = instance.getFilenameFromUrl("/bundle.js");
457
+
458
+ console.log(`Filename is ${filename}`);
459
+ });
460
+ ```
461
+
462
+ ## FAQ
463
+
464
+ ### Avoid blocking requests to non-Rspack resources.
465
+
466
+ Since `output.publicPath` and `output.filename`/`output.chunkFilename` can be dynamic, it's not possible to know which files are Rspack bundles (and they public paths) and which are not, so we can't avoid blocking requests.
467
+
468
+ But there is a solution to avoid it - mount the middleware to a non-root route, for example:
469
+
470
+ ```js
471
+ const { devMiddleware } = require("@rspack/dev-middleware");
472
+ const express = require("express");
473
+ const { rspack } = require("@rspack/core");
474
+
475
+ const compiler = rspack({
476
+ // Rspack options
477
+ });
478
+
479
+ const app = express();
480
+
481
+ // Mounting the middleware to the non-root route allows avoids this.
482
+ // Note - check your public path, if you want to handle `/dist/`, you need to setup `output.publicPath` to `/` value.
483
+ app.use(
484
+ "/dist/",
485
+ devMiddleware(compiler, {
486
+ // @rspack/dev-middleware options
487
+ }),
488
+ );
489
+
490
+ app.listen(3000, () => console.log("Example app listening on port 3000!"));
491
+ ```
492
+
493
+ ## Server-Side Rendering
494
+
495
+ _Note: this feature is experimental and may be removed or changed completely in the future._
496
+
497
+ In order to develop an app using server-side rendering, we need access to the
498
+ [`stats`](https://rspack.rs/api/javascript-api/stats), which is
499
+ generated with each build.
500
+
501
+ With server-side rendering enabled, `@rspack/dev-middleware` sets the `stats` to `res.locals.rspack.devMiddleware.stats`
502
+ and the filesystem to `res.locals.rspack.devMiddleware.outputFileSystem` before invoking the next middleware,
503
+ allowing a developer to render the page body and manage the response to clients.
504
+
505
+ _Note: Requests for bundle files will still be handled by
506
+ `@rspack/dev-middleware` and all requests will be pending until the build
507
+ process is finished with server-side rendering enabled._
508
+
509
+ Example Implementation:
510
+
511
+ ```js
512
+ const { devMiddleware } = require("@rspack/dev-middleware");
513
+ const express = require("express");
514
+ const isObject = require("is-object");
515
+ const { rspack } = require("@rspack/core");
516
+
517
+ const compiler = rspack({
518
+ /* Rspack configuration */
519
+ });
520
+
521
+ // eslint-disable-next-line new-cap
522
+ const app = new express();
523
+
524
+ // This function makes server rendering of asset references consistent with different Rspack chunk/entry configurations
525
+ function normalizeAssets(assets) {
526
+ if (isObject(assets)) {
527
+ return Object.values(assets);
528
+ }
529
+
530
+ return Array.isArray(assets) ? assets : [assets];
531
+ }
532
+
533
+ app.use(devMiddleware(compiler, { serverSideRender: true }));
534
+
535
+ // The following middleware would not be invoked until the latest build is finished.
536
+ app.use((req, res) => {
537
+ const { devMiddleware } = res.locals.rspack;
538
+ const { outputFileSystem } = devMiddleware;
539
+ const jsonStats = devMiddleware.stats.toJson();
540
+ const { assetsByChunkName, outputPath } = jsonStats;
541
+
542
+ // Then use `assetsByChunkName` for server-side rendering
543
+ // For example, if you have only one main chunk:
544
+ res.send(`
545
+ <html>
546
+ <head>
547
+ <title>My App</title>
548
+ <style>
549
+ ${normalizeAssets(assetsByChunkName.main)
550
+ .filter((path) => path.endsWith(".css"))
551
+ .map((path) => outputFileSystem.readFileSync(path.join(outputPath, path)))
552
+ .join("\n")}
553
+ </style>
554
+ </head>
555
+ <body>
556
+ <div id="root"></div>
557
+ ${normalizeAssets(assetsByChunkName.main)
558
+ .filter((path) => path.endsWith(".js"))
559
+ .map((path) => `<script src="${path}"></script>`)
560
+ .join("\n")}
561
+ </body>
562
+ </html>
563
+ `);
564
+ });
565
+ ```
566
+
567
+ ## Other servers
568
+
569
+ Examples of use with other servers will follow here.
570
+
571
+ ### Connect
572
+
573
+ ```js
574
+ const http = require("node:http");
575
+ const { devMiddleware } = require("@rspack/dev-middleware");
576
+ const connect = require("connect");
577
+ const { rspack } = require("@rspack/core");
578
+ const rspackConfig = require("./rspack.config.js");
579
+
580
+ const compiler = rspack(rspackConfig);
581
+ const devMiddlewareOptions = {
582
+ // options
583
+ };
584
+ const app = connect();
585
+
586
+ app.use(devMiddleware(compiler, devMiddlewareOptions));
587
+
588
+ http.createServer(app).listen(3000);
589
+ ```
590
+
591
+ ### Router
592
+
593
+ ```js
594
+ const http = require("node:http");
595
+ const { devMiddleware } = require("@rspack/dev-middleware");
596
+ const finalhandler = require("finalhandler");
597
+ const Router = require("router");
598
+ const { rspack } = require("@rspack/core");
599
+ const rspackConfig = require("./rspack.config.js");
600
+
601
+ const compiler = rspack(rspackConfig);
602
+ const devMiddlewareOptions = {
603
+ // options
604
+ };
605
+
606
+ // eslint-disable-next-line new-cap
607
+ const router = Router();
608
+
609
+ router.use(devMiddleware(compiler, devMiddlewareOptions));
610
+
611
+ const server = http.createServer((req, res) => {
612
+ router(req, res, finalhandler(req, res));
613
+ });
614
+
615
+ server.listen(3000);
616
+ ```
617
+
618
+ ### Express
619
+
620
+ ```js
621
+ const { devMiddleware } = require("@rspack/dev-middleware");
622
+ const express = require("express");
623
+ const { rspack } = require("@rspack/core");
624
+ const rspackConfig = require("./rspack.config.js");
625
+
626
+ const compiler = rspack(rspackConfig);
627
+ const devMiddlewareOptions = {
628
+ // options
629
+ };
630
+ const app = express();
631
+
632
+ app.use(devMiddleware(compiler, devMiddlewareOptions));
633
+
634
+ app.listen(3000, () => console.log("Example app listening on port 3000!"));
635
+ ```
636
+
637
+ ### Koa
638
+
639
+ ```js
640
+ const { devMiddleware } = require("@rspack/dev-middleware");
641
+ const Koa = require("koa");
642
+ const { rspack } = require("@rspack/core");
643
+ const rspackConfig = require("./rspack.simple.config");
644
+
645
+ const compiler = rspack(rspackConfig);
646
+ const devMiddlewareOptions = {
647
+ // options
648
+ };
649
+ const app = new Koa();
650
+
651
+ app.use(middleware.koaWrapper(compiler, devMiddlewareOptions));
652
+
653
+ app.listen(3000);
654
+ ```
655
+
656
+ ### Hapi
657
+
658
+ ```js
659
+ const Hapi = require("@hapi/hapi");
660
+ const { devMiddleware } = require("@rspack/dev-middleware");
661
+ const { rspack } = require("@rspack/core");
662
+ const rspackConfig = require("./rspack.config.js");
663
+
664
+ const compiler = rspack(rspackConfig);
665
+ const devMiddlewareOptions = {};
666
+
667
+ const server = Hapi.server({ port: 3000, host: "localhost" });
668
+
669
+ await server.register({
670
+ plugin: devMiddleware.hapiWrapper(),
671
+ options: {
672
+ // The `compiler` option is required
673
+ compiler,
674
+ ...devMiddlewareOptions,
675
+ },
676
+ });
677
+
678
+ await server.start();
679
+
680
+ console.log("Server running on %s", server.info.uri);
681
+
682
+ process.on("unhandledRejection", (err) => {
683
+ console.log(err);
684
+ process.exit(1);
685
+ });
686
+ ```
687
+
688
+ ### Fastify
689
+
690
+ Fastify interop will require the use of `fastify-express` instead of `middie` for providing middleware support. As the authors of `fastify-express` recommend, this should only be used as a stopgap while full Fastify support is worked on.
691
+
692
+ ```js
693
+ const { devMiddleware } = require("@rspack/dev-middleware");
694
+ const fastify = require("fastify")();
695
+ const { rspack } = require("@rspack/core");
696
+ const rspackConfig = require("./rspack.config.js");
697
+
698
+ const compiler = rspack(rspackConfig);
699
+ const devMiddlewareOptions = {
700
+ // options
701
+ };
702
+
703
+ await fastify.register(require("@fastify/express"));
704
+ await fastify.use(devMiddleware(compiler, devMiddlewareOptions));
705
+ await fastify.listen(3000);
706
+ ```
707
+
708
+ ### Hono
709
+
710
+ ```js
711
+ import { serve } from "@hono/node-server";
712
+ import devMiddleware from "@rspack/dev-middleware";
713
+ import { Hono } from "hono";
714
+ import { rspack } from "@rspack/core";
715
+ import rspackConfig from "./rspack.config.js";
716
+
717
+ const compiler = rspack(rspackConfig);
718
+ const devMiddlewareOptions = {
719
+ // options
720
+ };
721
+
722
+ const app = new Hono();
723
+
724
+ app.use(devMiddleware.honoWrapper(compiler, devMiddlewareOptions));
725
+
726
+ serve(app);
727
+ ```
728
+
729
+ ## Credits
730
+
731
+ This repository is forked from [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware). It adapts the original implementation for the Rspack ecosystem, bridging behavioral differences with webpack while adding Rspack-specific capabilities.
732
+
733
+ > Thanks to the webpack-dev-middleware maintainers and its original creator, [@sokra](https://github.com/sokra).
9
734
 
10
- Development middleware for rspack.
735
+ ## Contributing
11
736
 
12
- ## Documentation
737
+ Please take a moment to read our contributing guidelines if you haven't yet done so.
13
738
 
14
- See [https://rspack.dev](https://rspack.dev) for details.
739
+ [CONTRIBUTING](./CONTRIBUTING.md)
15
740
 
16
741
  ## License
17
742
 
18
- Rspack is [MIT licensed](https://github.com/web-infra-dev/rspack/blob/main/LICENSE).
743
+ [MIT](./LICENSE)