@modern-js/prod-server 2.27.0 → 2.29.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/cjs/index.js +4 -0
  3. package/dist/cjs/libs/context/context.js +10 -4
  4. package/dist/cjs/libs/hook-api/index.js +2 -1
  5. package/dist/cjs/libs/hook-api/index.worker.js +2 -1
  6. package/dist/cjs/libs/render/cache/__tests__/cache.test.js +12 -7
  7. package/dist/cjs/libs/render/cache/index.js +2 -1
  8. package/dist/cjs/libs/render/cache/spr.js +2 -1
  9. package/dist/cjs/libs/render/index.js +12 -3
  10. package/dist/cjs/libs/render/reader.js +2 -1
  11. package/dist/cjs/libs/render/ssr.js +3 -20
  12. package/dist/cjs/libs/reporter.js +22 -0
  13. package/dist/cjs/libs/route/matcher.js +2 -2
  14. package/dist/cjs/libs/serverTiming.js +27 -0
  15. package/dist/cjs/server/index.js +6 -4
  16. package/dist/cjs/server/modernServer.js +44 -16
  17. package/dist/cjs/utils.js +33 -0
  18. package/dist/cjs/workerServer.js +15 -6
  19. package/dist/esm/index.js +1 -0
  20. package/dist/esm/libs/context/context.js +8 -2
  21. package/dist/esm/libs/hook-api/index.js +2 -1
  22. package/dist/esm/libs/hook-api/index.worker.js +2 -1
  23. package/dist/esm/libs/render/cache/__tests__/cache.test.js +12 -12
  24. package/dist/esm/libs/render/cache/index.js +2 -2
  25. package/dist/esm/libs/render/cache/spr.js +2 -2
  26. package/dist/esm/libs/render/index.js +12 -3
  27. package/dist/esm/libs/render/reader.js +2 -2
  28. package/dist/esm/libs/render/ssr.js +6 -28
  29. package/dist/esm/libs/reporter.js +12 -0
  30. package/dist/esm/libs/route/matcher.js +2 -2
  31. package/dist/esm/libs/serverTiming.js +27 -0
  32. package/dist/esm/renderHtml.js +6 -6
  33. package/dist/esm/server/index.js +6 -4
  34. package/dist/esm/server/modernServer.js +84 -44
  35. package/dist/esm/server/modernServerSplit.js +6 -6
  36. package/dist/esm/utils.js +57 -0
  37. package/dist/esm/workerServer.js +14 -5
  38. package/dist/esm-node/index.js +1 -0
  39. package/dist/esm-node/libs/context/context.js +8 -2
  40. package/dist/esm-node/libs/hook-api/index.js +2 -1
  41. package/dist/esm-node/libs/hook-api/index.worker.js +2 -1
  42. package/dist/esm-node/libs/render/cache/__tests__/cache.test.js +12 -7
  43. package/dist/esm-node/libs/render/cache/index.js +2 -1
  44. package/dist/esm-node/libs/render/cache/spr.js +2 -1
  45. package/dist/esm-node/libs/render/index.js +12 -3
  46. package/dist/esm-node/libs/render/reader.js +2 -1
  47. package/dist/esm-node/libs/render/ssr.js +3 -20
  48. package/dist/esm-node/libs/reporter.js +12 -0
  49. package/dist/esm-node/libs/route/matcher.js +2 -2
  50. package/dist/esm-node/libs/serverTiming.js +17 -0
  51. package/dist/esm-node/server/index.js +6 -4
  52. package/dist/esm-node/server/modernServer.js +45 -17
  53. package/dist/esm-node/utils.js +30 -0
  54. package/dist/esm-node/workerServer.js +15 -6
  55. package/dist/types/index.d.ts +1 -0
  56. package/dist/types/libs/context/context.d.ts +5 -2
  57. package/dist/types/libs/hook-api/index.worker.d.ts +2 -1
  58. package/dist/types/libs/render/index.d.ts +13 -18
  59. package/dist/types/libs/reporter.d.ts +2 -0
  60. package/dist/types/libs/serverTiming.d.ts +12 -0
  61. package/dist/types/server/modernServer.d.ts +6 -4
  62. package/dist/types/type.d.ts +1 -0
  63. package/dist/types/utils.d.ts +3 -2
  64. package/package.json +8 -8
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @modern-js/prod-server
2
2
 
3
+ ## 2.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 16e5195: feat(prod-server): add body parser
8
+ feat(prod-server): 增加 body 解析器
9
+ - cba7675: feat: add a server reporter that report server cost, logger about error, info etc.
10
+ feat: 添加一个 server 端 reporter,来报告 server 端耗时,报错等
11
+
12
+ ### Patch Changes
13
+
14
+ - 76ace5d: fix(prod-server): bff may run bodyParser by themself, so we need't to run
15
+ fix(prod-server): bff 可能会在内部运行, 所以我们不需要运行
16
+ - Updated dependencies [e6b5355]
17
+ - Updated dependencies [93db783]
18
+ - Updated dependencies [cba7675]
19
+ - Updated dependencies [99052ea]
20
+ - Updated dependencies [1d71d2e]
21
+ - @modern-js/utils@2.29.0
22
+ - @modern-js/server-core@2.29.0
23
+ - @modern-js/plugin@2.29.0
24
+
25
+ ## 2.28.0
26
+
27
+ ### Minor Changes
28
+
29
+ - 6eae1e7: feat: support worker hmr using dev-server
30
+ feat: 借用 dev-server 支持 wokrer hmr
31
+
32
+ ### Patch Changes
33
+
34
+ - Updated dependencies [00b58a7]
35
+ - @modern-js/utils@2.28.0
36
+ - @modern-js/server-core@2.28.0
37
+ - @modern-js/plugin@2.28.0
38
+
3
39
  ## 2.27.0
4
40
 
5
41
  ### Patch Changes
package/dist/cjs/index.js CHANGED
@@ -19,6 +19,9 @@ _export(exports, {
19
19
  createProxyHandler: function() {
20
20
  return _proxy.createProxyHandler;
21
21
  },
22
+ createRenderHandler: function() {
23
+ return _render.createRenderHandler;
24
+ },
22
25
  default: function() {
23
26
  return _default;
24
27
  }
@@ -29,6 +32,7 @@ const _modernServer = require("./server/modernServer");
29
32
  const _proxy = require("./libs/proxy");
30
33
  _export_star._(require("./type"), exports);
31
34
  _export_star._(require("./constants"), exports);
35
+ const _render = require("./libs/render");
32
36
  const _default = (options) => {
33
37
  if (options == null) {
34
38
  throw new Error("can not start mserver without options");
@@ -15,7 +15,10 @@ const _querystring = /* @__PURE__ */ _interop_require_default._(require("queryst
15
15
  const _buffer = require("buffer");
16
16
  const _etag = /* @__PURE__ */ _interop_require_default._(require("etag"));
17
17
  const _fresh = /* @__PURE__ */ _interop_require_default._(require("fresh"));
18
- const _utils = require("../../utils");
18
+ const _utils = require("@modern-js/utils");
19
+ const _serverTiming = require("../serverTiming");
20
+ const _reporter = require("../reporter");
21
+ const _utils1 = require("../../utils");
19
22
  const MOCK_URL_BASE = "https://modernjs.dev/";
20
23
  class ModernServerContext {
21
24
  get logger() {
@@ -157,18 +160,21 @@ class ModernServerContext {
157
160
  return this.res.writableEnded;
158
161
  }
159
162
  error(dig, e = "") {
160
- this.logger.error(`Web Server Error - ${dig}, error = %s, req.url = %s, req.headers = %o`, e instanceof Error ? e.stack || e.message : e, this.path, (0, _utils.headersWithoutCookie)(this.headers));
163
+ this.logger.error(`Web Server Error - ${dig}, error = %s, req.url = %s, req.headers = %o`, e instanceof Error ? e.stack || e.message : e, this.path, (0, _utils1.headersWithoutCookie)(this.headers));
161
164
  }
162
165
  constructor(req, res, options) {
166
+ var _options;
163
167
  _define_property._(this, "req", void 0);
164
168
  _define_property._(this, "res", void 0);
165
169
  _define_property._(this, "params", {});
166
- _define_property._(this, "serverData", void 0);
170
+ _define_property._(this, "reporter", _reporter.defaultReporter);
171
+ _define_property._(this, "serverTiming", void 0);
172
+ _define_property._(this, "serverData", {});
167
173
  _define_property._(this, "options", {});
168
174
  this.req = req;
169
175
  this.res = res;
170
176
  this.options = options || {};
171
- this.serverData = {};
177
+ this.serverTiming = new _serverTiming.ServerTiming(res, (0, _utils.cutNameByHyphen)(((_options = options) === null || _options === void 0 ? void 0 : _options.metaName) || "modern-js"));
172
178
  this.bind();
173
179
  }
174
180
  }
@@ -27,10 +27,11 @@ const _route = require("./route");
27
27
  const _template = require("./template");
28
28
  const _base = require("./base");
29
29
  const base = (context) => {
30
- const { res } = context;
30
+ const { res, reporter } = context;
31
31
  return {
32
32
  response: new _base.BaseResponse(res),
33
33
  request: new _base.BaseRequest(context),
34
+ reporter,
34
35
  logger: context.logger,
35
36
  metrics: context.metrics
36
37
  };
@@ -56,7 +56,7 @@ class ServerResponse {
56
56
  }
57
57
  }
58
58
  const base = (context) => {
59
- const { req, res, logger, metrics } = context;
59
+ const { req, res, logger, metrics, reporter } = context;
60
60
  const serverResponse = new ServerResponse(res);
61
61
  const { host, pathname, searchParams } = new URL(req.url);
62
62
  const headers = {};
@@ -65,6 +65,7 @@ const base = (context) => {
65
65
  });
66
66
  return {
67
67
  response: new _base.BaseResponse(serverResponse),
68
+ reporter,
68
69
  request: new _base.BaseRequest({
69
70
  url: req.url,
70
71
  host,
@@ -19,6 +19,7 @@ const createCacheConfig = (config = {}) => ({
19
19
  jest.setTimeout(6e4);
20
20
  describe("cache", () => {
21
21
  it("should cache correctly", async () => {
22
+ var _cacheResult;
22
23
  (0, _spr.destroyCache)();
23
24
  const cache = (0, _spr.createCache)();
24
25
  const context = {
@@ -32,7 +33,7 @@ describe("cache", () => {
32
33
  await cache.set(context, content, cacheConfig, true);
33
34
  const cacheResult = await cache.get(context);
34
35
  expect(cacheResult).not.toBe(null);
35
- expect(cacheResult === null || cacheResult === void 0 ? void 0 : cacheResult.content).toBe("hello");
36
+ expect((_cacheResult = cacheResult) === null || _cacheResult === void 0 ? void 0 : _cacheResult.content).toBe("hello");
36
37
  });
37
38
  it("should ignore cache set when cache config not exist", async () => {
38
39
  (0, _spr.destroyCache)();
@@ -127,6 +128,7 @@ describe("cache", () => {
127
128
  (0, _spr.destroyCache)();
128
129
  const cache = (0, _spr.createCache)();
129
130
  for (const cacheable of _cacheable.cacheabelAry) {
131
+ var _cacheResult;
130
132
  const context = {
131
133
  entry: "",
132
134
  pathname: cacheable.requestOpt.url,
@@ -136,13 +138,14 @@ describe("cache", () => {
136
138
  const cacheConfig = createCacheConfig(cacheable.cacheConfig || {});
137
139
  await cache.set(context, cacheable.content, cacheConfig, true);
138
140
  const cacheResult = await cache.get(context);
139
- expect(cacheResult === null || cacheResult === void 0 ? void 0 : cacheResult.content).toBe(cacheable.content);
141
+ expect((_cacheResult = cacheResult) === null || _cacheResult === void 0 ? void 0 : _cacheResult.content).toBe(cacheable.content);
140
142
  }
141
143
  });
142
144
  it("should match cache correctly", async () => {
143
145
  (0, _spr.destroyCache)();
144
146
  const cache = (0, _spr.createCache)();
145
147
  for (const cacheable of _matchedcache.matchedCacheableAry) {
148
+ var _cacheResult;
146
149
  const [baseCacheable, matchOne, ...other] = cacheable;
147
150
  const { requestOpt = {}, cacheConfig, content } = baseCacheable;
148
151
  const context = {
@@ -159,7 +162,7 @@ describe("cache", () => {
159
162
  headers: matchOne.headers
160
163
  };
161
164
  const cacheResult = await cache.get(matchContext);
162
- expect(cacheResult === null || cacheResult === void 0 ? void 0 : cacheResult.content).toBe(content);
165
+ expect((_cacheResult = cacheResult) === null || _cacheResult === void 0 ? void 0 : _cacheResult.content).toBe(content);
163
166
  for (const notMatch of other) {
164
167
  const notMatchContext = {
165
168
  entry: "",
@@ -173,6 +176,7 @@ describe("cache", () => {
173
176
  }
174
177
  });
175
178
  it("should stale cache correctly", async () => {
179
+ var _freshResult, _staleResult;
176
180
  (0, _spr.destroyCache)();
177
181
  const cache = (0, _spr.createCache)();
178
182
  const context = {
@@ -188,16 +192,17 @@ describe("cache", () => {
188
192
  const shouldCache = await cache.set(context, content, config, true);
189
193
  expect(shouldCache.value).toBe(true);
190
194
  const freshResult = await cache.get(context);
191
- expect(freshResult === null || freshResult === void 0 ? void 0 : freshResult.isStale).toBe(false);
195
+ expect((_freshResult = freshResult) === null || _freshResult === void 0 ? void 0 : _freshResult.isStale).toBe(false);
192
196
  await new Promise((resolve) => {
193
197
  setTimeout(() => {
194
198
  resolve();
195
199
  }, 6e3);
196
200
  });
197
201
  const staleResult = await cache.get(context);
198
- expect(staleResult === null || staleResult === void 0 ? void 0 : staleResult.isStale).toBe(true);
202
+ expect((_staleResult = staleResult) === null || _staleResult === void 0 ? void 0 : _staleResult.isStale).toBe(true);
199
203
  });
200
204
  it("should garbage cache correctly", async () => {
205
+ var _freshResult, _staleResult;
201
206
  (0, _spr.destroyCache)();
202
207
  const cache = (0, _spr.createCache)();
203
208
  const context = {
@@ -214,13 +219,13 @@ describe("cache", () => {
214
219
  const shouldCache = await cache.set(context, content, config, true);
215
220
  expect(shouldCache.value).toBe(true);
216
221
  const freshResult = await cache.get(context);
217
- expect(freshResult === null || freshResult === void 0 ? void 0 : freshResult.isGarbage).toBe(false);
222
+ expect((_freshResult = freshResult) === null || _freshResult === void 0 ? void 0 : _freshResult.isGarbage).toBe(false);
218
223
  await new Promise((resolve) => {
219
224
  setTimeout(() => {
220
225
  resolve();
221
226
  }, 1e4);
222
227
  });
223
228
  const staleResult = await cache.get(context);
224
- expect(staleResult === null || staleResult === void 0 ? void 0 : staleResult.isGarbage).toBe(true);
229
+ expect((_staleResult = staleResult) === null || _staleResult === void 0 ? void 0 : _staleResult.isGarbage).toBe(true);
225
230
  });
226
231
  });
@@ -15,6 +15,7 @@ const _util = require("./util");
15
15
  const _default = (renderFn, ctx) => {
16
16
  const sprCache = (0, _spr.createCache)();
17
17
  const doRender = async (context) => {
18
+ var _cacheFile;
18
19
  const cacheContext = {
19
20
  entry: context.entryName,
20
21
  ...context.request
@@ -50,7 +51,7 @@ const _default = (renderFn, ctx) => {
50
51
  const renderResult = await renderFn(context);
51
52
  return afterRender(renderResult, saveHtmlIntoCache);
52
53
  }
53
- const cacheHash = cacheFile === null || cacheFile === void 0 ? void 0 : cacheFile.hash;
54
+ const cacheHash = (_cacheFile = cacheFile) === null || _cacheFile === void 0 ? void 0 : _cacheFile.hash;
54
55
  if (cacheFile.isGarbage) {
55
56
  const renderResult = await renderFn(context);
56
57
  return afterRender(renderResult, saveHtmlIntoCache);
@@ -161,9 +161,10 @@ class CacheManager {
161
161
  return (0, _util.maybeSync)(doCache)(sync);
162
162
  }
163
163
  async del(context, cacheHash) {
164
+ var _data;
164
165
  const cacheKey = this.generateRequestKey(context);
165
166
  const data = this.cache.get(cacheKey);
166
- data === null || data === void 0 ? void 0 : data.caches.del(cacheHash);
167
+ (_data = data) === null || _data === void 0 ? void 0 : _data.caches.del(cacheHash);
167
168
  }
168
169
  constructor(cacheOptions) {
169
170
  _define_property._(this, "cache", void 0);
@@ -17,7 +17,7 @@ const _static = require("./static");
17
17
  const _reader = require("./reader");
18
18
  const _ssr = /* @__PURE__ */ _interop_require_wildcard._(require("./ssr"));
19
19
  const _utils1 = require("./utils");
20
- const createRenderHandler = ({ distDir, staticGenerate, forceCSR, nonce, metaName = "modern-js" }) => async function render({ ctx, route, runner }) {
20
+ const createRenderHandler = ({ distDir, staticGenerate, forceCSR, nonce, ssrRender, metaName = "modern-js" }) => async function render({ ctx, route, runner }) {
21
21
  if (ctx.resHasHandled()) {
22
22
  return null;
23
23
  }
@@ -35,7 +35,7 @@ const createRenderHandler = ({ distDir, staticGenerate, forceCSR, nonce, metaNam
35
35
  const useCSR = forceCSR && (ctx.query.csr || ctx.headers[`x-${(0, _utils.cutNameByHyphen)(metaName)}-ssr-fallback`]);
36
36
  if (route.isSSR && !useCSR) {
37
37
  try {
38
- const result = await _ssr.render(ctx, {
38
+ const ssrRenderOptions = {
39
39
  distDir,
40
40
  entryName: route.entryName,
41
41
  urlPath: route.urlPath,
@@ -43,7 +43,16 @@ const createRenderHandler = ({ distDir, staticGenerate, forceCSR, nonce, metaNam
43
43
  template: content.toString(),
44
44
  staticGenerate,
45
45
  nonce
46
- }, runner);
46
+ };
47
+ const result = await (ssrRender ? ssrRender(ctx, ssrRenderOptions, runner) : _ssr.render(ctx, {
48
+ distDir,
49
+ entryName: route.entryName,
50
+ urlPath: route.urlPath,
51
+ bundle: route.bundle,
52
+ template: content.toString(),
53
+ staticGenerate,
54
+ nonce
55
+ }, runner));
47
56
  return result;
48
57
  } catch (err) {
49
58
  ctx.error(_constants.ERROR_DIGEST.ERENDER, err.stack || err.message);
@@ -101,8 +101,9 @@ class LruReader {
101
101
  }
102
102
  const reader = new LruReader();
103
103
  const readFile = async (filepath) => {
104
+ var _file;
104
105
  const file = await reader.read(filepath);
105
- return file === null || file === void 0 ? void 0 : file.content;
106
+ return (_file = file) === null || _file === void 0 ? void 0 : _file.content;
106
107
  };
107
108
  const updateFile = () => {
108
109
  reader.update();
@@ -22,7 +22,6 @@ const render = async (ctx, renderOptions, runner) => {
22
22
  const loadableStats = _utils.fs.existsSync(loadableUri) ? require(loadableUri) : "";
23
23
  const routesManifestUri = _path.default.join(distDir, _utils.ROUTE_MANIFEST_FILE);
24
24
  const routeManifest = _utils.fs.existsSync(routesManifestUri) ? require(routesManifestUri) : void 0;
25
- const body = await getRequestBody(ctx.req);
26
25
  const context = {
27
26
  request: {
28
27
  baseUrl: urlPath,
@@ -32,7 +31,7 @@ const render = async (ctx, renderOptions, runner) => {
32
31
  query: ctx.query,
33
32
  url: ctx.href,
34
33
  headers: ctx.headers,
35
- body
34
+ body: ctx.req.body
36
35
  },
37
36
  response: {
38
37
  setHeader: (key, value) => {
@@ -51,6 +50,8 @@ const render = async (ctx, renderOptions, runner) => {
51
50
  staticGenerate,
52
51
  logger: void 0,
53
52
  metrics: void 0,
53
+ reporter: ctx.reporter,
54
+ serverTiming: ctx.serverTiming,
54
55
  req: ctx.req,
55
56
  res: ctx.res,
56
57
  enableUnsafeCtx,
@@ -84,21 +85,3 @@ const render = async (ctx, renderOptions, runner) => {
84
85
  };
85
86
  }
86
87
  };
87
- const getRequestBody = (req) => {
88
- return new Promise((resolve, reject) => {
89
- if ((req === null || req === void 0 ? void 0 : req.method) && req.method.toLowerCase() !== "get") {
90
- let body = "";
91
- req.on("data", (chunk) => {
92
- body += chunk.toString();
93
- });
94
- req.on("end", () => {
95
- resolve(body);
96
- });
97
- req.on("error", (err) => {
98
- reject(err);
99
- });
100
- } else {
101
- resolve(void 0);
102
- }
103
- });
104
- };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "defaultReporter", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return defaultReporter;
9
+ }
10
+ });
11
+ const defaultReporter = {
12
+ init() {
13
+ },
14
+ reportError() {
15
+ },
16
+ reportTiming() {
17
+ },
18
+ reportInfo() {
19
+ },
20
+ reportWarn() {
21
+ }
22
+ };
@@ -49,9 +49,9 @@ class RouteMatcher {
49
49
  if (!this.urlReg) {
50
50
  return this.urlPath.length;
51
51
  } else {
52
- var _result_;
52
+ var _result_, _result;
53
53
  const result = this.urlReg.exec(pathname);
54
- return (result === null || result === void 0 ? void 0 : (_result_ = result[0]) === null || _result_ === void 0 ? void 0 : _result_.length) || null;
54
+ return ((_result = result) === null || _result === void 0 ? void 0 : (_result_ = _result[0]) === null || _result_ === void 0 ? void 0 : _result_.length) || null;
55
55
  }
56
56
  }
57
57
  // if match url path
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "ServerTiming", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return ServerTiming;
9
+ }
10
+ });
11
+ const _define_property = require("@swc/helpers/_/_define_property");
12
+ const SERVER_TIMING = "Server-Timing";
13
+ class ServerTiming {
14
+ addServeTiming(name, dur, desc) {
15
+ const _name = `bd-${this.meta}-${name}`;
16
+ const serverTiming = this.res.getHeader(SERVER_TIMING) || this.res.getHeader(SERVER_TIMING.toLocaleLowerCase());
17
+ const value = `${_name};${desc ? `decs="${desc}";` : ""} dur=${dur}`;
18
+ this.res.setHeader(SERVER_TIMING, serverTiming ? `${serverTiming}, ${value}` : value);
19
+ return this;
20
+ }
21
+ constructor(res, meta) {
22
+ _define_property._(this, "meta", void 0);
23
+ _define_property._(this, "res", void 0);
24
+ this.meta = meta;
25
+ this.res = res;
26
+ }
27
+ }
@@ -89,7 +89,8 @@ class Server {
89
89
  }
90
90
  listen(options, listener) {
91
91
  const callback = () => {
92
- listener === null || listener === void 0 ? void 0 : listener();
92
+ var _listener;
93
+ (_listener = listener) === null || _listener === void 0 ? void 0 : _listener();
93
94
  };
94
95
  if (typeof options === "object") {
95
96
  if (process.env.PORT) {
@@ -139,6 +140,7 @@ class Server {
139
140
  });
140
141
  }
141
142
  initAppContext() {
143
+ var _appContext, _appContext1, _appContext2;
142
144
  const { options } = this;
143
145
  const { pwd: appDirectory, plugins = [], config, appContext } = options;
144
146
  const serverPlugins = plugins.map((p) => ({
@@ -146,9 +148,9 @@ class Server {
146
148
  }));
147
149
  return {
148
150
  appDirectory,
149
- apiDirectory: appContext === null || appContext === void 0 ? void 0 : appContext.apiDirectory,
150
- lambdaDirectory: appContext === null || appContext === void 0 ? void 0 : appContext.lambdaDirectory,
151
- sharedDirectory: (appContext === null || appContext === void 0 ? void 0 : appContext.sharedDirectory) || _path.default.resolve(appDirectory, _utils.SHARED_DIR),
151
+ apiDirectory: (_appContext = appContext) === null || _appContext === void 0 ? void 0 : _appContext.apiDirectory,
152
+ lambdaDirectory: (_appContext1 = appContext) === null || _appContext1 === void 0 ? void 0 : _appContext1.lambdaDirectory,
153
+ sharedDirectory: ((_appContext2 = appContext) === null || _appContext2 === void 0 ? void 0 : _appContext2.sharedDirectory) || _path.default.resolve(appDirectory, _utils.SHARED_DIR),
152
154
  distDirectory: _path.default.join(appDirectory, config.output.path || "dist"),
153
155
  plugins: serverPlugins
154
156
  };
@@ -14,6 +14,7 @@ const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildc
14
14
  const _http = require("http");
15
15
  const _path = /* @__PURE__ */ _interop_require_default._(require("path"));
16
16
  const _utils = require("@modern-js/utils");
17
+ const _time = require("@modern-js/utils/universal/time");
17
18
  const _route = require("../libs/route");
18
19
  const _render = require("../libs/render");
19
20
  const _serveFile = require("../libs/serveFile");
@@ -27,9 +28,9 @@ const SERVER_DIR = "./server";
27
28
  class ModernServer {
28
29
  // server prepare
29
30
  async onInit(runner, app) {
30
- var _conf_bff, _this_conf_server, _conf_security, _this_conf_output;
31
+ var _conf_bff, _app, _this_conf_output;
31
32
  this.runner = runner;
32
- const { distDir, staticGenerate, conf, metaName } = this;
33
+ const { distDir, conf } = this;
33
34
  this.initReader();
34
35
  (0, _utils1.debug)("final server conf", this.conf);
35
36
  this.proxyHandler = (0, _proxy.createProxyHandler)((_conf_bff = conf.bff) === null || _conf_bff === void 0 ? void 0 : _conf_bff.proxy);
@@ -38,7 +39,7 @@ class ModernServer {
38
39
  this.addHandler(handler);
39
40
  });
40
41
  }
41
- app === null || app === void 0 ? void 0 : app.on("close", () => {
42
+ (_app = app) === null || _app === void 0 ? void 0 : _app.on("close", () => {
42
43
  this.reader.close();
43
44
  });
44
45
  const usageRoutes = this.filterRoutes(this.getRoutes());
@@ -46,20 +47,25 @@ class ModernServer {
46
47
  this.warmupSSRBundle();
47
48
  await this.prepareFrameHandler();
48
49
  await this.prepareLoaderHandler(usageRoutes, distDir);
50
+ this.routeRenderHandler = this.getRenderHandler();
51
+ await this.setupBeforeProdMiddleware();
52
+ this.addHandler(this.setupStaticMiddleware((_this_conf_output = this.conf.output) === null || _this_conf_output === void 0 ? void 0 : _this_conf_output.assetPrefix));
53
+ this.addHandler(_serveFile.faviconFallbackHandler);
54
+ this.addHandler(this.routeHandler.bind(this));
55
+ this.compose();
56
+ }
57
+ getRenderHandler() {
58
+ var _this_conf_server, _conf_security;
59
+ const { distDir, staticGenerate, conf, metaName } = this;
49
60
  const ssrConfig = (_this_conf_server = this.conf.server) === null || _this_conf_server === void 0 ? void 0 : _this_conf_server.ssr;
50
61
  const forceCSR = typeof ssrConfig === "object" ? ssrConfig.forceCSR : false;
51
- this.routeRenderHandler = (0, _render.createRenderHandler)({
62
+ return (0, _render.createRenderHandler)({
52
63
  distDir,
53
64
  staticGenerate,
54
65
  forceCSR,
55
66
  nonce: (_conf_security = conf.security) === null || _conf_security === void 0 ? void 0 : _conf_security.nonce,
56
67
  metaName
57
68
  });
58
- await this.setupBeforeProdMiddleware();
59
- this.addHandler(this.setupStaticMiddleware((_this_conf_output = this.conf.output) === null || _this_conf_output === void 0 ? void 0 : _this_conf_output.assetPrefix));
60
- this.addHandler(_serveFile.faviconFallbackHandler);
61
- this.addHandler(this.routeHandler.bind(this));
62
- this.compose();
63
69
  }
64
70
  // server ready
65
71
  onRepack(_) {
@@ -71,7 +77,9 @@ class ModernServer {
71
77
  async render(req, res, url) {
72
78
  req.logger = req.logger || this.logger;
73
79
  req.metrics = req.metrics || this.metrics;
74
- const context = (0, _context.createContext)(req, res);
80
+ const context = (0, _context.createContext)(req, res, {
81
+ metaName: this.metaName
82
+ });
75
83
  const matched = this.router.match(url || context.path);
76
84
  if (!matched) {
77
85
  return null;
@@ -165,9 +173,10 @@ class ModernServer {
165
173
  return handler;
166
174
  }
167
175
  async prepareAPIHandler(extension) {
176
+ var _bff, _bff1;
168
177
  const { workDir, runner, conf } = this;
169
178
  const { bff } = conf;
170
- const prefix = (bff === null || bff === void 0 ? void 0 : bff.prefix) || "/api";
179
+ const prefix = ((_bff = bff) === null || _bff === void 0 ? void 0 : _bff.prefix) || "/api";
171
180
  const webOnly = await (0, _utils.isWebOnly)();
172
181
  if (webOnly && process.env.NODE_ENV === "development") {
173
182
  return (req, res) => {
@@ -179,7 +188,7 @@ class ModernServer {
179
188
  pwd: workDir,
180
189
  config: extension,
181
190
  prefix: Array.isArray(prefix) ? prefix[0] : prefix,
182
- httpMethodDecider: bff === null || bff === void 0 ? void 0 : bff.httpMethodDecider,
191
+ httpMethodDecider: (_bff1 = bff) === null || _bff1 === void 0 ? void 0 : _bff1.httpMethodDecider,
183
192
  render: this.render.bind(this)
184
193
  }, {
185
194
  onLast: () => null
@@ -271,23 +280,35 @@ class ModernServer {
271
280
  /* —————————————————————— private function —————————————————————— */
272
281
  // handler route.json, include api / csr / ssr
273
282
  async routeHandler(context) {
274
- const { res } = context;
283
+ const { res, req, reporter } = context;
275
284
  const matched = this.router.match(context.path);
276
285
  if (!matched) {
277
286
  this.render404(context);
278
287
  return;
279
288
  }
289
+ await reporter.init({
290
+ match: matched
291
+ });
292
+ const end = (0, _time.time)();
293
+ res.on("finish", () => {
294
+ const cost = end();
295
+ reporter.reportTiming("server_handle_request", cost);
296
+ });
280
297
  let route = matched.generate(context.url);
281
298
  if (route.isApi) {
282
299
  await this.handleAPI(context);
283
300
  return;
284
301
  }
302
+ await (0, _utils1.bodyParser)(req);
285
303
  if (route.entryName) {
286
304
  const afterMatchContext = (0, _hookapi.createAfterMatchContext)(context, route.entryName);
287
305
  if (this.runMode === _constants.RUN_MODE.FULL) {
306
+ const end2 = (0, _time.time)();
288
307
  await this.runner.afterMatch(afterMatchContext, {
289
308
  onLast: _utils1.noop
290
309
  });
310
+ const cost = end2();
311
+ reporter.reportTiming("server_hook_after_render", cost);
291
312
  }
292
313
  if (this.isSend(res)) {
293
314
  return;
@@ -309,7 +330,10 @@ class ModernServer {
309
330
  if (this.frameWebHandler) {
310
331
  res.locals = res.locals || {};
311
332
  const middlewareContext = (0, _hookapi.createMiddlewareContext)(context);
333
+ const end2 = (0, _time.time)();
312
334
  await this.frameWebHandler(middlewareContext);
335
+ const cost = end2();
336
+ reporter.reportTiming("server_middleware", cost);
313
337
  res.locals = {
314
338
  ...res.locals,
315
339
  ...middlewareContext.response.locals
@@ -331,9 +355,12 @@ class ModernServer {
331
355
  if (route.entryName) {
332
356
  const afterRenderContext = (0, _hookapi.createAfterRenderContext)(context, response.toString());
333
357
  if (this.runMode === _constants.RUN_MODE.FULL) {
358
+ const end2 = (0, _time.time)();
334
359
  await this.runner.afterRender(afterRenderContext, {
335
360
  onLast: _utils1.noop
336
361
  });
362
+ const cost = end2();
363
+ reporter.reportTiming("server_hook_after_render", cost);
337
364
  }
338
365
  if (this.isSend(res)) {
339
366
  return;
@@ -446,6 +473,7 @@ class ModernServer {
446
473
  context.res.end((0, _utils1.createErrorDocument)(status, text));
447
474
  }
448
475
  constructor({ pwd, config, routes, staticGenerate, logger, metrics, runMode, proxyTarget, appContext }) {
476
+ var _appContext;
449
477
  _define_property._(this, "pwd", void 0);
450
478
  _define_property._(this, "distDir", void 0);
451
479
  _define_property._(this, "workDir", void 0);
@@ -460,13 +488,13 @@ class ModernServer {
460
488
  _define_property._(this, "reader", _reader);
461
489
  _define_property._(this, "proxyTarget", void 0);
462
490
  _define_property._(this, "routeRenderHandler", void 0);
491
+ _define_property._(this, "staticGenerate", void 0);
492
+ _define_property._(this, "metaName", void 0);
463
493
  _define_property._(this, "loaderHandler", null);
464
494
  _define_property._(this, "frameWebHandler", null);
465
495
  _define_property._(this, "frameAPIHandler", null);
466
496
  _define_property._(this, "proxyHandler", null);
467
497
  _define_property._(this, "_handler", void 0);
468
- _define_property._(this, "staticGenerate", void 0);
469
- _define_property._(this, "metaName", void 0);
470
498
  require("ignore-styles");
471
499
  this.pwd = pwd;
472
500
  this.distDir = _path.default.resolve(pwd, config.output.path || "dist");
@@ -480,6 +508,6 @@ class ModernServer {
480
508
  this.proxyTarget = proxyTarget;
481
509
  this.staticGenerate = staticGenerate || false;
482
510
  this.runMode = runMode || _constants.RUN_MODE.FULL;
483
- this.metaName = appContext === null || appContext === void 0 ? void 0 : appContext.metaName;
511
+ this.metaName = (_appContext = appContext) === null || _appContext === void 0 ? void 0 : _appContext.metaName;
484
512
  }
485
513
  }
package/dist/cjs/utils.js CHANGED
@@ -36,6 +36,9 @@ _export(exports, {
36
36
  },
37
37
  isRedirect: function() {
38
38
  return isRedirect;
39
+ },
40
+ bodyParser: function() {
41
+ return bodyParser;
39
42
  }
40
43
  });
41
44
  const _utils = require("@modern-js/utils");
@@ -159,3 +162,33 @@ const isRedirect = (code) => {
159
162
  308
160
163
  ].includes(code);
161
164
  };
165
+ function parseBodyTypes(headers, body) {
166
+ switch (headers["content-type"]) {
167
+ case "application/json":
168
+ return JSON.parse(body);
169
+ default:
170
+ return body;
171
+ }
172
+ }
173
+ const getRequestBody = (req) => new Promise((resolve, reject) => {
174
+ var _req;
175
+ if (((_req = req) === null || _req === void 0 ? void 0 : _req.method) && req.method.toLowerCase() !== "get") {
176
+ let body = "";
177
+ req.on("data", (chunk) => {
178
+ body += chunk.toString();
179
+ });
180
+ req.on("end", () => {
181
+ resolve(parseBodyTypes(req.headers, body));
182
+ });
183
+ req.on("error", (err) => {
184
+ reject(err);
185
+ });
186
+ } else {
187
+ resolve(void 0);
188
+ }
189
+ });
190
+ const bodyParser = async (req) => {
191
+ if (!req.body) {
192
+ req.body = await getRequestBody(req);
193
+ }
194
+ };