@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.
- package/dist/cjs/createDevServer.js +21 -6
- package/dist/cjs/dev-tools/reloadManager.js +68 -9
- package/dist/cjs/dev-tools/watcher/dependencyTree.js +9 -15
- package/dist/cjs/dev-tools/watcher/index.js +1 -1
- package/dist/cjs/dev.js +4 -4
- package/dist/cjs/helpers/mock.js +1 -1
- package/dist/cjs/helpers/repack.js +11 -8
- package/dist/esm/createDevServer.mjs +22 -7
- package/dist/esm/dev-tools/reloadManager.mjs +66 -10
- package/dist/esm/dev-tools/watcher/dependencyTree.mjs +9 -15
- package/dist/esm/dev-tools/watcher/index.mjs +1 -1
- package/dist/esm/dev.mjs +4 -4
- package/dist/esm/helpers/mock.mjs +1 -1
- package/dist/esm/helpers/repack.mjs +11 -8
- package/dist/esm-node/createDevServer.mjs +22 -7
- package/dist/esm-node/dev-tools/reloadManager.mjs +66 -10
- package/dist/esm-node/dev-tools/watcher/dependencyTree.mjs +9 -15
- package/dist/esm-node/dev-tools/watcher/index.mjs +1 -1
- package/dist/esm-node/dev.mjs +4 -4
- package/dist/esm-node/helpers/mock.mjs +1 -1
- package/dist/esm-node/helpers/repack.mjs +11 -8
- package/dist/types/dev-tools/reloadManager.d.ts +16 -0
- package/dist/types/dev.d.ts +6 -1
- package/dist/types/helpers/repack.d.ts +16 -1
- package/package.json +10 -10
|
@@ -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
|
-
|
|
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
|
-
|
|
126
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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 ||
|
|
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
|
-
|
|
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;
|
package/dist/cjs/helpers/mock.js
CHANGED
|
@@ -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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
|
|
84
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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 ||
|
|
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
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
85
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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 ||
|
|
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
|
-
|
|
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();
|
package/dist/esm-node/dev.mjs
CHANGED
|
@@ -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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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). */
|
package/dist/types/dev.d.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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.
|
|
42
|
-
"@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.
|
|
43
|
-
"@modern-js/server-
|
|
44
|
-
"@modern-js/
|
|
45
|
-
"@modern-js/
|
|
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.
|
|
56
|
-
"@
|
|
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.
|
|
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",
|