@modern-js/server 3.4.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,10 @@
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 { devPlugin } from "./dev.mjs";
4
+ import { logger } from "@modern-js/utils";
5
+ import { devRuntimeMiddlewarePlugin, setupDevInfra } from "./dev.mjs";
6
+ import { createReloadManager } from "./dev-tools/reloadManager.mjs";
7
+ import { createRuntimeServerOptions } from "./dev-tools/runtimeOptions.mjs";
5
8
  import { getDevAssetPrefix, getDevOptions } from "./helpers/index.mjs";
6
9
  async function createDevServer(options, applyPlugins) {
7
10
  const { config, pwd, serverConfigPath, builder } = options;
@@ -20,33 +23,76 @@ async function createDevServer(options, applyPlugins) {
20
23
  ...options.plugins || []
21
24
  ]
22
25
  };
23
- const server = createServerBase(prodServerOptions);
24
- const devHttpsOption = 'object' == typeof dev && dev.https;
25
- const isHttp2 = !!devHttpsOption;
26
- let nodeServer;
27
- if (devHttpsOption) {
28
- const { genHttpsOptions } = await import("./dev-tools/https/index.mjs");
29
- const httpsOptions = await genHttpsOptions(devHttpsOption, pwd);
30
- nodeServer = await createNodeServer(server.handle.bind(server), httpsOptions, isHttp2);
31
- } else nodeServer = await createNodeServer(server.handle.bind(server));
32
- const promise = getDevAssetPrefix(builder);
33
26
  let compiler = null;
34
27
  builder?.onAfterCreateCompiler((context)=>{
35
28
  compiler = context.compiler;
36
29
  });
30
+ const assetPrefixPromise = getDevAssetPrefix(builder);
37
31
  const builderDevServer = await builder?.createDevServer({
38
32
  runCompile: options.runCompile
39
33
  });
40
- server.addPlugins([
41
- devPlugin({
42
- ...options,
43
- builderDevServer
44
- }, compiler)
45
- ]);
46
- const assetPrefix = await promise;
47
- if (assetPrefix) prodServerOptions.config.output.assetPrefix = assetPrefix;
48
- await applyPlugins(server, prodServerOptions, nodeServer);
49
- await server.init();
34
+ const assetPrefix = await assetPrefixPromise;
35
+ let currentRuntimeServer;
36
+ let nodeServer;
37
+ const buildRuntimeServer = async ()=>{
38
+ const freshServerConfig = await loadServerRuntimeConfig(serverConfigPath) || {};
39
+ const runtimeOptions = createRuntimeServerOptions({
40
+ ...prodServerOptions,
41
+ serverConfig: {
42
+ ...freshServerConfig,
43
+ ...options.serverConfig
44
+ },
45
+ plugins: [
46
+ ...freshServerConfig.plugins || [],
47
+ ...options.plugins || []
48
+ ]
49
+ }, assetPrefix);
50
+ const runtimeServer = createServerBase(runtimeOptions);
51
+ runtimeServer.addPlugins([
52
+ devRuntimeMiddlewarePlugin({
53
+ ...options,
54
+ builderDevServer
55
+ }, compiler)
56
+ ]);
57
+ await applyPlugins(runtimeServer, runtimeOptions, nodeServer);
58
+ await runtimeServer.init();
59
+ currentRuntimeServer = runtimeServer;
60
+ return runtimeServer.handle;
61
+ };
62
+ const pendingReloadFiles = new Set();
63
+ const reloadManager = createReloadManager({
64
+ build: buildRuntimeServer,
65
+ onReload: ()=>{
66
+ const files = Array.from(pendingReloadFiles);
67
+ pendingReloadFiles.clear();
68
+ logger.info(files.length > 0 ? `Server runtime reloaded (${files.join(', ')})` : 'Server runtime reloaded');
69
+ }
70
+ });
71
+ const devHttpsOption = 'object' == typeof dev && dev.https;
72
+ const isHttp2 = !!devHttpsOption;
73
+ if (devHttpsOption) {
74
+ const { genHttpsOptions } = await import("./dev-tools/https/index.mjs");
75
+ const httpsOptions = await genHttpsOptions(devHttpsOption, pwd);
76
+ nodeServer = await createNodeServer(reloadManager.handle, httpsOptions, isHttp2);
77
+ } else nodeServer = await createNodeServer(reloadManager.handle);
78
+ reloadManager.setHandle(await buildRuntimeServer());
79
+ setupDevInfra({
80
+ config,
81
+ pwd,
82
+ distDir,
83
+ apiDir: options.appContext?.apiDirectory,
84
+ sharedDir: options.appContext?.sharedDirectory,
85
+ builder,
86
+ builderDevServer,
87
+ compiler,
88
+ nodeServer,
89
+ getRuntimeServer: ()=>currentRuntimeServer,
90
+ onFileChange: (filepath)=>{
91
+ pendingReloadFiles.add(node_path.relative(pwd, filepath));
92
+ reloadManager.schedule();
93
+ },
94
+ onClose: ()=>reloadManager.close()
95
+ });
50
96
  const afterListen = async ()=>{
51
97
  await builderDevServer?.afterListen();
52
98
  };
@@ -0,0 +1,185 @@
1
+ import { logger } from "@modern-js/utils";
2
+ function _check_private_redeclaration(obj, privateCollection) {
3
+ if (privateCollection.has(obj)) throw new TypeError("Cannot initialize the same private elements twice on an object");
4
+ }
5
+ function _class_apply_descriptor_get(receiver, descriptor) {
6
+ if (descriptor.get) return descriptor.get.call(receiver);
7
+ return descriptor.value;
8
+ }
9
+ function _class_apply_descriptor_set(receiver, descriptor, value) {
10
+ if (descriptor.set) descriptor.set.call(receiver, value);
11
+ else {
12
+ if (!descriptor.writable) throw new TypeError("attempted to set read only private field");
13
+ descriptor.value = value;
14
+ }
15
+ }
16
+ function _class_extract_field_descriptor(receiver, privateMap, action) {
17
+ if (!privateMap.has(receiver)) throw new TypeError("attempted to " + action + " private field on non-instance");
18
+ return privateMap.get(receiver);
19
+ }
20
+ function _class_private_field_get(receiver, privateMap) {
21
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
22
+ return _class_apply_descriptor_get(receiver, descriptor);
23
+ }
24
+ function _class_private_field_init(obj, privateMap, value) {
25
+ _check_private_redeclaration(obj, privateMap);
26
+ privateMap.set(obj, value);
27
+ }
28
+ function _class_private_field_set(receiver, privateMap, value) {
29
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
30
+ _class_apply_descriptor_set(receiver, descriptor, value);
31
+ return value;
32
+ }
33
+ function _class_private_method_get(receiver, privateSet, fn) {
34
+ if (!privateSet.has(receiver)) throw new TypeError("attempted to get private field on non-instance");
35
+ return fn;
36
+ }
37
+ function _class_private_method_init(obj, privateSet) {
38
+ _check_private_redeclaration(obj, privateSet);
39
+ privateSet.add(obj);
40
+ }
41
+ const DEFAULT_DEBOUNCE_MS = 300;
42
+ const notReadyHandle = ()=>new Response('Dev server is starting…', {
43
+ status: 503,
44
+ headers: {
45
+ 'content-type': 'text/plain; charset=utf-8'
46
+ }
47
+ });
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();
49
+ class ReloadManager {
50
+ setHandle(handle) {
51
+ _class_private_field_set(this, _current, handle);
52
+ }
53
+ get handle() {
54
+ return (request, ...args)=>_class_private_field_get(this, _current).call(this, request, ...args);
55
+ }
56
+ get currentHandle() {
57
+ return _class_private_field_get(this, _current);
58
+ }
59
+ get isReloading() {
60
+ return _class_private_field_get(this, _running);
61
+ }
62
+ schedule() {
63
+ if (_class_private_field_get(this, _closed)) return;
64
+ if (_class_private_field_get(this, _debounceTimer)) clearTimeout(_class_private_field_get(this, _debounceTimer));
65
+ _class_private_field_set(this, _debounceTimer, setTimeout(()=>{
66
+ _class_private_field_set(this, _debounceTimer, null);
67
+ this.reloadNow();
68
+ }, _class_private_field_get(this, _debounceMs)));
69
+ }
70
+ async reloadNow() {
71
+ if (_class_private_field_get(this, _closed)) return;
72
+ if (_class_private_field_get(this, _running)) {
73
+ _class_private_field_set(this, _pending, true);
74
+ return _class_private_field_get(this, _runningPromise) ?? Promise.resolve();
75
+ }
76
+ _class_private_field_set(this, _running, true);
77
+ _class_private_field_set(this, _runningPromise, _class_private_method_get(this, _runLoop, runLoop).call(this));
78
+ try {
79
+ await _class_private_field_get(this, _runningPromise);
80
+ } finally{
81
+ _class_private_field_set(this, _running, false);
82
+ _class_private_field_set(this, _runningPromise, null);
83
+ }
84
+ }
85
+ close() {
86
+ _class_private_field_set(this, _closed, true);
87
+ _class_private_field_set(this, _pending, false);
88
+ if (_class_private_field_get(this, _debounceTimer)) {
89
+ clearTimeout(_class_private_field_get(this, _debounceTimer));
90
+ _class_private_field_set(this, _debounceTimer, null);
91
+ }
92
+ }
93
+ constructor(options){
94
+ _class_private_method_init(this, _runLoop);
95
+ _class_private_method_init(this, _reportBuildError);
96
+ _class_private_method_init(this, _reportReloadCallbackError);
97
+ _class_private_field_init(this, _current, {
98
+ writable: true,
99
+ value: void 0
100
+ });
101
+ _class_private_field_init(this, _build, {
102
+ writable: true,
103
+ value: void 0
104
+ });
105
+ _class_private_field_init(this, _debounceMs, {
106
+ writable: true,
107
+ value: void 0
108
+ });
109
+ _class_private_field_init(this, _onReload, {
110
+ writable: true,
111
+ value: void 0
112
+ });
113
+ _class_private_field_init(this, _onError, {
114
+ writable: true,
115
+ value: void 0
116
+ });
117
+ _class_private_field_init(this, _onReloadError, {
118
+ writable: true,
119
+ value: void 0
120
+ });
121
+ _class_private_field_init(this, _debounceTimer, {
122
+ writable: true,
123
+ value: void 0
124
+ });
125
+ _class_private_field_init(this, _running, {
126
+ writable: true,
127
+ value: void 0
128
+ });
129
+ _class_private_field_init(this, _pending, {
130
+ writable: true,
131
+ value: void 0
132
+ });
133
+ _class_private_field_init(this, _runningPromise, {
134
+ writable: true,
135
+ value: void 0
136
+ });
137
+ _class_private_field_init(this, _closed, {
138
+ writable: true,
139
+ value: void 0
140
+ });
141
+ _class_private_field_set(this, _debounceTimer, null);
142
+ _class_private_field_set(this, _running, false);
143
+ _class_private_field_set(this, _pending, false);
144
+ _class_private_field_set(this, _runningPromise, null);
145
+ _class_private_field_set(this, _closed, false);
146
+ _class_private_field_set(this, _current, options.initialHandle ?? notReadyHandle);
147
+ _class_private_field_set(this, _build, options.build);
148
+ _class_private_field_set(this, _debounceMs, options.debounceMs ?? DEFAULT_DEBOUNCE_MS);
149
+ _class_private_field_set(this, _onReload, options.onReload);
150
+ _class_private_field_set(this, _onError, options.onError);
151
+ _class_private_field_set(this, _onReloadError, options.onReloadError);
152
+ }
153
+ }
154
+ async function runLoop() {
155
+ var _this, _this1;
156
+ do {
157
+ _class_private_field_set(this, _pending, false);
158
+ let next;
159
+ try {
160
+ next = await _class_private_field_get(this, _build).call(this);
161
+ } catch (error) {
162
+ _class_private_method_get(this, _reportBuildError, reportBuildError).call(this, error);
163
+ continue;
164
+ }
165
+ if (_class_private_field_get(this, _closed)) return;
166
+ _class_private_field_set(this, _current, next);
167
+ try {
168
+ null == (_this = _class_private_field_get(_this1 = this, _onReload)) || _this.call(_this1, next);
169
+ } catch (callbackError) {
170
+ _class_private_method_get(this, _reportReloadCallbackError, reportReloadCallbackError).call(this, callbackError);
171
+ }
172
+ }while (_class_private_field_get(this, _pending) && !_class_private_field_get(this, _closed))
173
+ }
174
+ function reportBuildError(error) {
175
+ if (_class_private_field_get(this, _onError)) _class_private_field_get(this, _onError).call(this, error);
176
+ else logger.error(`[dev-server] runtime reload build failed, keep serving previous handle:\n${error instanceof Error ? error.stack ?? error.message : error}`);
177
+ }
178
+ function reportReloadCallbackError(error) {
179
+ if (_class_private_field_get(this, _onReloadError)) _class_private_field_get(this, _onReloadError).call(this, error);
180
+ 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}`);
181
+ }
182
+ function createReloadManager(options) {
183
+ return new ReloadManager(options);
184
+ }
185
+ export { ReloadManager, createReloadManager };
@@ -0,0 +1,35 @@
1
+ function createRuntimeServerOptions(base, assetPrefix) {
2
+ const baseConfig = base.config ?? {};
3
+ const baseOutput = baseConfig.output ?? {};
4
+ const baseServerConfig = base.serverConfig ?? {};
5
+ return {
6
+ ...base,
7
+ config: {
8
+ ...baseConfig,
9
+ output: {
10
+ ...baseOutput,
11
+ ...assetPrefix ? {
12
+ assetPrefix
13
+ } : {}
14
+ }
15
+ },
16
+ serverConfig: {
17
+ ...baseServerConfig,
18
+ middlewares: [
19
+ ...baseServerConfig.middlewares ?? []
20
+ ],
21
+ renderMiddlewares: [
22
+ ...baseServerConfig.renderMiddlewares ?? []
23
+ ],
24
+ ...baseServerConfig.plugins ? {
25
+ plugins: [
26
+ ...baseServerConfig.plugins
27
+ ]
28
+ } : {}
29
+ },
30
+ plugins: [
31
+ ...base.plugins ?? []
32
+ ]
33
+ };
34
+ }
35
+ export { createRuntimeServerOptions };
package/dist/esm/dev.mjs CHANGED
@@ -1,40 +1,16 @@
1
+ import node_path from "node:path";
2
+ import { AGGRED_DIR } from "@modern-js/server-core";
1
3
  import { connectMid2HonoMid } from "@modern-js/server-core/node";
2
- import { API_DIR, SHARED_DIR } from "@modern-js/utils";
4
+ import { API_DIR, SHARED_DIR, logger } from "@modern-js/utils";
3
5
  import { getDevOptions, getMockMiddleware, initFileReader, onRepack, startWatcher } from "./helpers/index.mjs";
4
- const devPlugin = (options, compiler)=>({
6
+ const devRuntimeMiddlewarePlugin = (options, compiler)=>({
5
7
  name: '@modern-js/plugin-dev',
6
8
  setup (api) {
7
- const { config, pwd, builder, builderDevServer } = options;
8
- const closeCb = [];
9
+ const { pwd, builderDevServer } = options;
9
10
  const dev = getDevOptions(options.dev);
10
11
  api.onPrepare(async ()=>{
11
- const { middlewares: builderMiddlewares, close, connectWebSocket } = builderDevServer || {};
12
- close && closeCb.push(close);
13
- const { middlewares, distDirectory, nodeServer, apiDirectory, sharedDirectory, serverBase } = api.getServerContext();
14
- connectWebSocket && nodeServer && connectWebSocket({
15
- server: nodeServer
16
- });
17
- const hooks = api.getHooks();
18
- builder?.onDevCompileDone(({ stats })=>{
19
- if ('server' !== stats.toJson({
20
- all: false
21
- }).name) onRepack(distDirectory, hooks);
22
- });
23
- const { watchOptions } = config.server;
24
- const watcher = startWatcher({
25
- pwd,
26
- distDir: distDirectory,
27
- apiDir: apiDirectory || API_DIR,
28
- sharedDir: sharedDirectory || SHARED_DIR,
29
- watchOptions,
30
- server: serverBase
31
- });
32
- closeCb.push(watcher.close.bind(watcher));
33
- closeCb.length > 0 && nodeServer?.on('close', ()=>{
34
- closeCb.forEach((cb)=>{
35
- cb();
36
- });
37
- });
12
+ const { middlewares: builderMiddlewares } = builderDevServer || {};
13
+ const { middlewares } = api.getServerContext();
38
14
  const before = [];
39
15
  const after = [];
40
16
  const { setupMiddlewares = [] } = dev;
@@ -74,4 +50,58 @@ const devPlugin = (options, compiler)=>({
74
50
  });
75
51
  }
76
52
  });
77
- export { devPlugin };
53
+ function setupDevInfra({ config, pwd, distDir, apiDir, sharedDir, builder, builderDevServer, getRuntimeServer, onFileChange, onClose, nodeServer }) {
54
+ const { close, connectWebSocket } = builderDevServer || {};
55
+ const closeCb = [];
56
+ close && closeCb.push(close);
57
+ connectWebSocket && nodeServer && connectWebSocket({
58
+ server: nodeServer
59
+ });
60
+ builder?.onDevCompileDone(({ stats })=>{
61
+ if ('server' !== stats.toJson({
62
+ all: false
63
+ }).name) {
64
+ const runtimeServer = getRuntimeServer();
65
+ if (runtimeServer) onRepack(distDir, runtimeServer.hooks);
66
+ }
67
+ });
68
+ const { watchOptions } = config.server;
69
+ const mockPath = node_path.normalize(node_path.join(pwd, AGGRED_DIR.mock));
70
+ const watcher = startWatcher({
71
+ pwd,
72
+ distDir,
73
+ apiDir: apiDir || API_DIR,
74
+ sharedDir: sharedDir || SHARED_DIR,
75
+ watchOptions,
76
+ onChange: (filepath, event)=>{
77
+ const runtimeServer = getRuntimeServer();
78
+ if (runtimeServer && !filepath.startsWith(mockPath)) {
79
+ const fileChangeEvent = {
80
+ type: 'file-change',
81
+ payload: [
82
+ {
83
+ filename: filepath,
84
+ event
85
+ }
86
+ ]
87
+ };
88
+ Promise.resolve(runtimeServer.hooks.onReset.call({
89
+ event: fileChangeEvent
90
+ })).catch((error)=>logger.error(error));
91
+ }
92
+ onFileChange(filepath, event);
93
+ }
94
+ });
95
+ closeCb.push(watcher.close.bind(watcher));
96
+ onClose && closeCb.push(onClose);
97
+ const close$ = ()=>{
98
+ closeCb.forEach((cb)=>{
99
+ cb();
100
+ });
101
+ };
102
+ closeCb.length > 0 && nodeServer?.on('close', close$);
103
+ return {
104
+ close: close$
105
+ };
106
+ }
107
+ export { devRuntimeMiddlewarePlugin, setupDevInfra };
@@ -1,39 +1,12 @@
1
1
  import path from "path";
2
2
  import { AGGRED_DIR } from "@modern-js/server-core";
3
- import { SERVER_BUNDLE_DIRECTORY, SERVER_DIR, logger } from "@modern-js/utils";
3
+ import { SERVER_BUNDLE_DIRECTORY, SERVER_DIR } from "@modern-js/utils";
4
4
  import dev_tools_watcher, { mergeWatchOptions } from "../dev-tools/watcher/index.mjs";
5
- import { initOrUpdateMockMiddlewares } from "./mock.mjs";
6
- import { debug } from "./utils.mjs";
7
5
  export * from "./repack.mjs";
8
6
  export * from "./devOptions.mjs";
9
7
  export * from "./fileReader.mjs";
10
8
  export * from "./mock.mjs";
11
- async function onServerChange({ pwd, filepath, event, server }) {
12
- const { mock } = AGGRED_DIR;
13
- const mockPath = path.normalize(path.join(pwd, mock));
14
- const { hooks } = server;
15
- if (filepath.startsWith(mockPath)) {
16
- await initOrUpdateMockMiddlewares(pwd);
17
- logger.info('Finish update the mock handlers');
18
- } else try {
19
- const fileChangeEvent = {
20
- type: 'file-change',
21
- payload: [
22
- {
23
- filename: filepath,
24
- event
25
- }
26
- ]
27
- };
28
- await hooks.onReset.call({
29
- event: fileChangeEvent
30
- });
31
- debug(`Finish reload server, trigger by ${filepath} ${event}`);
32
- } catch (e) {
33
- logger.error(e);
34
- }
35
- }
36
- function startWatcher({ pwd, distDir, apiDir, sharedDir, watchOptions, server }) {
9
+ function startWatcher({ pwd, distDir, apiDir, sharedDir, watchOptions, onChange }) {
37
10
  const { mock } = AGGRED_DIR;
38
11
  const defaultWatched = [
39
12
  `${mock}/**/*`,
@@ -53,12 +26,7 @@ function startWatcher({ pwd, distDir, apiDir, sharedDir, watchOptions, server })
53
26
  if (filepath.includes('-server-loaders.js')) return void delete require.cache[filepath];
54
27
  watcher.updateDepTree();
55
28
  watcher.cleanDepCache(filepath);
56
- onServerChange({
57
- pwd,
58
- filepath,
59
- event,
60
- server
61
- });
29
+ onChange(filepath, event);
62
30
  });
63
31
  return watcher;
64
32
  }
@@ -1,7 +1,7 @@
1
1
  import node_path from "node:path";
2
2
  import { AGGRED_DIR } from "@modern-js/server-core";
3
3
  import { connectMockMid2HonoMid } from "@modern-js/server-core/node";
4
- import { fs } from "@modern-js/utils";
4
+ import { compatibleRequire, fs } from "@modern-js/utils";
5
5
  import { match } from "path-to-regexp";
6
6
  let mockAPIs = [];
7
7
  let mockConfig;
@@ -34,7 +34,7 @@ const getMockModule = async (pwd)=>{
34
34
  }
35
35
  }
36
36
  if (!mockFilePath) return;
37
- const { default: mockHandlers, config } = await import(mockFilePath);
37
+ const { default: mockHandlers, config } = await compatibleRequire(mockFilePath, false);
38
38
  const enable = config?.enable;
39
39
  if (false === enable) return;
40
40
  if (!mockHandlers) throw new Error(`Mock file ${mockFilePath} parsed failed!`);
@@ -2,7 +2,10 @@ 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 { devPlugin } from "./dev.mjs";
5
+ import { logger } from "@modern-js/utils";
6
+ import { devRuntimeMiddlewarePlugin, setupDevInfra } from "./dev.mjs";
7
+ import { createReloadManager } from "./dev-tools/reloadManager.mjs";
8
+ import { createRuntimeServerOptions } from "./dev-tools/runtimeOptions.mjs";
6
9
  import { getDevAssetPrefix, getDevOptions } from "./helpers/index.mjs";
7
10
  async function createDevServer(options, applyPlugins) {
8
11
  const { config, pwd, serverConfigPath, builder } = options;
@@ -21,33 +24,76 @@ async function createDevServer(options, applyPlugins) {
21
24
  ...options.plugins || []
22
25
  ]
23
26
  };
24
- const server = createServerBase(prodServerOptions);
25
- const devHttpsOption = 'object' == typeof dev && dev.https;
26
- const isHttp2 = !!devHttpsOption;
27
- let nodeServer;
28
- if (devHttpsOption) {
29
- const { genHttpsOptions } = await import("./dev-tools/https/index.mjs");
30
- const httpsOptions = await genHttpsOptions(devHttpsOption, pwd);
31
- nodeServer = await createNodeServer(server.handle.bind(server), httpsOptions, isHttp2);
32
- } else nodeServer = await createNodeServer(server.handle.bind(server));
33
- const promise = getDevAssetPrefix(builder);
34
27
  let compiler = null;
35
28
  builder?.onAfterCreateCompiler((context)=>{
36
29
  compiler = context.compiler;
37
30
  });
31
+ const assetPrefixPromise = getDevAssetPrefix(builder);
38
32
  const builderDevServer = await builder?.createDevServer({
39
33
  runCompile: options.runCompile
40
34
  });
41
- server.addPlugins([
42
- devPlugin({
43
- ...options,
44
- builderDevServer
45
- }, compiler)
46
- ]);
47
- const assetPrefix = await promise;
48
- if (assetPrefix) prodServerOptions.config.output.assetPrefix = assetPrefix;
49
- await applyPlugins(server, prodServerOptions, nodeServer);
50
- await server.init();
35
+ const assetPrefix = await assetPrefixPromise;
36
+ let currentRuntimeServer;
37
+ let nodeServer;
38
+ const buildRuntimeServer = async ()=>{
39
+ const freshServerConfig = await loadServerRuntimeConfig(serverConfigPath) || {};
40
+ const runtimeOptions = createRuntimeServerOptions({
41
+ ...prodServerOptions,
42
+ serverConfig: {
43
+ ...freshServerConfig,
44
+ ...options.serverConfig
45
+ },
46
+ plugins: [
47
+ ...freshServerConfig.plugins || [],
48
+ ...options.plugins || []
49
+ ]
50
+ }, assetPrefix);
51
+ const runtimeServer = createServerBase(runtimeOptions);
52
+ runtimeServer.addPlugins([
53
+ devRuntimeMiddlewarePlugin({
54
+ ...options,
55
+ builderDevServer
56
+ }, compiler)
57
+ ]);
58
+ await applyPlugins(runtimeServer, runtimeOptions, nodeServer);
59
+ await runtimeServer.init();
60
+ currentRuntimeServer = runtimeServer;
61
+ return runtimeServer.handle;
62
+ };
63
+ const pendingReloadFiles = new Set();
64
+ const reloadManager = createReloadManager({
65
+ build: buildRuntimeServer,
66
+ onReload: ()=>{
67
+ const files = Array.from(pendingReloadFiles);
68
+ pendingReloadFiles.clear();
69
+ logger.info(files.length > 0 ? `Server runtime reloaded (${files.join(', ')})` : 'Server runtime reloaded');
70
+ }
71
+ });
72
+ const devHttpsOption = 'object' == typeof dev && dev.https;
73
+ const isHttp2 = !!devHttpsOption;
74
+ if (devHttpsOption) {
75
+ const { genHttpsOptions } = await import("./dev-tools/https/index.mjs");
76
+ const httpsOptions = await genHttpsOptions(devHttpsOption, pwd);
77
+ nodeServer = await createNodeServer(reloadManager.handle, httpsOptions, isHttp2);
78
+ } else nodeServer = await createNodeServer(reloadManager.handle);
79
+ reloadManager.setHandle(await buildRuntimeServer());
80
+ setupDevInfra({
81
+ config,
82
+ pwd,
83
+ distDir,
84
+ apiDir: options.appContext?.apiDirectory,
85
+ sharedDir: options.appContext?.sharedDirectory,
86
+ builder,
87
+ builderDevServer,
88
+ compiler,
89
+ nodeServer,
90
+ getRuntimeServer: ()=>currentRuntimeServer,
91
+ onFileChange: (filepath)=>{
92
+ pendingReloadFiles.add(node_path.relative(pwd, filepath));
93
+ reloadManager.schedule();
94
+ },
95
+ onClose: ()=>reloadManager.close()
96
+ });
51
97
  const afterListen = async ()=>{
52
98
  await builderDevServer?.afterListen();
53
99
  };
@@ -3,13 +3,13 @@ const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/
3
3
  import { chalk, getPackageManager, logger, tryResolve } from "@modern-js/utils";
4
4
  import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
5
5
  import { dirname as __rspack_dirname } from "node:path";
6
- var https_dirname = __rspack_dirname(__rspack_fileURLToPath(import.meta.url));
6
+ var __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url));
7
7
  const genHttpsOptions = async (userOptions, pwd)=>{
8
8
  const httpsOptions = 'boolean' == typeof userOptions ? {} : userOptions;
9
9
  if (!httpsOptions.key || !httpsOptions.cert) {
10
10
  let devcertPath;
11
11
  try {
12
- devcertPath = tryResolve('devcert', pwd, https_dirname);
12
+ devcertPath = tryResolve('devcert', pwd, __rspack_import_meta_dirname__);
13
13
  } catch (err) {
14
14
  const packageManager = await getPackageManager(pwd);
15
15
  const command = chalk.yellow.bold(`${packageManager} add devcert@1.2.2 -D`);