rspack-dev-middleware 0.4.1 → 0.4.2

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.
Files changed (75) hide show
  1. package/cjs/client/HotUpdate.cjs +1 -1
  2. package/cjs/client/client.cjs +2 -2
  3. package/cjs/client/events.cjs +5 -5
  4. package/cjs/client/events.d.cts +3 -7
  5. package/cjs/client/index.cjs +1 -1
  6. package/cjs/client/main.cjs +3 -3
  7. package/cjs/client/ui/Overlay.cjs +4 -4
  8. package/cjs/client/ui/Progress.cjs +3 -3
  9. package/cjs/client/ui/images/rspack-logo.svg.cjs +1 -1
  10. package/cjs/client/ui/utils.cjs +16 -22
  11. package/cjs/client/ui/utils.d.cts +3 -10
  12. package/cjs/server/compose.cjs +2 -2
  13. package/cjs/server/dev/ReadStream.cjs +5 -5
  14. package/cjs/server/dev/Service.cjs +10 -21
  15. package/cjs/server/dev/index.cjs +7 -3
  16. package/cjs/server/dev/middleware.cjs +4 -5
  17. package/cjs/server/dev/utils/fs.cjs +1 -1
  18. package/cjs/server/dev/utils/http.cjs +56 -28
  19. package/cjs/server/dev/utils/http.d.cts +26 -1
  20. package/cjs/server/dev/utils/path.cjs +1 -1
  21. package/cjs/server/dev/utils/paths.cjs +1 -1
  22. package/cjs/server/dev/utils/setupHooks.cjs +3 -9
  23. package/cjs/server/dev/utils/setupOutputFileSystem.cjs +1 -1
  24. package/cjs/server/dev/utils/setupWatching.cjs +11 -16
  25. package/cjs/server/dev/utils/setupWriteToDisk.cjs +1 -1
  26. package/cjs/server/hot/Message.d.cts +16 -32
  27. package/cjs/server/hot/Socket.cjs +19 -20
  28. package/cjs/server/hot/index.cjs +1 -1
  29. package/cjs/server/hot/utils.cjs +2 -8
  30. package/cjs/server/index.cjs +1 -1
  31. package/cjs/server/schema.cjs +27 -6
  32. package/cjs/server/utils.cjs +12 -1
  33. package/cjs/server/utils.d.cts +1 -0
  34. package/esm/client/HotUpdate.js +1 -1
  35. package/esm/client/client.js +2 -2
  36. package/esm/client/events.d.ts +3 -7
  37. package/esm/client/events.js +5 -5
  38. package/esm/client/index.js +1 -1
  39. package/esm/client/main.js +3 -3
  40. package/esm/client/ui/Overlay.js +5 -5
  41. package/esm/client/ui/Progress.js +4 -4
  42. package/esm/client/ui/images/rspack-logo.svg.js +1 -1
  43. package/esm/client/ui/utils.d.ts +3 -10
  44. package/esm/client/ui/utils.js +15 -21
  45. package/esm/server/compose.js +2 -2
  46. package/esm/server/dev/ReadStream.js +5 -5
  47. package/esm/server/dev/Service.js +10 -15
  48. package/esm/server/dev/index.js +7 -3
  49. package/esm/server/dev/middleware.js +4 -5
  50. package/esm/server/dev/utils/fs.js +1 -1
  51. package/esm/server/dev/utils/http.d.ts +26 -1
  52. package/esm/server/dev/utils/http.js +62 -29
  53. package/esm/server/dev/utils/path.js +1 -1
  54. package/esm/server/dev/utils/paths.js +1 -1
  55. package/esm/server/dev/utils/setupHooks.js +4 -10
  56. package/esm/server/dev/utils/setupOutputFileSystem.js +1 -1
  57. package/esm/server/dev/utils/setupWatching.js +11 -16
  58. package/esm/server/dev/utils/setupWriteToDisk.js +1 -1
  59. package/esm/server/hot/Message.d.ts +16 -32
  60. package/esm/server/hot/Socket.js +16 -17
  61. package/esm/server/hot/index.js +1 -1
  62. package/esm/server/hot/utils.js +3 -9
  63. package/esm/server/index.js +1 -1
  64. package/esm/server/schema.js +27 -6
  65. package/esm/server/utils.d.ts +1 -0
  66. package/esm/server/utils.js +12 -2
  67. package/package.json +33 -35
  68. package/cjs/server/dev/utils/hash.cjs +0 -47
  69. package/cjs/server/dev/utils/hash.d.cts +0 -9
  70. package/cjs/server/dev/utils/ready.cjs +0 -24
  71. package/cjs/server/dev/utils/ready.d.cts +0 -5
  72. package/esm/server/dev/utils/hash.d.ts +0 -9
  73. package/esm/server/dev/utils/hash.js +0 -45
  74. package/esm/server/dev/utils/ready.d.ts +0 -5
  75. package/esm/server/dev/utils/ready.js +0 -22
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -93,7 +93,7 @@ function createClient(options) {
93
93
  const ws = new WebSocket(url);
94
94
  ws.onmessage = message => {
95
95
  const parsed = parseMessage(message);
96
- if (parsed) {
96
+ if (parsed != null) {
97
97
  const { action, payload } = parsed;
98
98
  switch (action) {
99
99
  case 'invalid':
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -28,7 +28,7 @@ const events = {
28
28
  */
29
29
  function on(event, callback) {
30
30
  const callbacks = events[event];
31
- if (callbacks) {
31
+ if (callbacks != null) {
32
32
  callbacks.push(callback);
33
33
  }
34
34
  }
@@ -40,8 +40,8 @@ function on(event, callback) {
40
40
  */
41
41
  function off(event, callback) {
42
42
  const callbacks = events[event];
43
- if (callbacks) {
44
- if (callback) {
43
+ if (callbacks != null) {
44
+ if (callback != null) {
45
45
  const index = callbacks.indexOf(callback);
46
46
  if (index >= 0) {
47
47
  callbacks.splice(index, 1);
@@ -53,7 +53,7 @@ function off(event, callback) {
53
53
  }
54
54
  function emit(event, message, options) {
55
55
  const callbacks = events[event];
56
- if (callbacks && callbacks.length > 0) {
56
+ if (callbacks != null && callbacks.length > 0) {
57
57
  for (const callback of callbacks) {
58
58
  callback(message, options);
59
59
  }
@@ -4,13 +4,9 @@
4
4
  import { Options } from './client.cjs';
5
5
  import { GetProp } from '../server/interface.cjs';
6
6
  import { Messages } from '../server/hot/Message.cjs';
7
- export interface Events {
8
- ok(message: GetProp<Messages, 'ok'>, options: Options): void;
9
- hash(message: GetProp<Messages, 'hash'>, options: Options): void;
10
- issues(message: GetProp<Messages, 'issues'>, options: Options): void;
11
- invalid(message: GetProp<Messages, 'invalid'>, options: Options): void;
12
- progress(message: GetProp<Messages, 'progress'>, options: Options): void;
13
- }
7
+ export type Events = {
8
+ [E in keyof Messages]: (message: Messages[E], options: Options) => void;
9
+ };
14
10
  /**
15
11
  * @function on
16
12
  * @description Add an event listener callback.
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -20,7 +20,7 @@ const isTLS = protocol => {
20
20
  };
21
21
  const getCurrentScript = () => {
22
22
  const { currentScript } = document;
23
- if (currentScript) {
23
+ if (currentScript != null) {
24
24
  return currentScript;
25
25
  }
26
26
  };
@@ -37,7 +37,7 @@ const getProtocol = (params, protocol) => {
37
37
  const getOrigin = params => {
38
38
  const { location } = self;
39
39
  const script = getCurrentScript();
40
- if (script) {
40
+ if (script != null) {
41
41
  const url = new URL(script.src, location.href);
42
42
  const protocol = getProtocol(params, url.protocol);
43
43
  return `${protocol}//${url.host}`;
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -186,8 +186,8 @@ class Overlay {
186
186
  #warningsTitle;
187
187
  constructor(name) {
188
188
  const root = utils.getRootElement(OVERLAY);
189
- utils.insertCSSString(CSS, root);
190
- const [dialog] = utils.appendDOMString('text/html', HTML, root);
189
+ utils.appendStyleSheet(CSS, root);
190
+ const dialog = utils.appendMarkup('text/html', HTML, root);
191
191
  this.#dialog = dialog;
192
192
  this.#name = dialog.querySelector(`.${OVERLAY}-name`);
193
193
  this.#close = dialog.querySelector(`.${OVERLAY}-close`);
@@ -213,7 +213,7 @@ class Overlay {
213
213
  problemTitle.innerText = `${count} ${name}(s)`;
214
214
  for (const { moduleName, chunkName, message } of issues) {
215
215
  const details = utils.ansiToHTML(message);
216
- const filename = moduleName || chunkName || 'unknown';
216
+ const filename = utils.escapeHTML(moduleName || chunkName || 'unknown');
217
217
  html += `<section><em>${name}</em> in ${filename}<pre>${details}</pre></section>`;
218
218
  }
219
219
  problemList.innerHTML = html;
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -67,8 +67,8 @@ class Progress {
67
67
  #track;
68
68
  constructor() {
69
69
  const root = utils.getRootElement(PROGRESS);
70
- utils.insertCSSString(CSS, root);
71
- [this.#svg] = utils.appendDOMString('image/svg+xml', SVG, root);
70
+ utils.appendStyleSheet(CSS, root);
71
+ this.#svg = utils.appendMarkup('image/svg+xml', SVG, root);
72
72
  this.#track = this.#svg.querySelector(`.${PROGRESS}-track`);
73
73
  }
74
74
  update(percent) {
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -65,10 +65,10 @@ function blockToHTML({ style, value, url }) {
65
65
  textDecorations.push('line-through');
66
66
  }
67
67
  const { color, background } = style;
68
- if (color) {
68
+ if (color != null) {
69
69
  styles.push(`color: rgb(${color})`);
70
70
  }
71
- if (background) {
71
+ if (background != null) {
72
72
  styles.push(`background-color: rgb(${background})`);
73
73
  }
74
74
  if (textDecorations.length > 0) {
@@ -104,29 +104,23 @@ function getRootElement(tagName) {
104
104
  document.body.appendChild(stage);
105
105
  return shadowRoot;
106
106
  }
107
- function insertCSSString(css, root = document.body, styleElement = document.createElement('style')) {
108
- styleElement.appendChild(document.createTextNode(css));
109
- if (!root.contains(styleElement)) {
110
- root.appendChild(styleElement);
111
- }
112
- return styleElement;
107
+ function appendStyleSheet(css, root) {
108
+ const styleElement = document.createElement('style');
109
+ styleElement.textContent = css;
110
+ root.appendChild(styleElement);
113
111
  }
114
- function appendDOMString(type, string, root = document.body) {
115
- const nodes = [];
116
- const parser = new DOMParser();
117
- const fragment = document.createDocumentFragment();
118
- const { body, childNodes } = parser.parseFromString(string, type);
119
- for (const node of body ? body.childNodes : childNodes) {
120
- nodes.push(node);
121
- fragment.appendChild(node);
122
- }
123
- root.appendChild(fragment);
124
- return nodes;
112
+ function appendMarkup(type, string, root) {
113
+ const { body, documentElement } = new DOMParser().parseFromString(string, type);
114
+ // XML: the root element is documentElement.
115
+ // HTML: the implicit <head> precedes <body>, the root element is body.firstElementChild.
116
+ const element = type === 'image/svg+xml' ? documentElement : body.firstElementChild;
117
+ root.appendChild(element);
118
+ return element;
125
119
  }
126
120
 
127
121
  exports.ansiToHTML = ansiToHTML;
128
- exports.appendDOMString = appendDOMString;
122
+ exports.appendMarkup = appendMarkup;
123
+ exports.appendStyleSheet = appendStyleSheet;
129
124
  exports.blockToHTML = blockToHTML;
130
125
  exports.escapeHTML = escapeHTML;
131
126
  exports.getRootElement = getRootElement;
132
- exports.insertCSSString = insertCSSString;
@@ -7,13 +7,6 @@ export declare function blockToHTML({ style, value, url }: AnsiBlock): string;
7
7
  export declare function ansiToHTML(text: string): string;
8
8
  export type RootElement = HTMLElement | ShadowRoot;
9
9
  export declare function getRootElement(tagName: string): ShadowRoot;
10
- export declare function insertCSSString(
11
- css: string,
12
- root?: HTMLElement | ShadowRoot,
13
- styleElement?: HTMLStyleElement
14
- ): HTMLStyleElement;
15
- export declare function appendDOMString<T extends DOMParserSupportedType>(
16
- type: T,
17
- string: string,
18
- root?: RootElement
19
- ): (T extends 'image/svg+xml' ? SVGElement : HTMLElement)[];
10
+ export declare function appendStyleSheet(css: string, root: RootElement): void;
11
+ export declare function appendMarkup(type: 'text/html', html: string, root: RootElement): HTMLElement;
12
+ export declare function appendMarkup(type: 'image/svg+xml', svg: string, root: RootElement): SVGElement;
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -33,7 +33,7 @@ async function dispatch(middlewares, index, stack, context, next) {
33
33
  await middleware(context, () => {
34
34
  return dispatch(middlewares, index + 1, stack, context, next);
35
35
  });
36
- } else if (next) {
36
+ } else if (next != null) {
37
37
  await next();
38
38
  }
39
39
  }
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -99,12 +99,12 @@ class ReadStream extends node_stream.Readable {
99
99
  // Change read state.
100
100
  switch (this.#readState) {
101
101
  case 0 /* ReadState.PREFIX */:
102
- this.#readState = 1 /* ReadState.RANGE */;
102
+ this.#readState = 1; /* ReadState.RANGE */
103
103
  this.#readFileRange(fd, range, size - bytesRead);
104
104
  break;
105
105
  case 2 /* ReadState.SUFFIX */:
106
106
  this.#currentRangeIndex++;
107
- this.#readState = 0 /* ReadState.PREFIX */;
107
+ this.#readState = 0; /* ReadState.PREFIX */
108
108
  const nextRange = this.#getRange();
109
109
  if (nextRange == null) {
110
110
  this.push(null);
@@ -147,14 +147,14 @@ class ReadStream extends node_stream.Readable {
147
147
  // file range read completed.
148
148
  if (bytesRead < size) {
149
149
  this.#bytesRead = 0;
150
- this.#readState = 2 /* ReadState.SUFFIX */;
150
+ this.#readState = 2; /* ReadState.SUFFIX */
151
151
  this.#readPadding(fd, range, size - bytesRead);
152
152
  }
153
153
  }
154
154
  });
155
155
  } else {
156
156
  this.#bytesRead = 0;
157
- this.#readState = 2 /* ReadState.SUFFIX */;
157
+ this.#readState = 2; /* ReadState.SUFFIX */
158
158
  this.#readPadding(fd, range, size);
159
159
  }
160
160
  }
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -10,7 +10,6 @@
10
10
 
11
11
  'use strict';
12
12
 
13
- const createETag = require('etag');
14
13
  const ReadStream = require('./ReadStream.cjs');
15
14
  const utils = require('../utils.cjs');
16
15
  const fs = require('./utils/fs.cjs');
@@ -18,12 +17,6 @@ const node_path = require('node:path');
18
17
  const path = require('./utils/path.cjs');
19
18
  const http = require('./utils/http.cjs');
20
19
 
21
- function _interopDefault(e) {
22
- return e && e.__esModule ? e : { default: e };
23
- }
24
-
25
- const createETag__default = /*#__PURE__*/ _interopDefault(createETag);
26
-
27
20
  /**
28
21
  * @module Service
29
22
  */
@@ -66,7 +59,7 @@ class Service {
66
59
  // Get headers.
67
60
  const headers = await options.headers(path, stats);
68
61
  // If headers not empty, set headers.
69
- if (headers) {
62
+ if (headers != null) {
70
63
  response.set(headers);
71
64
  }
72
65
  // Accept-Ranges.
@@ -83,7 +76,7 @@ class Service {
83
76
  response.remove('ETag');
84
77
  } else if (!response.get('ETag')) {
85
78
  // Set weak ETag.
86
- response.set('ETag', createETag__default.default(stats));
79
+ response.set('ETag', http.createETag(stats));
87
80
  }
88
81
  // Last-Modified.
89
82
  if (options.lastModified === false) {
@@ -160,10 +153,8 @@ class Service {
160
153
  }
161
154
  // Head request.
162
155
  if (request.method === 'HEAD') {
163
- // Set Content-Length.
156
+ // Set Content-Length, koa keeps it and sends no body for HEAD.
164
157
  response.length = stats.size;
165
- // Set body null
166
- response.body = null;
167
158
  // File found.
168
159
  return true;
169
160
  }
@@ -171,14 +162,12 @@ class Service {
171
162
  const ranges = http.parseRanges(context, stats);
172
163
  // 416
173
164
  if (ranges === -1) {
174
- // Set Content-Range.
175
- response.set('Content-Range', `bytes */${stats.size}`);
176
- // Unsatisfiable 416.
177
- return context.throw(416);
178
- }
179
- // 400.
180
- if (ranges === -2) {
181
- return context.throw(400);
165
+ // koa strips all response headers on error, pass Content-Range via err.headers.
166
+ return context.throw(416, {
167
+ headers: {
168
+ 'Content-Range': `bytes */${stats.size}`
169
+ }
170
+ });
182
171
  }
183
172
  // Set response body.
184
173
  response.body = new ReadStream.ReadStream(path$1, ranges, {
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -27,8 +27,12 @@ function setup(compiler, options) {
27
27
  compiler,
28
28
  stats: null,
29
29
  callbacks: [],
30
- logger: compiler.getInfrastructureLogger(utils.PLUGIN_NAME),
31
- options: { fs: fs.createMemfs(), highWaterMark: 65536, ...options }
30
+ options: {
31
+ ...options,
32
+ fs: options.fs ?? fs.createMemfs(),
33
+ highWaterMark: options.highWaterMark ?? 65536
34
+ },
35
+ logger: compiler.getInfrastructureLogger(utils.PLUGIN_NAME)
32
36
  };
33
37
  setupHooks.setupHooks(context);
34
38
  if (options.writeToDisk) {
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -11,7 +11,6 @@
11
11
  'use strict';
12
12
 
13
13
  const Service = require('./Service.cjs');
14
- const ready = require('./utils/ready.cjs');
15
14
  const http = require('./utils/http.cjs');
16
15
  const paths = require('./utils/paths.cjs');
17
16
 
@@ -31,13 +30,13 @@ function getFileServices(context, stats) {
31
30
  }
32
31
  function getFileServicesAsync(context) {
33
32
  return new Promise(resolve => {
34
- const { stats } = context;
35
- // If stats exists, resolve immediately.
33
+ const { stats, callbacks } = context;
34
+ // Resolve immediately if stats exists.
36
35
  if (stats) {
37
36
  resolve(getFileServices(context, stats));
38
37
  } else {
39
38
  // Otherwise, wait until bundle finished.
40
- ready.ready(context, stats => {
39
+ callbacks.push(stats => {
41
40
  resolve(getFileServices(context, stats));
42
41
  });
43
42
  }
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -2,7 +2,7 @@
2
2
  * @module rspack-dev-middleware
3
3
  * @package rspack-dev-middleware
4
4
  * @license MIT
5
- * @version 0.4.1
5
+ * @version 0.4.2
6
6
  * @author nuintun <nuintun@qq.com>
7
7
  * @description A koa 2 middleware for rspack development and hot reloading.
8
8
  * @see https://github.com/nuintun/rspack-dev-middleware#readme
@@ -10,9 +10,9 @@
10
10
 
11
11
  'use strict';
12
12
 
13
- const hash = require('./hash.cjs');
14
13
  const node_buffer = require('node:buffer');
15
14
  const parseRange = require('range-parser');
15
+ const node_crypto = require('node:crypto');
16
16
 
17
17
  function _interopDefault(e) {
18
18
  return e && e.__esModule ? e : { default: e };
@@ -24,6 +24,7 @@ const parseRange__default = /*#__PURE__*/ _interopDefault(parseRange);
24
24
  * @module http
25
25
  */
26
26
  const SPLIT_ETAG_RE = /\s*,\s*/;
27
+ const BOUNDARY_SCRATCH = node_buffer.Buffer.allocUnsafeSlow(24);
27
28
  const SINGLE_ETAG_RE = /^(?:W\/)?"[ !#-\x7E\x80-\xFF]+"$/;
28
29
  /**
29
30
  * @function decodeURI
@@ -37,6 +38,13 @@ function decodeURI(URI) {
37
38
  return -1;
38
39
  }
39
40
  }
41
+ /**
42
+ * @function generateBoundary
43
+ * @description Generate a boundary string.
44
+ */
45
+ function generateBoundary() {
46
+ return node_crypto.getRandomValues(BOUNDARY_SCRATCH).toString('base64url');
47
+ }
40
48
  /**
41
49
  * @function isConditionalGET
42
50
  * @description Check if request is conditional GET.
@@ -50,6 +58,14 @@ function isConditionalGET({ request }) {
50
58
  request.get('If-Unmodified-Since')
51
59
  );
52
60
  }
61
+ /**
62
+ * @function createETag
63
+ * @description Generate a weak entity tag from file stats.
64
+ * @param stats The file stats.
65
+ */
66
+ function createETag(stats) {
67
+ return `W/"${stats.size.toString(16)}-${stats.mtime.getTime().toString(16)}"`;
68
+ }
53
69
  /**
54
70
  * @function isETagMatch
55
71
  * @see https://httpwg.org/specs/rfc9110.html
@@ -58,25 +74,45 @@ function isConditionalGET({ request }) {
58
74
  * @param isIfMatch The flag of if-match.
59
75
  */
60
76
  function isETagMatch(match, etag, isIfMatch) {
77
+ // Trim match.
78
+ match = match.trim();
79
+ // Check If-Match.
80
+ if (isIfMatch && match === '*') {
81
+ // The condition is true if the selected representation exists.
82
+ return true;
83
+ }
61
84
  // Trim etag.
62
85
  etag = etag.trim();
63
86
  // Weak tags cannot be matched and return false.
64
87
  if (!etag || etag.startsWith('W/')) {
65
88
  return false;
66
89
  }
67
- // Trim match.
68
- match = match.trim();
69
90
  // Check If-Match.
70
91
  if (isIfMatch) {
71
- if (match === '*') {
72
- return true;
73
- }
74
92
  // If-Match maybe a list of etag.
75
93
  return match.split(SPLIT_ETAG_RE).includes(etag);
76
94
  }
77
95
  // Check If-Range.
78
96
  return match === etag;
79
97
  }
98
+ /**
99
+ * @function isRangeFresh
100
+ * @description Check if request range fresh.
101
+ * @param context Koa context.
102
+ */
103
+ function isRangeFresh({ request, response }) {
104
+ const ifRange = request.get('If-Range');
105
+ // No If-Range.
106
+ if (!ifRange) {
107
+ return true;
108
+ }
109
+ // If-Range as modified date failed.
110
+ if (SINGLE_ETAG_RE.test(ifRange)) {
111
+ return isETagMatch(ifRange, response.get('ETag'));
112
+ }
113
+ // Check if Last-Modified is valid and equal to If-Range date
114
+ return Date.parse(response.get('Last-Modified')) <= Date.parse(ifRange);
115
+ }
80
116
  /**
81
117
  * @function isPreconditionFailed
82
118
  * @description Check if request precondition failed.
@@ -99,24 +135,6 @@ function isPreconditionFailed({ request, response }) {
99
135
  // Check precondition passed.
100
136
  return false;
101
137
  }
102
- /**
103
- * @function isRangeFresh
104
- * @description Check if request range fresh.
105
- * @param context Koa context.
106
- */
107
- function isRangeFresh({ request, response }) {
108
- const ifRange = request.get('If-Range');
109
- // No If-Range.
110
- if (!ifRange) {
111
- return true;
112
- }
113
- // If-Range as modified date failed.
114
- if (SINGLE_ETAG_RE.test(ifRange)) {
115
- return isETagMatch(ifRange, response.get('ETag'));
116
- }
117
- // Check if Last-Modified is valid and equal to If-Range date
118
- return Date.parse(response.get('Last-Modified')) <= Date.parse(ifRange);
119
- }
120
138
  /**
121
139
  * @function parseRanges
122
140
  * @description Parse ranges.
@@ -134,10 +152,16 @@ function parseRanges(context, stats) {
134
152
  // Parse range -1 -2 or [].
135
153
  const parsed = parseRange__default.default(size, range, { combine: true });
136
154
  // -1 signals an unsatisfiable range.
137
- // -2 signals a malformed header string.
138
- if (parsed === -1 || parsed === -2) {
155
+ if (parsed === -1) {
139
156
  return parsed;
140
157
  }
158
+ // -2 signals a malformed or unknown-unit range, ignore it (RFC 9110 §14.2).
159
+ if (parsed === -2) {
160
+ // Set Content-Length.
161
+ response.length = size;
162
+ // Return ranges.
163
+ return [{ offset: 0, length: size }];
164
+ }
141
165
  // Ranges ok, support multiple ranges.
142
166
  if (parsed.type === 'bytes') {
143
167
  // Set 206 status.
@@ -152,7 +176,7 @@ function parseRanges(context, stats) {
152
176
  // Parsed entries.
153
177
  const entries = parsed.entries();
154
178
  // Range boundary.
155
- const boundary = `${hash.generate(32)}`;
179
+ const boundary = generateBoundary();
156
180
  // Multipart Content-Type.
157
181
  const contentType = `Content-Type: ${response.type}`;
158
182
  // Range suffix.
@@ -198,7 +222,11 @@ function parseRanges(context, stats) {
198
222
  return [{ offset: 0, length: size }];
199
223
  }
200
224
 
225
+ exports.createETag = createETag;
201
226
  exports.decodeURI = decodeURI;
227
+ exports.generateBoundary = generateBoundary;
202
228
  exports.isConditionalGET = isConditionalGET;
229
+ exports.isETagMatch = isETagMatch;
203
230
  exports.isPreconditionFailed = isPreconditionFailed;
231
+ exports.isRangeFresh = isRangeFresh;
204
232
  exports.parseRanges = parseRanges;