@bleedingdev/modern-js-server 3.9.0-ultramodern.2 → 3.9.0-ultramodern.21

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.
@@ -43,7 +43,6 @@ const external_node_path_namespaceObject = require("node:path");
43
43
  var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
44
44
  const server_core_namespaceObject = require("@modern-js/server-core");
45
45
  const node_namespaceObject = require("@modern-js/server-core/node");
46
- const runtime_lifecycle_namespaceObject = require("@modern-js/server-runtime-extensions/runtime-lifecycle");
47
46
  const utils_namespaceObject = require("@modern-js/utils");
48
47
  const external_dev_js_namespaceObject = require("./dev.js");
49
48
  const reloadManager_js_namespaceObject = require("./dev-tools/reloadManager.js");
@@ -98,12 +97,17 @@ async function createDevServer(options, applyPlugins) {
98
97
  builderDevServer
99
98
  }, compiler)
100
99
  ]);
101
- const handle = await (0, runtime_lifecycle_namespaceObject.initializeDisposableServerRuntime)(runtimeServer, runtimeServer.handle, async ()=>{
100
+ try {
102
101
  await applyPlugins(runtimeServer, runtimeOptions, nodeServer);
103
102
  await runtimeServer.init();
104
- });
103
+ } catch (error) {
104
+ await runtimeServer.dispose().catch((disposeError)=>{
105
+ utils_namespaceObject.logger.error(disposeError);
106
+ });
107
+ throw error;
108
+ }
105
109
  nextRuntimeServer = runtimeServer;
106
- return handle;
110
+ return (0, reloadManager_js_namespaceObject.createDrainingHandle)(runtimeServer.handle, ()=>runtimeServer.dispose());
107
111
  };
108
112
  const pendingReloadFiles = new Set();
109
113
  const reloadManager = (0, reloadManager_js_namespaceObject.createReloadManager)({
@@ -122,8 +126,18 @@ async function createDevServer(options, applyPlugins) {
122
126
  const httpsOptions = await genHttpsOptions(devHttpsOption, pwd);
123
127
  nodeServer = await (0, node_namespaceObject.createNodeServer)(reloadManager.handle, httpsOptions, isHttp2);
124
128
  } else nodeServer = await (0, node_namespaceObject.createNodeServer)(reloadManager.handle);
125
- reloadManager.setHandle(await buildRuntimeServer());
126
- currentRuntimeServer = nextRuntimeServer;
129
+ try {
130
+ reloadManager.setHandle(await buildRuntimeServer());
131
+ currentRuntimeServer = nextRuntimeServer;
132
+ } catch (error) {
133
+ reloadManager.close();
134
+ const cleanup = await Promise.allSettled([
135
+ Promise.resolve().then(()=>builderDevServer?.close()),
136
+ Promise.resolve().then(()=>nodeServer.close())
137
+ ]);
138
+ for (const result of cleanup)if ('rejected' === result.status) utils_namespaceObject.logger.error(result.reason);
139
+ throw error;
140
+ }
127
141
  (0, external_dev_js_namespaceObject.setupDevInfra)({
128
142
  config,
129
143
  pwd,
@@ -135,6 +149,7 @@ async function createDevServer(options, applyPlugins) {
135
149
  compiler,
136
150
  nodeServer,
137
151
  getRuntimeServer: ()=>currentRuntimeServer,
152
+ holdRequests: (task)=>reloadManager.hold(task),
138
153
  onFileChange: (filepath)=>{
139
154
  pendingReloadFiles.add(external_node_path_default().relative(pwd, filepath));
140
155
  reloadManager.schedule();
@@ -29,6 +29,7 @@ var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
30
  __webpack_require__.d(__webpack_exports__, {
31
31
  ReloadManager: ()=>ReloadManager,
32
+ createDrainingHandle: ()=>createDrainingHandle,
32
33
  createReloadManager: ()=>createReloadManager
33
34
  });
34
35
  const utils_namespaceObject = require("@modern-js/utils");
@@ -71,6 +72,35 @@ function _class_private_method_init(obj, privateSet) {
71
72
  _check_private_redeclaration(obj, privateSet);
72
73
  privateSet.add(obj);
73
74
  }
75
+ function createDrainingHandle(handle, dispose) {
76
+ let activeRequests = 0;
77
+ let retired = false;
78
+ let resolveDrained;
79
+ let disposePromise;
80
+ return Object.assign(async (request, ...args)=>{
81
+ if (retired) throw new Error('Cannot dispatch through a retired server runtime.');
82
+ activeRequests += 1;
83
+ try {
84
+ return await handle(request, ...args);
85
+ } finally{
86
+ activeRequests -= 1;
87
+ if (0 === activeRequests) resolveDrained?.();
88
+ }
89
+ }, {
90
+ dispose: ()=>{
91
+ if (!disposePromise) {
92
+ retired = true;
93
+ disposePromise = Promise.resolve().then(async ()=>{
94
+ if (activeRequests > 0) await new Promise((resolve)=>{
95
+ resolveDrained = resolve;
96
+ });
97
+ await dispose();
98
+ });
99
+ }
100
+ return disposePromise;
101
+ }
102
+ });
103
+ }
74
104
  const DEFAULT_DEBOUNCE_MS = 300;
75
105
  const notReadyHandle = ()=>new Response('Dev server is starting…', {
76
106
  status: 503,
@@ -78,13 +108,21 @@ const notReadyHandle = ()=>new Response('Dev server is starting…', {
78
108
  'content-type': 'text/plain; charset=utf-8'
79
109
  }
80
110
  });
81
- var _current = /*#__PURE__*/ new WeakMap(), _build = /*#__PURE__*/ new WeakMap(), _debounceMs = /*#__PURE__*/ new WeakMap(), _onReload = /*#__PURE__*/ new WeakMap(), _onError = /*#__PURE__*/ new WeakMap(), _onReloadError = /*#__PURE__*/ new WeakMap(), _debounceTimer = /*#__PURE__*/ new WeakMap(), _running = /*#__PURE__*/ new WeakMap(), _pending = /*#__PURE__*/ new WeakMap(), _runningPromise = /*#__PURE__*/ new WeakMap(), _closed = /*#__PURE__*/ new WeakMap(), _runLoop = /*#__PURE__*/ new WeakSet(), _reportBuildError = /*#__PURE__*/ new WeakSet(), _reportReloadCallbackError = /*#__PURE__*/ new WeakSet(), _dispose = /*#__PURE__*/ new WeakSet();
111
+ var _current = /*#__PURE__*/ new WeakMap(), _build = /*#__PURE__*/ new WeakMap(), _debounceMs = /*#__PURE__*/ new WeakMap(), _onReload = /*#__PURE__*/ new WeakMap(), _onError = /*#__PURE__*/ new WeakMap(), _onReloadError = /*#__PURE__*/ new WeakMap(), _debounceTimer = /*#__PURE__*/ new WeakMap(), _running = /*#__PURE__*/ new WeakMap(), _pending = /*#__PURE__*/ new WeakMap(), _runningPromise = /*#__PURE__*/ new WeakMap(), _closed = /*#__PURE__*/ new WeakMap(), _held = /*#__PURE__*/ new WeakMap(), _holding = /*#__PURE__*/ new WeakMap(), _released = /*#__PURE__*/ new WeakSet(), _runLoop = /*#__PURE__*/ new WeakSet(), _reportBuildError = /*#__PURE__*/ new WeakSet(), _reportReloadCallbackError = /*#__PURE__*/ new WeakSet(), _dispose = /*#__PURE__*/ new WeakSet();
82
112
  class ReloadManager {
83
113
  setHandle(handle) {
84
114
  _class_private_field_set(this, _current, handle);
85
115
  }
86
116
  get handle() {
87
- return (request, ...args)=>_class_private_field_get(this, _current).call(this, request, ...args);
117
+ return (request, ...args)=>0 === _class_private_field_get(this, _holding) ? _class_private_field_get(this, _current).call(this, request, ...args) : _class_private_method_get(this, _released, released).call(this).then(()=>_class_private_field_get(this, _current).call(this, request, ...args));
118
+ }
119
+ hold(task) {
120
+ _class_private_field_set(this, _holding, _class_private_field_get(this, _holding) + 1);
121
+ const run = _class_private_field_get(this, _held).then(task).finally(()=>{
122
+ _class_private_field_set(this, _holding, _class_private_field_get(this, _holding) - 1);
123
+ });
124
+ _class_private_field_set(this, _held, run.catch(()=>{}));
125
+ return run;
88
126
  }
89
127
  get currentHandle() {
90
128
  return _class_private_field_get(this, _current);
@@ -123,9 +161,11 @@ class ReloadManager {
123
161
  clearTimeout(_class_private_field_get(this, _debounceTimer));
124
162
  _class_private_field_set(this, _debounceTimer, null);
125
163
  }
126
- _class_private_method_get(this, _dispose, dispose).call(this, _class_private_field_get(this, _current));
164
+ const current = _class_private_field_get(this, _current);
165
+ _class_private_method_get(this, _released, released).call(this).then(()=>_class_private_method_get(this, _dispose, reloadManager_dispose).call(this, current));
127
166
  }
128
167
  constructor(options){
168
+ _class_private_method_init(this, _released);
129
169
  _class_private_method_init(this, _runLoop);
130
170
  _class_private_method_init(this, _reportBuildError);
131
171
  _class_private_method_init(this, _reportReloadCallbackError);
@@ -174,11 +214,21 @@ class ReloadManager {
174
214
  writable: true,
175
215
  value: void 0
176
216
  });
217
+ _class_private_field_init(this, _held, {
218
+ writable: true,
219
+ value: void 0
220
+ });
221
+ _class_private_field_init(this, _holding, {
222
+ writable: true,
223
+ value: void 0
224
+ });
177
225
  _class_private_field_set(this, _debounceTimer, null);
178
226
  _class_private_field_set(this, _running, false);
179
227
  _class_private_field_set(this, _pending, false);
180
228
  _class_private_field_set(this, _runningPromise, null);
181
229
  _class_private_field_set(this, _closed, false);
230
+ _class_private_field_set(this, _held, Promise.resolve());
231
+ _class_private_field_set(this, _holding, 0);
182
232
  _class_private_field_set(this, _current, options.initialHandle ?? notReadyHandle);
183
233
  _class_private_field_set(this, _build, options.build);
184
234
  _class_private_field_set(this, _debounceMs, options.debounceMs ?? DEFAULT_DEBOUNCE_MS);
@@ -187,6 +237,9 @@ class ReloadManager {
187
237
  _class_private_field_set(this, _onReloadError, options.onReloadError);
188
238
  }
189
239
  }
240
+ async function released() {
241
+ while(_class_private_field_get(this, _holding) > 0)await _class_private_field_get(this, _held);
242
+ }
190
243
  async function runLoop() {
191
244
  var _this, _this1;
192
245
  do {
@@ -198,15 +251,19 @@ async function runLoop() {
198
251
  _class_private_method_get(this, _reportBuildError, reportBuildError).call(this, error);
199
252
  continue;
200
253
  }
201
- if (_class_private_field_get(this, _closed)) return void await _class_private_method_get(this, _dispose, dispose).call(this, next);
254
+ await _class_private_method_get(this, _released, released).call(this);
255
+ if (_class_private_field_get(this, _closed)) return void await _class_private_method_get(this, _dispose, reloadManager_dispose).call(this, next);
202
256
  const previous = _class_private_field_get(this, _current);
203
257
  _class_private_field_set(this, _current, next);
204
258
  try {
205
- null == (_this = _class_private_field_get(_this1 = this, _onReload)) || _this.call(_this1, next);
206
- } catch (callbackError) {
207
- _class_private_method_get(this, _reportReloadCallbackError, reportReloadCallbackError).call(this, callbackError);
259
+ try {
260
+ null == (_this = _class_private_field_get(_this1 = this, _onReload)) || _this.call(_this1, next);
261
+ } catch (callbackError) {
262
+ _class_private_method_get(this, _reportReloadCallbackError, reportReloadCallbackError).call(this, callbackError);
263
+ }
264
+ } finally{
265
+ await _class_private_method_get(this, _dispose, reloadManager_dispose).call(this, previous);
208
266
  }
209
- await _class_private_method_get(this, _dispose, dispose).call(this, previous);
210
267
  }while (_class_private_field_get(this, _pending) && !_class_private_field_get(this, _closed));
211
268
  }
212
269
  function reportBuildError(error) {
@@ -217,7 +274,7 @@ function reportReloadCallbackError(error) {
217
274
  if (_class_private_field_get(this, _onReloadError)) _class_private_field_get(this, _onReloadError).call(this, error);
218
275
  else utils_namespaceObject.logger.warn(`[dev-server] onReload callback failed after a successful swap (handle is already active):\n${error instanceof Error ? error.stack ?? error.message : error}`);
219
276
  }
220
- async function dispose(handle) {
277
+ async function reloadManager_dispose(handle) {
221
278
  try {
222
279
  await handle.dispose?.();
223
280
  } catch (error) {
@@ -228,9 +285,11 @@ function createReloadManager(options) {
228
285
  return new ReloadManager(options);
229
286
  }
230
287
  exports.ReloadManager = __webpack_exports__.ReloadManager;
288
+ exports.createDrainingHandle = __webpack_exports__.createDrainingHandle;
231
289
  exports.createReloadManager = __webpack_exports__.createReloadManager;
232
290
  for(var __rspack_i in __webpack_exports__)if (-1 === [
233
291
  "ReloadManager",
292
+ "createDrainingHandle",
234
293
  "createReloadManager"
235
294
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
236
295
  Object.defineProperty(exports, '__esModule', {
@@ -69,34 +69,28 @@ class DependencyTree {
69
69
  for (const treeNode of this.tree.values()){
70
70
  const { parent } = treeNode.module;
71
71
  const { children } = treeNode.module;
72
- if (parent && !this.shouldIgnore(parent.filename)) {
72
+ if (parent) {
73
73
  const parentTreeNode = this.tree.get(parent.filename);
74
74
  if (parentTreeNode) treeNode.parent.add(parentTreeNode);
75
75
  }
76
76
  children?.forEach((child)=>{
77
- if (!this.shouldIgnore(child.filename)) {
78
- const childTreeNode = this.tree.get(child.filename);
79
- if (childTreeNode) {
80
- treeNode.children.add(childTreeNode);
81
- childTreeNode.parent.add(treeNode);
82
- }
77
+ const childTreeNode = this.tree.get(child.filename);
78
+ if (childTreeNode) {
79
+ treeNode.children.add(childTreeNode);
80
+ childTreeNode.parent.add(treeNode);
83
81
  }
84
82
  });
85
83
  }
86
84
  }
87
85
  shouldIgnore(path) {
88
86
  const matchPath = path && external_node_path_default().isAbsolute(path) ? external_node_path_default().relative(process.cwd(), path) : path;
89
- return !matchPath || Boolean(this.ignore.find((rule)=>external_minimatch_namespaceObject.match([
90
- matchPath
91
- ], rule, {
92
- dot: true
93
- }).length > 0));
87
+ return !matchPath || this.ignore.some((rule)=>rule.match(matchPath));
94
88
  }
95
89
  constructor(){
96
90
  this.tree = new Map();
97
- this.ignore = [
98
- ...defaultIgnores
99
- ];
91
+ this.ignore = defaultIgnores.map((rule)=>new external_minimatch_namespaceObject.Minimatch(rule, {
92
+ dot: true
93
+ }));
100
94
  }
101
95
  }
102
96
  exports.DependencyTree = __webpack_exports__.DependencyTree;
@@ -49,7 +49,7 @@ const external_dependencyTree_js_namespaceObject = require("./dependencyTree.js"
49
49
  const external_statsCache_js_namespaceObject = require("./statsCache.js");
50
50
  const defaultWatchOptions = {
51
51
  ignoreInitial: true,
52
- ignored: /api\/typings\/.*/
52
+ ignored: /api\/typings\/.*|(?:^|[/\\])node_modules(?:[/\\]|$)/
53
53
  };
54
54
  const getWatchedFiles = (watcher)=>{
55
55
  const watched = watcher.getWatched();
package/dist/cjs/dev.js CHANGED
@@ -81,7 +81,7 @@ const devRuntimeMiddlewarePlugin = (options, compiler)=>({
81
81
  });
82
82
  }
83
83
  });
84
- function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, onFileChange, onClose, nodeServer }) {
84
+ function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, holdRequests, onFileChange, onClose, nodeServer }) {
85
85
  const { close, connectWebSocket } = builderDevServer || {};
86
86
  const closeCb = [];
87
87
  close && closeCb.push(close);
@@ -91,10 +91,10 @@ function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, build
91
91
  builder?.onDevCompileDone(({ stats })=>{
92
92
  if ('server' !== stats.toJson({
93
93
  all: false
94
- }).name) {
94
+ }).name) holdRequests(async ()=>{
95
95
  const runtimeServer = getRuntimeServer();
96
- if (runtimeServer) (0, index_js_namespaceObject.onRepack)(distDir, runtimeServer.hooks);
97
- }
96
+ if (runtimeServer) await (0, index_js_namespaceObject.onRepack)(distDir, runtimeServer.hooks);
97
+ }).catch((error)=>utils_namespaceObject.logger.error(error));
98
98
  });
99
99
  const { watchOptions } = config.server;
100
100
  const mockDir = config.dev?.mockDir;
@@ -129,7 +129,7 @@ async function getMockMiddleware(pwd, mockDir) {
129
129
  if (matchedMockAPI) {
130
130
  const { handler } = matchedMockAPI;
131
131
  if ('function' == typeof handler) return await (0, node_namespaceObject.connectMockMid2HonoMid)(handler)(c, next);
132
- return c.json(handler);
132
+ else return c.json(handler);
133
133
  }
134
134
  return next();
135
135
  };
@@ -36,14 +36,17 @@ const cleanSSRCache = (distDir)=>{
36
36
  if (key.startsWith(distDir)) delete require.cache[key];
37
37
  });
38
38
  };
39
- const onRepack = (distDir, hooks)=>{
40
- cleanSSRCache(distDir);
41
- fileReader_namespaceObject.fileReader.reset();
42
- hooks.onReset.call({
43
- event: {
44
- type: 'repack'
45
- }
46
- });
39
+ const onRepack = async (distDir, hooks)=>{
40
+ try {
41
+ await hooks.onReset.call({
42
+ event: {
43
+ type: 'repack'
44
+ }
45
+ });
46
+ } finally{
47
+ cleanSSRCache(distDir);
48
+ fileReader_namespaceObject.fileReader.reset();
49
+ }
47
50
  };
48
51
  exports.onRepack = __webpack_exports__.onRepack;
49
52
  for(var __rspack_i in __webpack_exports__)if (-1 === [
@@ -1,10 +1,9 @@
1
1
  import node_path from "node:path";
2
2
  import { createServerBase } from "@modern-js/server-core";
3
3
  import { createNodeServer, loadServerRuntimeConfig } from "@modern-js/server-core/node";
4
- import { initializeDisposableServerRuntime } from "@modern-js/server-runtime-extensions/runtime-lifecycle";
5
4
  import { logger } from "@modern-js/utils";
6
5
  import { devRuntimeMiddlewarePlugin, setupDevInfra } from "./dev.mjs";
7
- import { createReloadManager } from "./dev-tools/reloadManager.mjs";
6
+ import { createDrainingHandle, createReloadManager } from "./dev-tools/reloadManager.mjs";
8
7
  import { createRuntimeServerOptions } from "./dev-tools/runtimeOptions.mjs";
9
8
  import { getDevAssetPrefix, getDevOptions } from "./helpers/index.mjs";
10
9
  async function createDevServer(options, applyPlugins) {
@@ -56,12 +55,17 @@ async function createDevServer(options, applyPlugins) {
56
55
  builderDevServer
57
56
  }, compiler)
58
57
  ]);
59
- const handle = await initializeDisposableServerRuntime(runtimeServer, runtimeServer.handle, async ()=>{
58
+ try {
60
59
  await applyPlugins(runtimeServer, runtimeOptions, nodeServer);
61
60
  await runtimeServer.init();
62
- });
61
+ } catch (error) {
62
+ await runtimeServer.dispose().catch((disposeError)=>{
63
+ logger.error(disposeError);
64
+ });
65
+ throw error;
66
+ }
63
67
  nextRuntimeServer = runtimeServer;
64
- return handle;
68
+ return createDrainingHandle(runtimeServer.handle, ()=>runtimeServer.dispose());
65
69
  };
66
70
  const pendingReloadFiles = new Set();
67
71
  const reloadManager = createReloadManager({
@@ -80,8 +84,18 @@ async function createDevServer(options, applyPlugins) {
80
84
  const httpsOptions = await genHttpsOptions(devHttpsOption, pwd);
81
85
  nodeServer = await createNodeServer(reloadManager.handle, httpsOptions, isHttp2);
82
86
  } else nodeServer = await createNodeServer(reloadManager.handle);
83
- reloadManager.setHandle(await buildRuntimeServer());
84
- currentRuntimeServer = nextRuntimeServer;
87
+ try {
88
+ reloadManager.setHandle(await buildRuntimeServer());
89
+ currentRuntimeServer = nextRuntimeServer;
90
+ } catch (error) {
91
+ reloadManager.close();
92
+ const cleanup = await Promise.allSettled([
93
+ Promise.resolve().then(()=>builderDevServer?.close()),
94
+ Promise.resolve().then(()=>nodeServer.close())
95
+ ]);
96
+ for (const result of cleanup)if ('rejected' === result.status) logger.error(result.reason);
97
+ throw error;
98
+ }
85
99
  setupDevInfra({
86
100
  config,
87
101
  pwd,
@@ -93,6 +107,7 @@ async function createDevServer(options, applyPlugins) {
93
107
  compiler,
94
108
  nodeServer,
95
109
  getRuntimeServer: ()=>currentRuntimeServer,
110
+ holdRequests: (task)=>reloadManager.hold(task),
96
111
  onFileChange: (filepath)=>{
97
112
  pendingReloadFiles.add(node_path.relative(pwd, filepath));
98
113
  reloadManager.schedule();
@@ -38,6 +38,35 @@ function _class_private_method_init(obj, privateSet) {
38
38
  _check_private_redeclaration(obj, privateSet);
39
39
  privateSet.add(obj);
40
40
  }
41
+ function createDrainingHandle(handle, dispose) {
42
+ let activeRequests = 0;
43
+ let retired = false;
44
+ let resolveDrained;
45
+ let disposePromise;
46
+ return Object.assign(async (request, ...args)=>{
47
+ if (retired) throw new Error('Cannot dispatch through a retired server runtime.');
48
+ activeRequests += 1;
49
+ try {
50
+ return await handle(request, ...args);
51
+ } finally{
52
+ activeRequests -= 1;
53
+ if (0 === activeRequests) resolveDrained?.();
54
+ }
55
+ }, {
56
+ dispose: ()=>{
57
+ if (!disposePromise) {
58
+ retired = true;
59
+ disposePromise = Promise.resolve().then(async ()=>{
60
+ if (activeRequests > 0) await new Promise((resolve)=>{
61
+ resolveDrained = resolve;
62
+ });
63
+ await dispose();
64
+ });
65
+ }
66
+ return disposePromise;
67
+ }
68
+ });
69
+ }
41
70
  const DEFAULT_DEBOUNCE_MS = 300;
42
71
  const notReadyHandle = ()=>new Response('Dev server is starting…', {
43
72
  status: 503,
@@ -45,13 +74,21 @@ const notReadyHandle = ()=>new Response('Dev server is starting…', {
45
74
  'content-type': 'text/plain; charset=utf-8'
46
75
  }
47
76
  });
48
- var _current = /*#__PURE__*/ new WeakMap(), _build = /*#__PURE__*/ new WeakMap(), _debounceMs = /*#__PURE__*/ new WeakMap(), _onReload = /*#__PURE__*/ new WeakMap(), _onError = /*#__PURE__*/ new WeakMap(), _onReloadError = /*#__PURE__*/ new WeakMap(), _debounceTimer = /*#__PURE__*/ new WeakMap(), _running = /*#__PURE__*/ new WeakMap(), _pending = /*#__PURE__*/ new WeakMap(), _runningPromise = /*#__PURE__*/ new WeakMap(), _closed = /*#__PURE__*/ new WeakMap(), _runLoop = /*#__PURE__*/ new WeakSet(), _reportBuildError = /*#__PURE__*/ new WeakSet(), _reportReloadCallbackError = /*#__PURE__*/ new WeakSet(), _dispose = /*#__PURE__*/ new WeakSet();
77
+ var _current = /*#__PURE__*/ new WeakMap(), _build = /*#__PURE__*/ new WeakMap(), _debounceMs = /*#__PURE__*/ new WeakMap(), _onReload = /*#__PURE__*/ new WeakMap(), _onError = /*#__PURE__*/ new WeakMap(), _onReloadError = /*#__PURE__*/ new WeakMap(), _debounceTimer = /*#__PURE__*/ new WeakMap(), _running = /*#__PURE__*/ new WeakMap(), _pending = /*#__PURE__*/ new WeakMap(), _runningPromise = /*#__PURE__*/ new WeakMap(), _closed = /*#__PURE__*/ new WeakMap(), _held = /*#__PURE__*/ new WeakMap(), _holding = /*#__PURE__*/ new WeakMap(), _released = /*#__PURE__*/ new WeakSet(), _runLoop = /*#__PURE__*/ new WeakSet(), _reportBuildError = /*#__PURE__*/ new WeakSet(), _reportReloadCallbackError = /*#__PURE__*/ new WeakSet(), _dispose = /*#__PURE__*/ new WeakSet();
49
78
  class ReloadManager {
50
79
  setHandle(handle) {
51
80
  _class_private_field_set(this, _current, handle);
52
81
  }
53
82
  get handle() {
54
- return (request, ...args)=>_class_private_field_get(this, _current).call(this, request, ...args);
83
+ return (request, ...args)=>0 === _class_private_field_get(this, _holding) ? _class_private_field_get(this, _current).call(this, request, ...args) : _class_private_method_get(this, _released, released).call(this).then(()=>_class_private_field_get(this, _current).call(this, request, ...args));
84
+ }
85
+ hold(task) {
86
+ _class_private_field_set(this, _holding, _class_private_field_get(this, _holding) + 1);
87
+ const run = _class_private_field_get(this, _held).then(task).finally(()=>{
88
+ _class_private_field_set(this, _holding, _class_private_field_get(this, _holding) - 1);
89
+ });
90
+ _class_private_field_set(this, _held, run.catch(()=>{}));
91
+ return run;
55
92
  }
56
93
  get currentHandle() {
57
94
  return _class_private_field_get(this, _current);
@@ -90,9 +127,11 @@ class ReloadManager {
90
127
  clearTimeout(_class_private_field_get(this, _debounceTimer));
91
128
  _class_private_field_set(this, _debounceTimer, null);
92
129
  }
93
- _class_private_method_get(this, _dispose, dispose).call(this, _class_private_field_get(this, _current));
130
+ const current = _class_private_field_get(this, _current);
131
+ _class_private_method_get(this, _released, released).call(this).then(()=>_class_private_method_get(this, _dispose, reloadManager_dispose).call(this, current));
94
132
  }
95
133
  constructor(options){
134
+ _class_private_method_init(this, _released);
96
135
  _class_private_method_init(this, _runLoop);
97
136
  _class_private_method_init(this, _reportBuildError);
98
137
  _class_private_method_init(this, _reportReloadCallbackError);
@@ -141,11 +180,21 @@ class ReloadManager {
141
180
  writable: true,
142
181
  value: void 0
143
182
  });
183
+ _class_private_field_init(this, _held, {
184
+ writable: true,
185
+ value: void 0
186
+ });
187
+ _class_private_field_init(this, _holding, {
188
+ writable: true,
189
+ value: void 0
190
+ });
144
191
  _class_private_field_set(this, _debounceTimer, null);
145
192
  _class_private_field_set(this, _running, false);
146
193
  _class_private_field_set(this, _pending, false);
147
194
  _class_private_field_set(this, _runningPromise, null);
148
195
  _class_private_field_set(this, _closed, false);
196
+ _class_private_field_set(this, _held, Promise.resolve());
197
+ _class_private_field_set(this, _holding, 0);
149
198
  _class_private_field_set(this, _current, options.initialHandle ?? notReadyHandle);
150
199
  _class_private_field_set(this, _build, options.build);
151
200
  _class_private_field_set(this, _debounceMs, options.debounceMs ?? DEFAULT_DEBOUNCE_MS);
@@ -154,6 +203,9 @@ class ReloadManager {
154
203
  _class_private_field_set(this, _onReloadError, options.onReloadError);
155
204
  }
156
205
  }
206
+ async function released() {
207
+ while(_class_private_field_get(this, _holding) > 0)await _class_private_field_get(this, _held);
208
+ }
157
209
  async function runLoop() {
158
210
  var _this, _this1;
159
211
  do {
@@ -165,15 +217,19 @@ async function runLoop() {
165
217
  _class_private_method_get(this, _reportBuildError, reportBuildError).call(this, error);
166
218
  continue;
167
219
  }
168
- if (_class_private_field_get(this, _closed)) return void await _class_private_method_get(this, _dispose, dispose).call(this, next);
220
+ await _class_private_method_get(this, _released, released).call(this);
221
+ if (_class_private_field_get(this, _closed)) return void await _class_private_method_get(this, _dispose, reloadManager_dispose).call(this, next);
169
222
  const previous = _class_private_field_get(this, _current);
170
223
  _class_private_field_set(this, _current, next);
171
224
  try {
172
- null == (_this = _class_private_field_get(_this1 = this, _onReload)) || _this.call(_this1, next);
173
- } catch (callbackError) {
174
- _class_private_method_get(this, _reportReloadCallbackError, reportReloadCallbackError).call(this, callbackError);
225
+ try {
226
+ null == (_this = _class_private_field_get(_this1 = this, _onReload)) || _this.call(_this1, next);
227
+ } catch (callbackError) {
228
+ _class_private_method_get(this, _reportReloadCallbackError, reportReloadCallbackError).call(this, callbackError);
229
+ }
230
+ } finally{
231
+ await _class_private_method_get(this, _dispose, reloadManager_dispose).call(this, previous);
175
232
  }
176
- await _class_private_method_get(this, _dispose, dispose).call(this, previous);
177
233
  }while (_class_private_field_get(this, _pending) && !_class_private_field_get(this, _closed))
178
234
  }
179
235
  function reportBuildError(error) {
@@ -184,7 +240,7 @@ function reportReloadCallbackError(error) {
184
240
  if (_class_private_field_get(this, _onReloadError)) _class_private_field_get(this, _onReloadError).call(this, error);
185
241
  else logger.warn(`[dev-server] onReload callback failed after a successful swap (handle is already active):\n${error instanceof Error ? error.stack ?? error.message : error}`);
186
242
  }
187
- async function dispose(handle) {
243
+ async function reloadManager_dispose(handle) {
188
244
  try {
189
245
  await handle.dispose?.();
190
246
  } catch (error) {
@@ -194,4 +250,4 @@ async function dispose(handle) {
194
250
  function createReloadManager(options) {
195
251
  return new ReloadManager(options);
196
252
  }
197
- export { ReloadManager, createReloadManager };
253
+ export { ReloadManager, createDrainingHandle, createReloadManager };
@@ -26,34 +26,28 @@ class DependencyTree {
26
26
  for (const treeNode of this.tree.values()){
27
27
  const { parent } = treeNode.module;
28
28
  const { children } = treeNode.module;
29
- if (parent && !this.shouldIgnore(parent.filename)) {
29
+ if (parent) {
30
30
  const parentTreeNode = this.tree.get(parent.filename);
31
31
  if (parentTreeNode) treeNode.parent.add(parentTreeNode);
32
32
  }
33
33
  children?.forEach((child)=>{
34
- if (!this.shouldIgnore(child.filename)) {
35
- const childTreeNode = this.tree.get(child.filename);
36
- if (childTreeNode) {
37
- treeNode.children.add(childTreeNode);
38
- childTreeNode.parent.add(treeNode);
39
- }
34
+ const childTreeNode = this.tree.get(child.filename);
35
+ if (childTreeNode) {
36
+ treeNode.children.add(childTreeNode);
37
+ childTreeNode.parent.add(treeNode);
40
38
  }
41
39
  });
42
40
  }
43
41
  }
44
42
  shouldIgnore(path) {
45
43
  const matchPath = path && node_path.isAbsolute(path) ? node_path.relative(process.cwd(), path) : path;
46
- return !matchPath || Boolean(this.ignore.find((rule)=>__rspack_external_minimatch.match([
47
- matchPath
48
- ], rule, {
49
- dot: true
50
- }).length > 0));
44
+ return !matchPath || this.ignore.some((rule)=>rule.match(matchPath));
51
45
  }
52
46
  constructor(){
53
47
  this.tree = new Map();
54
- this.ignore = [
55
- ...defaultIgnores
56
- ];
48
+ this.ignore = defaultIgnores.map((rule)=>new __rspack_external_minimatch.Minimatch(rule, {
49
+ dot: true
50
+ }));
57
51
  }
58
52
  }
59
53
  export { DependencyTree, defaultIgnores };
@@ -4,7 +4,7 @@ import { DependencyTree } from "./dependencyTree.mjs";
4
4
  import { StatsCache } from "./statsCache.mjs";
5
5
  const defaultWatchOptions = {
6
6
  ignoreInitial: true,
7
- ignored: /api\/typings\/.*/
7
+ ignored: /api\/typings\/.*|(?:^|[/\\])node_modules(?:[/\\]|$)/
8
8
  };
9
9
  const getWatchedFiles = (watcher)=>{
10
10
  const watched = watcher.getWatched();
package/dist/esm/dev.mjs CHANGED
@@ -48,7 +48,7 @@ const devRuntimeMiddlewarePlugin = (options, compiler)=>({
48
48
  });
49
49
  }
50
50
  });
51
- function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, onFileChange, onClose, nodeServer }) {
51
+ function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, holdRequests, onFileChange, onClose, nodeServer }) {
52
52
  const { close, connectWebSocket } = builderDevServer || {};
53
53
  const closeCb = [];
54
54
  close && closeCb.push(close);
@@ -58,10 +58,10 @@ function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, build
58
58
  builder?.onDevCompileDone(({ stats })=>{
59
59
  if ('server' !== stats.toJson({
60
60
  all: false
61
- }).name) {
61
+ }).name) holdRequests(async ()=>{
62
62
  const runtimeServer = getRuntimeServer();
63
- if (runtimeServer) onRepack(distDir, runtimeServer.hooks);
64
- }
63
+ if (runtimeServer) await onRepack(distDir, runtimeServer.hooks);
64
+ }).catch((error)=>logger.error(error));
65
65
  });
66
66
  const { watchOptions } = config.server;
67
67
  const mockDir = config.dev?.mockDir;
@@ -83,7 +83,7 @@ async function getMockMiddleware(pwd, mockDir) {
83
83
  if (matchedMockAPI) {
84
84
  const { handler } = matchedMockAPI;
85
85
  if ('function' == typeof handler) return await connectMockMid2HonoMid(handler)(c, next);
86
- return c.json(handler);
86
+ else return c.json(handler);
87
87
  }
88
88
  return next();
89
89
  };
@@ -4,13 +4,16 @@ const cleanSSRCache = (distDir)=>{
4
4
  if (key.startsWith(distDir)) delete require.cache[key];
5
5
  });
6
6
  };
7
- const onRepack = (distDir, hooks)=>{
8
- cleanSSRCache(distDir);
9
- fileReader.reset();
10
- hooks.onReset.call({
11
- event: {
12
- type: 'repack'
13
- }
14
- });
7
+ const onRepack = async (distDir, hooks)=>{
8
+ try {
9
+ await hooks.onReset.call({
10
+ event: {
11
+ type: 'repack'
12
+ }
13
+ });
14
+ } finally{
15
+ cleanSSRCache(distDir);
16
+ fileReader.reset();
17
+ }
15
18
  };
16
19
  export { onRepack };
@@ -2,10 +2,9 @@ import "node:module";
2
2
  import node_path from "node:path";
3
3
  import { createServerBase } from "@modern-js/server-core";
4
4
  import { createNodeServer, loadServerRuntimeConfig } from "@modern-js/server-core/node";
5
- import { initializeDisposableServerRuntime } from "@modern-js/server-runtime-extensions/runtime-lifecycle";
6
5
  import { logger } from "@modern-js/utils";
7
6
  import { devRuntimeMiddlewarePlugin, setupDevInfra } from "./dev.mjs";
8
- import { createReloadManager } from "./dev-tools/reloadManager.mjs";
7
+ import { createDrainingHandle, createReloadManager } from "./dev-tools/reloadManager.mjs";
9
8
  import { createRuntimeServerOptions } from "./dev-tools/runtimeOptions.mjs";
10
9
  import { getDevAssetPrefix, getDevOptions } from "./helpers/index.mjs";
11
10
  async function createDevServer(options, applyPlugins) {
@@ -57,12 +56,17 @@ async function createDevServer(options, applyPlugins) {
57
56
  builderDevServer
58
57
  }, compiler)
59
58
  ]);
60
- const handle = await initializeDisposableServerRuntime(runtimeServer, runtimeServer.handle, async ()=>{
59
+ try {
61
60
  await applyPlugins(runtimeServer, runtimeOptions, nodeServer);
62
61
  await runtimeServer.init();
63
- });
62
+ } catch (error) {
63
+ await runtimeServer.dispose().catch((disposeError)=>{
64
+ logger.error(disposeError);
65
+ });
66
+ throw error;
67
+ }
64
68
  nextRuntimeServer = runtimeServer;
65
- return handle;
69
+ return createDrainingHandle(runtimeServer.handle, ()=>runtimeServer.dispose());
66
70
  };
67
71
  const pendingReloadFiles = new Set();
68
72
  const reloadManager = createReloadManager({
@@ -81,8 +85,18 @@ async function createDevServer(options, applyPlugins) {
81
85
  const httpsOptions = await genHttpsOptions(devHttpsOption, pwd);
82
86
  nodeServer = await createNodeServer(reloadManager.handle, httpsOptions, isHttp2);
83
87
  } else nodeServer = await createNodeServer(reloadManager.handle);
84
- reloadManager.setHandle(await buildRuntimeServer());
85
- currentRuntimeServer = nextRuntimeServer;
88
+ try {
89
+ reloadManager.setHandle(await buildRuntimeServer());
90
+ currentRuntimeServer = nextRuntimeServer;
91
+ } catch (error) {
92
+ reloadManager.close();
93
+ const cleanup = await Promise.allSettled([
94
+ Promise.resolve().then(()=>builderDevServer?.close()),
95
+ Promise.resolve().then(()=>nodeServer.close())
96
+ ]);
97
+ for (const result of cleanup)if ('rejected' === result.status) logger.error(result.reason);
98
+ throw error;
99
+ }
86
100
  setupDevInfra({
87
101
  config,
88
102
  pwd,
@@ -94,6 +108,7 @@ async function createDevServer(options, applyPlugins) {
94
108
  compiler,
95
109
  nodeServer,
96
110
  getRuntimeServer: ()=>currentRuntimeServer,
111
+ holdRequests: (task)=>reloadManager.hold(task),
97
112
  onFileChange: (filepath)=>{
98
113
  pendingReloadFiles.add(node_path.relative(pwd, filepath));
99
114
  reloadManager.schedule();
@@ -39,6 +39,35 @@ function _class_private_method_init(obj, privateSet) {
39
39
  _check_private_redeclaration(obj, privateSet);
40
40
  privateSet.add(obj);
41
41
  }
42
+ function createDrainingHandle(handle, dispose) {
43
+ let activeRequests = 0;
44
+ let retired = false;
45
+ let resolveDrained;
46
+ let disposePromise;
47
+ return Object.assign(async (request, ...args)=>{
48
+ if (retired) throw new Error('Cannot dispatch through a retired server runtime.');
49
+ activeRequests += 1;
50
+ try {
51
+ return await handle(request, ...args);
52
+ } finally{
53
+ activeRequests -= 1;
54
+ if (0 === activeRequests) resolveDrained?.();
55
+ }
56
+ }, {
57
+ dispose: ()=>{
58
+ if (!disposePromise) {
59
+ retired = true;
60
+ disposePromise = Promise.resolve().then(async ()=>{
61
+ if (activeRequests > 0) await new Promise((resolve)=>{
62
+ resolveDrained = resolve;
63
+ });
64
+ await dispose();
65
+ });
66
+ }
67
+ return disposePromise;
68
+ }
69
+ });
70
+ }
42
71
  const DEFAULT_DEBOUNCE_MS = 300;
43
72
  const notReadyHandle = ()=>new Response('Dev server is starting…', {
44
73
  status: 503,
@@ -46,13 +75,21 @@ const notReadyHandle = ()=>new Response('Dev server is starting…', {
46
75
  'content-type': 'text/plain; charset=utf-8'
47
76
  }
48
77
  });
49
- var _current = /*#__PURE__*/ new WeakMap(), _build = /*#__PURE__*/ new WeakMap(), _debounceMs = /*#__PURE__*/ new WeakMap(), _onReload = /*#__PURE__*/ new WeakMap(), _onError = /*#__PURE__*/ new WeakMap(), _onReloadError = /*#__PURE__*/ new WeakMap(), _debounceTimer = /*#__PURE__*/ new WeakMap(), _running = /*#__PURE__*/ new WeakMap(), _pending = /*#__PURE__*/ new WeakMap(), _runningPromise = /*#__PURE__*/ new WeakMap(), _closed = /*#__PURE__*/ new WeakMap(), _runLoop = /*#__PURE__*/ new WeakSet(), _reportBuildError = /*#__PURE__*/ new WeakSet(), _reportReloadCallbackError = /*#__PURE__*/ new WeakSet(), _dispose = /*#__PURE__*/ new WeakSet();
78
+ var _current = /*#__PURE__*/ new WeakMap(), _build = /*#__PURE__*/ new WeakMap(), _debounceMs = /*#__PURE__*/ new WeakMap(), _onReload = /*#__PURE__*/ new WeakMap(), _onError = /*#__PURE__*/ new WeakMap(), _onReloadError = /*#__PURE__*/ new WeakMap(), _debounceTimer = /*#__PURE__*/ new WeakMap(), _running = /*#__PURE__*/ new WeakMap(), _pending = /*#__PURE__*/ new WeakMap(), _runningPromise = /*#__PURE__*/ new WeakMap(), _closed = /*#__PURE__*/ new WeakMap(), _held = /*#__PURE__*/ new WeakMap(), _holding = /*#__PURE__*/ new WeakMap(), _released = /*#__PURE__*/ new WeakSet(), _runLoop = /*#__PURE__*/ new WeakSet(), _reportBuildError = /*#__PURE__*/ new WeakSet(), _reportReloadCallbackError = /*#__PURE__*/ new WeakSet(), _dispose = /*#__PURE__*/ new WeakSet();
50
79
  class ReloadManager {
51
80
  setHandle(handle) {
52
81
  _class_private_field_set(this, _current, handle);
53
82
  }
54
83
  get handle() {
55
- return (request, ...args)=>_class_private_field_get(this, _current).call(this, request, ...args);
84
+ return (request, ...args)=>0 === _class_private_field_get(this, _holding) ? _class_private_field_get(this, _current).call(this, request, ...args) : _class_private_method_get(this, _released, released).call(this).then(()=>_class_private_field_get(this, _current).call(this, request, ...args));
85
+ }
86
+ hold(task) {
87
+ _class_private_field_set(this, _holding, _class_private_field_get(this, _holding) + 1);
88
+ const run = _class_private_field_get(this, _held).then(task).finally(()=>{
89
+ _class_private_field_set(this, _holding, _class_private_field_get(this, _holding) - 1);
90
+ });
91
+ _class_private_field_set(this, _held, run.catch(()=>{}));
92
+ return run;
56
93
  }
57
94
  get currentHandle() {
58
95
  return _class_private_field_get(this, _current);
@@ -91,9 +128,11 @@ class ReloadManager {
91
128
  clearTimeout(_class_private_field_get(this, _debounceTimer));
92
129
  _class_private_field_set(this, _debounceTimer, null);
93
130
  }
94
- _class_private_method_get(this, _dispose, dispose).call(this, _class_private_field_get(this, _current));
131
+ const current = _class_private_field_get(this, _current);
132
+ _class_private_method_get(this, _released, released).call(this).then(()=>_class_private_method_get(this, _dispose, reloadManager_dispose).call(this, current));
95
133
  }
96
134
  constructor(options){
135
+ _class_private_method_init(this, _released);
97
136
  _class_private_method_init(this, _runLoop);
98
137
  _class_private_method_init(this, _reportBuildError);
99
138
  _class_private_method_init(this, _reportReloadCallbackError);
@@ -142,11 +181,21 @@ class ReloadManager {
142
181
  writable: true,
143
182
  value: void 0
144
183
  });
184
+ _class_private_field_init(this, _held, {
185
+ writable: true,
186
+ value: void 0
187
+ });
188
+ _class_private_field_init(this, _holding, {
189
+ writable: true,
190
+ value: void 0
191
+ });
145
192
  _class_private_field_set(this, _debounceTimer, null);
146
193
  _class_private_field_set(this, _running, false);
147
194
  _class_private_field_set(this, _pending, false);
148
195
  _class_private_field_set(this, _runningPromise, null);
149
196
  _class_private_field_set(this, _closed, false);
197
+ _class_private_field_set(this, _held, Promise.resolve());
198
+ _class_private_field_set(this, _holding, 0);
150
199
  _class_private_field_set(this, _current, options.initialHandle ?? notReadyHandle);
151
200
  _class_private_field_set(this, _build, options.build);
152
201
  _class_private_field_set(this, _debounceMs, options.debounceMs ?? DEFAULT_DEBOUNCE_MS);
@@ -155,6 +204,9 @@ class ReloadManager {
155
204
  _class_private_field_set(this, _onReloadError, options.onReloadError);
156
205
  }
157
206
  }
207
+ async function released() {
208
+ while(_class_private_field_get(this, _holding) > 0)await _class_private_field_get(this, _held);
209
+ }
158
210
  async function runLoop() {
159
211
  var _this, _this1;
160
212
  do {
@@ -166,15 +218,19 @@ async function runLoop() {
166
218
  _class_private_method_get(this, _reportBuildError, reportBuildError).call(this, error);
167
219
  continue;
168
220
  }
169
- if (_class_private_field_get(this, _closed)) return void await _class_private_method_get(this, _dispose, dispose).call(this, next);
221
+ await _class_private_method_get(this, _released, released).call(this);
222
+ if (_class_private_field_get(this, _closed)) return void await _class_private_method_get(this, _dispose, reloadManager_dispose).call(this, next);
170
223
  const previous = _class_private_field_get(this, _current);
171
224
  _class_private_field_set(this, _current, next);
172
225
  try {
173
- null == (_this = _class_private_field_get(_this1 = this, _onReload)) || _this.call(_this1, next);
174
- } catch (callbackError) {
175
- _class_private_method_get(this, _reportReloadCallbackError, reportReloadCallbackError).call(this, callbackError);
226
+ try {
227
+ null == (_this = _class_private_field_get(_this1 = this, _onReload)) || _this.call(_this1, next);
228
+ } catch (callbackError) {
229
+ _class_private_method_get(this, _reportReloadCallbackError, reportReloadCallbackError).call(this, callbackError);
230
+ }
231
+ } finally{
232
+ await _class_private_method_get(this, _dispose, reloadManager_dispose).call(this, previous);
176
233
  }
177
- await _class_private_method_get(this, _dispose, dispose).call(this, previous);
178
234
  }while (_class_private_field_get(this, _pending) && !_class_private_field_get(this, _closed));
179
235
  }
180
236
  function reportBuildError(error) {
@@ -185,7 +241,7 @@ function reportReloadCallbackError(error) {
185
241
  if (_class_private_field_get(this, _onReloadError)) _class_private_field_get(this, _onReloadError).call(this, error);
186
242
  else logger.warn(`[dev-server] onReload callback failed after a successful swap (handle is already active):\n${error instanceof Error ? error.stack ?? error.message : error}`);
187
243
  }
188
- async function dispose(handle) {
244
+ async function reloadManager_dispose(handle) {
189
245
  try {
190
246
  await handle.dispose?.();
191
247
  } catch (error) {
@@ -195,4 +251,4 @@ async function dispose(handle) {
195
251
  function createReloadManager(options) {
196
252
  return new ReloadManager(options);
197
253
  }
198
- export { ReloadManager, createReloadManager };
254
+ export { ReloadManager, createDrainingHandle, createReloadManager };
@@ -27,34 +27,28 @@ class DependencyTree {
27
27
  for (const treeNode of this.tree.values()){
28
28
  const { parent } = treeNode.module;
29
29
  const { children } = treeNode.module;
30
- if (parent && !this.shouldIgnore(parent.filename)) {
30
+ if (parent) {
31
31
  const parentTreeNode = this.tree.get(parent.filename);
32
32
  if (parentTreeNode) treeNode.parent.add(parentTreeNode);
33
33
  }
34
34
  children?.forEach((child)=>{
35
- if (!this.shouldIgnore(child.filename)) {
36
- const childTreeNode = this.tree.get(child.filename);
37
- if (childTreeNode) {
38
- treeNode.children.add(childTreeNode);
39
- childTreeNode.parent.add(treeNode);
40
- }
35
+ const childTreeNode = this.tree.get(child.filename);
36
+ if (childTreeNode) {
37
+ treeNode.children.add(childTreeNode);
38
+ childTreeNode.parent.add(treeNode);
41
39
  }
42
40
  });
43
41
  }
44
42
  }
45
43
  shouldIgnore(path) {
46
44
  const matchPath = path && node_path.isAbsolute(path) ? node_path.relative(process.cwd(), path) : path;
47
- return !matchPath || Boolean(this.ignore.find((rule)=>__rspack_external_minimatch.match([
48
- matchPath
49
- ], rule, {
50
- dot: true
51
- }).length > 0));
45
+ return !matchPath || this.ignore.some((rule)=>rule.match(matchPath));
52
46
  }
53
47
  constructor(){
54
48
  this.tree = new Map();
55
- this.ignore = [
56
- ...defaultIgnores
57
- ];
49
+ this.ignore = defaultIgnores.map((rule)=>new __rspack_external_minimatch.Minimatch(rule, {
50
+ dot: true
51
+ }));
58
52
  }
59
53
  }
60
54
  export { DependencyTree, defaultIgnores };
@@ -6,7 +6,7 @@ import { DependencyTree } from "./dependencyTree.mjs";
6
6
  import { StatsCache } from "./statsCache.mjs";
7
7
  const defaultWatchOptions = {
8
8
  ignoreInitial: true,
9
- ignored: /api\/typings\/.*/
9
+ ignored: /api\/typings\/.*|(?:^|[/\\])node_modules(?:[/\\]|$)/
10
10
  };
11
11
  const getWatchedFiles = (watcher)=>{
12
12
  const watched = watcher.getWatched();
@@ -49,7 +49,7 @@ const devRuntimeMiddlewarePlugin = (options, compiler)=>({
49
49
  });
50
50
  }
51
51
  });
52
- function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, onFileChange, onClose, nodeServer }) {
52
+ function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, holdRequests, onFileChange, onClose, nodeServer }) {
53
53
  const { close, connectWebSocket } = builderDevServer || {};
54
54
  const closeCb = [];
55
55
  close && closeCb.push(close);
@@ -59,10 +59,10 @@ function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, build
59
59
  builder?.onDevCompileDone(({ stats })=>{
60
60
  if ('server' !== stats.toJson({
61
61
  all: false
62
- }).name) {
62
+ }).name) holdRequests(async ()=>{
63
63
  const runtimeServer = getRuntimeServer();
64
- if (runtimeServer) onRepack(distDir, runtimeServer.hooks);
65
- }
64
+ if (runtimeServer) await onRepack(distDir, runtimeServer.hooks);
65
+ }).catch((error)=>logger.error(error));
66
66
  });
67
67
  const { watchOptions } = config.server;
68
68
  const mockDir = config.dev?.mockDir;
@@ -84,7 +84,7 @@ async function getMockMiddleware(pwd, mockDir) {
84
84
  if (matchedMockAPI) {
85
85
  const { handler } = matchedMockAPI;
86
86
  if ('function' == typeof handler) return await connectMockMid2HonoMid(handler)(c, next);
87
- return c.json(handler);
87
+ else return c.json(handler);
88
88
  }
89
89
  return next();
90
90
  };
@@ -6,13 +6,16 @@ const cleanSSRCache = (distDir)=>{
6
6
  if (key.startsWith(distDir)) delete require.cache[key];
7
7
  });
8
8
  };
9
- const onRepack = (distDir, hooks)=>{
10
- cleanSSRCache(distDir);
11
- fileReader.reset();
12
- hooks.onReset.call({
13
- event: {
14
- type: 'repack'
15
- }
16
- });
9
+ const onRepack = async (distDir, hooks)=>{
10
+ try {
11
+ await hooks.onReset.call({
12
+ event: {
13
+ type: 'repack'
14
+ }
15
+ });
16
+ } finally{
17
+ cleanSSRCache(distDir);
18
+ fileReader.reset();
19
+ }
17
20
  };
18
21
  export { onRepack };
@@ -5,6 +5,13 @@
5
5
  export type ReloadableHandle = ((request: Request, ...args: any[]) => Response | Promise<Response>) & {
6
6
  dispose?: () => void | Promise<void>;
7
7
  };
8
+ /**
9
+ * Retire a request handle before waiting for its active handler promises.
10
+ * This preserves handler completion semantics; response streams are not drained.
11
+ */
12
+ export declare function createDrainingHandle(handle: ReloadableHandle, dispose: () => void | Promise<void>): ReloadableHandle & {
13
+ dispose: () => Promise<void>;
14
+ };
8
15
  export interface ReloadManagerOptions {
9
16
  /**
10
17
  * The handle used before the first successful build. Optional: when omitted
@@ -64,6 +71,15 @@ export declare class ReloadManager {
64
71
  * be recreated on reload.
65
72
  */
66
73
  get handle(): ReloadableHandle;
74
+ /**
75
+ * Run `task` after the previously held tasks, and make requests arriving
76
+ * through `handle` wait until it settles. A reload waits for it before it
77
+ * swaps the runtime. Requests already dispatched are not waited for: an SSR
78
+ * loader fetching its own dev server would deadlock. The task itself must
79
+ * not await a request to this handle, which waits for the task.
80
+ * Returns the task's own result, rejection included.
81
+ */
82
+ hold(task: () => Promise<void>): Promise<void>;
67
83
  /** The currently active resolved handle (introspection / tests). */
68
84
  get currentHandle(): ReloadableHandle;
69
85
  /** Whether a reload is currently running (introspection / tests). */
@@ -35,6 +35,11 @@ export interface DevInfraOptions {
35
35
  nodeServer?: NodeServer | NodeHttpsServer | Http2SecureServer;
36
36
  /** Accessor for the currently-active runtime ServerBase (a mutable ref). */
37
37
  getRuntimeServer: () => ServerBase | undefined;
38
+ /**
39
+ * Run a repack task while new requests wait for it (`ReloadManager.hold`),
40
+ * so no request re-requires the server bundle mid-reset.
41
+ */
42
+ holdRequests: (task: () => Promise<void>) => Promise<void>;
38
43
  /**
39
44
  * Triggered when a watched user server file changes (require cache already
40
45
  * busted). Wired to the runtime reload scheduler.
@@ -64,5 +69,5 @@ export interface DevInfra {
64
69
  * runtime, so a later phase can swap the trigger to the reload scheduler
65
70
  * without leaking a stale closure to a dead runtime.
66
71
  */
67
- export declare function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, onFileChange, onClose, nodeServer, }: DevInfraOptions): DevInfra;
72
+ export declare function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, holdRequests, onFileChange, onClose, nodeServer, }: DevInfraOptions): DevInfra;
68
73
  export {};
@@ -1,2 +1,17 @@
1
1
  import type { ServerPluginHooks } from '@modern-js/server-core';
2
- export declare const onRepack: (distDir: string, hooks: ServerPluginHooks) => void;
2
+ /**
3
+ * Reset the dev server after the server bundle is rebuilt.
4
+ *
5
+ * Runtime state a rebuilt bundle keeps outside the require cache belongs to
6
+ * the plugin that owns it and is reset by that plugin's `onReset` handler:
7
+ * `@module-federation/modern-js-v3/server` resets the Module Federation
8
+ * runtime on `globalThis` there (module-federation/core#5152).
9
+ *
10
+ * Contract: the `onReset({ event: { type: 'repack' } })` handlers run in
11
+ * registration order and are awaited before the previous generation is purged.
12
+ * The caller holds new requests until this promise settles, so no request
13
+ * re-requires the bundle while a handler is still running. As with every async
14
+ * server hook, a rejecting handler skips the handlers after it; the generation
15
+ * is still purged and the promise rejects with that error.
16
+ */
17
+ export declare const onRepack: (distDir: string, hooks: ServerPluginHooks) => Promise<void>;
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.9.0-ultramodern.2",
20
+ "version": "3.9.0-ultramodern.21",
21
21
  "types": "./dist/types/index.d.ts",
22
22
  "main": "./dist/cjs/index.js",
23
23
  "exports": {
@@ -38,12 +38,11 @@
38
38
  }
39
39
  },
40
40
  "dependencies": {
41
- "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.0-ultramodern.2",
42
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.2",
43
- "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.2",
44
- "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.9.0-ultramodern.2",
45
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.2",
46
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.2",
41
+ "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.0-ultramodern.21",
42
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.21",
43
+ "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.9.0-ultramodern.21",
44
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.21",
45
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.21",
47
46
  "@swc/helpers": "^0.5.23",
48
47
  "connect-history-api-fallback": "^2.0.0",
49
48
  "http-compression": "1.1.3",
@@ -52,11 +51,12 @@
52
51
  "ws": "^8.21.3"
53
52
  },
54
53
  "devDependencies": {
55
- "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.0-ultramodern.2",
56
- "@rslib/core": "1.0.0",
54
+ "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.0-ultramodern.21",
55
+ "@module-federation/runtime": "2.9.2",
56
+ "@rslib/core": "1.0.2",
57
57
  "@scripts/rstest-config": "2.66.0",
58
58
  "@types/connect-history-api-fallback": "^1.5.4",
59
- "@types/node": "^26.4.1",
59
+ "@types/node": "^26.6.2",
60
60
  "@types/ws": "^8.18.1",
61
61
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
62
62
  "node-mocks-http": "^1.18.1",