@modern-js/prod-server 2.28.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 (36) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/cjs/libs/context/context.js +10 -4
  3. package/dist/cjs/libs/hook-api/index.js +2 -1
  4. package/dist/cjs/libs/hook-api/index.worker.js +2 -1
  5. package/dist/cjs/libs/render/ssr.js +3 -19
  6. package/dist/cjs/libs/reporter.js +22 -0
  7. package/dist/cjs/libs/serverTiming.js +27 -0
  8. package/dist/cjs/server/modernServer.js +23 -2
  9. package/dist/cjs/utils.js +33 -0
  10. package/dist/cjs/workerServer.js +12 -3
  11. package/dist/esm/libs/context/context.js +8 -2
  12. package/dist/esm/libs/hook-api/index.js +2 -1
  13. package/dist/esm/libs/hook-api/index.worker.js +2 -1
  14. package/dist/esm/libs/render/ssr.js +6 -29
  15. package/dist/esm/libs/reporter.js +12 -0
  16. package/dist/esm/libs/serverTiming.js +27 -0
  17. package/dist/esm/server/modernServer.js +57 -26
  18. package/dist/esm/utils.js +57 -0
  19. package/dist/esm/workerServer.js +13 -4
  20. package/dist/esm-node/libs/context/context.js +8 -2
  21. package/dist/esm-node/libs/hook-api/index.js +2 -1
  22. package/dist/esm-node/libs/hook-api/index.worker.js +2 -1
  23. package/dist/esm-node/libs/render/ssr.js +3 -19
  24. package/dist/esm-node/libs/reporter.js +12 -0
  25. package/dist/esm-node/libs/serverTiming.js +17 -0
  26. package/dist/esm-node/server/modernServer.js +24 -3
  27. package/dist/esm-node/utils.js +30 -0
  28. package/dist/esm-node/workerServer.js +12 -3
  29. package/dist/types/libs/context/context.d.ts +5 -2
  30. package/dist/types/libs/hook-api/index.worker.d.ts +2 -1
  31. package/dist/types/libs/reporter.d.ts +2 -0
  32. package/dist/types/libs/serverTiming.d.ts +12 -0
  33. package/dist/types/server/modernServer.d.ts +1 -1
  34. package/dist/types/type.d.ts +1 -0
  35. package/dist/types/utils.d.ts +3 -2
  36. package/package.json +8 -8
@@ -8,10 +8,11 @@ import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
8
8
  import { createServer } from "http";
9
9
  import path from "path";
10
10
  import { fs, isPromise, isWebOnly, mime, ROUTE_SPEC_FILE } from "@modern-js/utils";
11
+ import { time } from "@modern-js/utils/universal/time";
11
12
  import { RouteMatchManager } from "../libs/route";
12
13
  import { createRenderHandler } from "../libs/render";
13
14
  import { createStaticFileHandler, faviconFallbackHandler } from "../libs/serveFile";
14
- import { createErrorDocument, createMiddlewareCollecter, getStaticReg, mergeExtension, noop, debug, isRedirect } from "../utils";
15
+ import { createErrorDocument, createMiddlewareCollecter, getStaticReg, mergeExtension, noop, debug, isRedirect, bodyParser } from "../utils";
15
16
  import * as reader from "../libs/render/reader";
16
17
  import { createProxyHandler } from "../libs/proxy";
17
18
  import { createContext } from "../libs/context";
@@ -164,7 +165,9 @@ export var ModernServer = /* @__PURE__ */ function() {
164
165
  case 0:
165
166
  req.logger = req.logger || _this.logger;
166
167
  req.metrics = req.metrics || _this.metrics;
167
- context = createContext(req, res);
168
+ context = createContext(req, res, {
169
+ metaName: _this.metaName
170
+ });
168
171
  matched = _this.router.match(url || context.path);
169
172
  if (!matched) {
170
173
  return [
@@ -666,11 +669,11 @@ export var ModernServer = /* @__PURE__ */ function() {
666
669
  function routeHandler(context) {
667
670
  var _this = this;
668
671
  return _async_to_generator(function() {
669
- var res, matched, route, afterMatchContext, _afterMatchContext_router, current, url, status, matched1, middlewareContext, renderResult, responseStream, response, afterRenderContext;
672
+ var res, req, reporter, matched, end, route, afterMatchContext, end1, cost, _afterMatchContext_router, current, url, status, matched1, middlewareContext, end2, cost1, renderResult, responseStream, response, afterRenderContext, end3, cost2;
670
673
  return _ts_generator(this, function(_state) {
671
674
  switch (_state.label) {
672
675
  case 0:
673
- res = context.res;
676
+ res = context.res, req = context.req, reporter = context.reporter;
674
677
  matched = _this.router.match(context.path);
675
678
  if (!matched) {
676
679
  _this.render404(context);
@@ -678,43 +681,65 @@ export var ModernServer = /* @__PURE__ */ function() {
678
681
  2
679
682
  ];
680
683
  }
684
+ return [
685
+ 4,
686
+ reporter.init({
687
+ match: matched
688
+ })
689
+ ];
690
+ case 1:
691
+ _state.sent();
692
+ end = time();
693
+ res.on("finish", function() {
694
+ var cost3 = end();
695
+ reporter.reportTiming("server_handle_request", cost3);
696
+ });
681
697
  route = matched.generate(context.url);
682
698
  if (!route.isApi)
683
699
  return [
684
700
  3,
685
- 2
701
+ 3
686
702
  ];
687
703
  return [
688
704
  4,
689
705
  _this.handleAPI(context)
690
706
  ];
691
- case 1:
707
+ case 2:
692
708
  _state.sent();
693
709
  return [
694
710
  2
695
711
  ];
696
- case 2:
712
+ case 3:
713
+ return [
714
+ 4,
715
+ bodyParser(req)
716
+ ];
717
+ case 4:
718
+ _state.sent();
697
719
  if (!route.entryName)
698
720
  return [
699
721
  3,
700
- 5
722
+ 7
701
723
  ];
702
724
  afterMatchContext = createAfterMatchContext(context, route.entryName);
703
725
  if (!(_this.runMode === RUN_MODE.FULL))
704
726
  return [
705
727
  3,
706
- 4
728
+ 6
707
729
  ];
730
+ end1 = time();
708
731
  return [
709
732
  4,
710
733
  _this.runner.afterMatch(afterMatchContext, {
711
734
  onLast: noop
712
735
  })
713
736
  ];
714
- case 3:
737
+ case 5:
715
738
  _state.sent();
716
- _state.label = 4;
717
- case 4:
739
+ cost = end1();
740
+ reporter.reportTiming("server_hook_after_render", cost);
741
+ _state.label = 6;
742
+ case 6:
718
743
  if (_this.isSend(res)) {
719
744
  return [
720
745
  2
@@ -737,34 +762,37 @@ export var ModernServer = /* @__PURE__ */ function() {
737
762
  }
738
763
  route = matched1.generate(context.url);
739
764
  }
740
- _state.label = 5;
741
- case 5:
765
+ _state.label = 7;
766
+ case 7:
742
767
  if (!_this.frameWebHandler)
743
768
  return [
744
769
  3,
745
- 7
770
+ 9
746
771
  ];
747
772
  res.locals = res.locals || {};
748
773
  middlewareContext = createMiddlewareContext(context);
774
+ end2 = time();
749
775
  return [
750
776
  4,
751
777
  _this.frameWebHandler(middlewareContext)
752
778
  ];
753
- case 6:
779
+ case 8:
754
780
  _state.sent();
781
+ cost1 = end2();
782
+ reporter.reportTiming("server_middleware", cost1);
755
783
  res.locals = _object_spread({}, res.locals, middlewareContext.response.locals);
756
784
  if (_this.isSend(res)) {
757
785
  return [
758
786
  2
759
787
  ];
760
788
  }
761
- _state.label = 7;
762
- case 7:
789
+ _state.label = 9;
790
+ case 9:
763
791
  return [
764
792
  4,
765
793
  _this.handleWeb(context, route)
766
794
  ];
767
- case 8:
795
+ case 10:
768
796
  renderResult = _state.sent();
769
797
  if (!renderResult) {
770
798
  return [
@@ -782,32 +810,35 @@ export var ModernServer = /* @__PURE__ */ function() {
782
810
  if (!route.entryName)
783
811
  return [
784
812
  3,
785
- 11
813
+ 13
786
814
  ];
787
815
  afterRenderContext = createAfterRenderContext(context, response.toString());
788
816
  if (!(_this.runMode === RUN_MODE.FULL))
789
817
  return [
790
818
  3,
791
- 10
819
+ 12
792
820
  ];
821
+ end3 = time();
793
822
  return [
794
823
  4,
795
824
  _this.runner.afterRender(afterRenderContext, {
796
825
  onLast: noop
797
826
  })
798
827
  ];
799
- case 9:
828
+ case 11:
800
829
  _state.sent();
801
- _state.label = 10;
802
- case 10:
830
+ cost2 = end3();
831
+ reporter.reportTiming("server_hook_after_render", cost2);
832
+ _state.label = 12;
833
+ case 12:
803
834
  if (_this.isSend(res)) {
804
835
  return [
805
836
  2
806
837
  ];
807
838
  }
808
839
  response = afterRenderContext.template.get();
809
- _state.label = 11;
810
- case 11:
840
+ _state.label = 13;
841
+ case 13:
811
842
  res.end(response);
812
843
  return [
813
844
  2
package/dist/esm/utils.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { _ as _async_to_generator } from "@swc/helpers/_/_async_to_generator";
1
2
  import { _ as _object_spread } from "@swc/helpers/_/_object_spread";
2
3
  import { _ as _to_consumable_array } from "@swc/helpers/_/_to_consumable_array";
4
+ import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
3
5
  import { createDebugger } from "@modern-js/utils";
4
6
  export var debug = createDebugger("prod-server");
5
7
  export var mergeExtension = function(users) {
@@ -90,3 +92,58 @@ export var isRedirect = function(code) {
90
92
  308
91
93
  ].includes(code);
92
94
  };
95
+ function parseBodyTypes(headers, body) {
96
+ switch (headers["content-type"]) {
97
+ case "application/json":
98
+ return JSON.parse(body);
99
+ default:
100
+ return body;
101
+ }
102
+ }
103
+ var getRequestBody = function(req) {
104
+ return new Promise(function(resolve, reject) {
105
+ var _req;
106
+ if (((_req = req) === null || _req === void 0 ? void 0 : _req.method) && req.method.toLowerCase() !== "get") {
107
+ var body = "";
108
+ req.on("data", function(chunk) {
109
+ body += chunk.toString();
110
+ });
111
+ req.on("end", function() {
112
+ resolve(parseBodyTypes(req.headers, body));
113
+ });
114
+ req.on("error", function(err) {
115
+ reject(err);
116
+ });
117
+ } else {
118
+ resolve(void 0);
119
+ }
120
+ });
121
+ };
122
+ export var bodyParser = function() {
123
+ var _ref = _async_to_generator(function(req) {
124
+ return _ts_generator(this, function(_state) {
125
+ switch (_state.label) {
126
+ case 0:
127
+ if (!!req.body)
128
+ return [
129
+ 3,
130
+ 2
131
+ ];
132
+ return [
133
+ 4,
134
+ getRequestBody(req)
135
+ ];
136
+ case 1:
137
+ req.body = _state.sent();
138
+ _state.label = 2;
139
+ case 2:
140
+ return [
141
+ 2
142
+ ];
143
+ }
144
+ });
145
+ });
146
+ return function bodyParser2(req) {
147
+ return _ref.apply(this, arguments);
148
+ };
149
+ }();
@@ -9,6 +9,7 @@ import { createAfterMatchContext, createAfterRenderContext, createMiddlewareCont
9
9
  import { Logger } from "./libs/logger";
10
10
  import { RouteMatchManager } from "./libs/route";
11
11
  import { metrics as defaultMetrics } from "./libs/metrics";
12
+ import { defaultReporter } from "./libs/reporter";
12
13
  export var ReturnResponse = /* @__PURE__ */ function() {
13
14
  "use strict";
14
15
  function ReturnResponse2(body, status) {
@@ -91,7 +92,7 @@ export var createHandler = function(manifest) {
91
92
  routeMgr.reset(routes);
92
93
  return function() {
93
94
  var _ref = _async_to_generator(function(options) {
94
- var _page_serverHooks_afterMatch, _page_serverHooks, _page, request, loadableStats, routeManifest, url, pageMatch, entryName, page, logger, metrics, hookContext, afterMatchHookContext, _page_serverHooks1, _page_serverHooks_afterRender, _page_serverHooks2, middlewarsHookContext, responseLike, params, baseUrl, serverRenderContext, body, afterRenderHookContext, e;
95
+ var _page_serverHooks_afterMatch, _page_serverHooks, _page, request, loadableStats, routeManifest, url, pageMatch, entryName, page, logger, metrics, reporter, hookContext, afterMatchHookContext, _page_serverHooks1, _page_serverHooks_afterRender, _page_serverHooks2, middlewarsHookContext, responseLike, params, baseUrl, serverRenderContext, body, afterRenderHookContext, e;
95
96
  function createServerRequest(url2, baseUrl2, request2, params2) {
96
97
  var pathname = url2.pathname, host = url2.host, searchParams = url2.searchParams;
97
98
  var rawHeaders = request2.headers;
@@ -128,7 +129,8 @@ export var createHandler = function(manifest) {
128
129
  level: "warn"
129
130
  });
130
131
  metrics = defaultMetrics;
131
- hookContext = createWorkerHookContext(request.url, logger, metrics);
132
+ reporter = defaultReporter;
133
+ hookContext = createWorkerHookContext(request.url, logger, metrics, reporter);
132
134
  afterMatchHookContext = createAfterMatchContext(hookContext, entryName);
133
135
  (_page = page) === null || _page === void 0 ? void 0 : (_page_serverHooks = _page.serverHooks) === null || _page_serverHooks === void 0 ? void 0 : (_page_serverHooks_afterMatch = _page_serverHooks.afterMatch) === null || _page_serverHooks_afterMatch === void 0 ? void 0 : _page_serverHooks_afterMatch.call(_page_serverHooks, afterMatchHookContext, function() {
134
136
  return void 0;
@@ -182,9 +184,15 @@ export var createHandler = function(manifest) {
182
184
  template: page.template,
183
185
  entryName: page.entryName,
184
186
  logger: logger,
187
+ reporter: defaultReporter,
185
188
  metrics: metrics,
186
189
  // FIXME: pass correctly req & res
187
190
  req: request,
191
+ serverTiming: {
192
+ addServeTiming: function addServeTiming() {
193
+ return this;
194
+ }
195
+ },
188
196
  res: responseLike
189
197
  };
190
198
  return [
@@ -236,7 +244,7 @@ function createResponse(template) {
236
244
  return RESPONSE_NOTFOUND;
237
245
  }
238
246
  }
239
- function createWorkerHookContext(url, logger, metrics) {
247
+ function createWorkerHookContext(url, logger, metrics, reporter) {
240
248
  var _ref = [
241
249
  {
242
250
  headers: new Headers(),
@@ -250,7 +258,8 @@ function createWorkerHookContext(url, logger, metrics) {
250
258
  res: res,
251
259
  req: req,
252
260
  logger: logger,
253
- metrics: metrics
261
+ metrics: metrics,
262
+ reporter: reporter
254
263
  };
255
264
  }
256
265
  function applyMiddlewares(ctx, middleware) {
@@ -4,6 +4,9 @@ import qs from "querystring";
4
4
  import { Buffer } from "buffer";
5
5
  import createEtag from "etag";
6
6
  import fresh from "fresh";
7
+ import { cutNameByHyphen } from "@modern-js/utils";
8
+ import { ServerTiming } from "../serverTiming";
9
+ import { defaultReporter } from "../reporter";
7
10
  import { headersWithoutCookie } from "../../utils";
8
11
  const MOCK_URL_BASE = "https://modernjs.dev/";
9
12
  export class ModernServerContext {
@@ -149,15 +152,18 @@ export class ModernServerContext {
149
152
  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, headersWithoutCookie(this.headers));
150
153
  }
151
154
  constructor(req, res, options) {
155
+ var _options;
152
156
  _define_property(this, "req", void 0);
153
157
  _define_property(this, "res", void 0);
154
158
  _define_property(this, "params", {});
155
- _define_property(this, "serverData", void 0);
159
+ _define_property(this, "reporter", defaultReporter);
160
+ _define_property(this, "serverTiming", void 0);
161
+ _define_property(this, "serverData", {});
156
162
  _define_property(this, "options", {});
157
163
  this.req = req;
158
164
  this.res = res;
159
165
  this.options = options || {};
160
- this.serverData = {};
166
+ this.serverTiming = new ServerTiming(res, cutNameByHyphen(((_options = options) === null || _options === void 0 ? void 0 : _options.metaName) || "modern-js"));
161
167
  this.bind();
162
168
  }
163
169
  }
@@ -2,10 +2,11 @@ import { RouteAPI } from "./route";
2
2
  import { TemplateAPI } from "./template";
3
3
  import { BaseRequest, BaseResponse } from "./base";
4
4
  export const base = (context) => {
5
- const { res } = context;
5
+ const { res, reporter } = context;
6
6
  return {
7
7
  response: new BaseResponse(res),
8
8
  request: new BaseRequest(context),
9
+ reporter,
9
10
  logger: context.logger,
10
11
  metrics: context.metrics
11
12
  };
@@ -31,7 +31,7 @@ class ServerResponse {
31
31
  }
32
32
  }
33
33
  export const base = (context) => {
34
- const { req, res, logger, metrics } = context;
34
+ const { req, res, logger, metrics, reporter } = context;
35
35
  const serverResponse = new ServerResponse(res);
36
36
  const { host, pathname, searchParams } = new URL(req.url);
37
37
  const headers = {};
@@ -40,6 +40,7 @@ export const base = (context) => {
40
40
  });
41
41
  return {
42
42
  response: new BaseResponse(serverResponse),
43
+ reporter,
43
44
  request: new BaseRequest({
44
45
  url: req.url,
45
46
  host,
@@ -11,7 +11,6 @@ export const render = async (ctx, renderOptions, runner) => {
11
11
  const loadableStats = fs.existsSync(loadableUri) ? require(loadableUri) : "";
12
12
  const routesManifestUri = path.join(distDir, ROUTE_MANIFEST_FILE);
13
13
  const routeManifest = fs.existsSync(routesManifestUri) ? require(routesManifestUri) : void 0;
14
- const body = await getRequestBody(ctx.req);
15
14
  const context = {
16
15
  request: {
17
16
  baseUrl: urlPath,
@@ -21,7 +20,7 @@ export const render = async (ctx, renderOptions, runner) => {
21
20
  query: ctx.query,
22
21
  url: ctx.href,
23
22
  headers: ctx.headers,
24
- body
23
+ body: ctx.req.body
25
24
  },
26
25
  response: {
27
26
  setHeader: (key, value) => {
@@ -40,6 +39,8 @@ export const render = async (ctx, renderOptions, runner) => {
40
39
  staticGenerate,
41
40
  logger: void 0,
42
41
  metrics: void 0,
42
+ reporter: ctx.reporter,
43
+ serverTiming: ctx.serverTiming,
43
44
  req: ctx.req,
44
45
  res: ctx.res,
45
46
  enableUnsafeCtx,
@@ -73,20 +74,3 @@ export const render = async (ctx, renderOptions, runner) => {
73
74
  };
74
75
  }
75
76
  };
76
- const getRequestBody = (req) => new Promise((resolve, reject) => {
77
- var _req;
78
- if (((_req = req) === null || _req === void 0 ? void 0 : _req.method) && req.method.toLowerCase() !== "get") {
79
- let body = "";
80
- req.on("data", (chunk) => {
81
- body += chunk.toString();
82
- });
83
- req.on("end", () => {
84
- resolve(body);
85
- });
86
- req.on("error", (err) => {
87
- reject(err);
88
- });
89
- } else {
90
- resolve(void 0);
91
- }
92
- });
@@ -0,0 +1,12 @@
1
+ export const defaultReporter = {
2
+ init() {
3
+ },
4
+ reportError() {
5
+ },
6
+ reportTiming() {
7
+ },
8
+ reportInfo() {
9
+ },
10
+ reportWarn() {
11
+ }
12
+ };
@@ -0,0 +1,17 @@
1
+ import { _ as _define_property } from "@swc/helpers/_/_define_property";
2
+ const SERVER_TIMING = "Server-Timing";
3
+ export class ServerTiming {
4
+ addServeTiming(name, dur, desc) {
5
+ const _name = `bd-${this.meta}-${name}`;
6
+ const serverTiming = this.res.getHeader(SERVER_TIMING) || this.res.getHeader(SERVER_TIMING.toLocaleLowerCase());
7
+ const value = `${_name};${desc ? `decs="${desc}";` : ""} dur=${dur}`;
8
+ this.res.setHeader(SERVER_TIMING, serverTiming ? `${serverTiming}, ${value}` : value);
9
+ return this;
10
+ }
11
+ constructor(res, meta) {
12
+ _define_property(this, "meta", void 0);
13
+ _define_property(this, "res", void 0);
14
+ this.meta = meta;
15
+ this.res = res;
16
+ }
17
+ }
@@ -2,10 +2,11 @@ import { _ as _define_property } from "@swc/helpers/_/_define_property";
2
2
  import { createServer } from "http";
3
3
  import path from "path";
4
4
  import { fs, isPromise, isWebOnly, mime, ROUTE_SPEC_FILE } from "@modern-js/utils";
5
+ import { time } from "@modern-js/utils/universal/time";
5
6
  import { RouteMatchManager } from "../libs/route";
6
7
  import { createRenderHandler } from "../libs/render";
7
8
  import { createStaticFileHandler, faviconFallbackHandler } from "../libs/serveFile";
8
- import { createErrorDocument, createMiddlewareCollecter, getStaticReg, mergeExtension, noop, debug, isRedirect } from "../utils";
9
+ import { createErrorDocument, createMiddlewareCollecter, getStaticReg, mergeExtension, noop, debug, isRedirect, bodyParser } from "../utils";
9
10
  import * as reader from "../libs/render/reader";
10
11
  import { createProxyHandler } from "../libs/proxy";
11
12
  import { createContext } from "../libs/context";
@@ -64,7 +65,9 @@ export class ModernServer {
64
65
  async render(req, res, url) {
65
66
  req.logger = req.logger || this.logger;
66
67
  req.metrics = req.metrics || this.metrics;
67
- const context = createContext(req, res);
68
+ const context = createContext(req, res, {
69
+ metaName: this.metaName
70
+ });
68
71
  const matched = this.router.match(url || context.path);
69
72
  if (!matched) {
70
73
  return null;
@@ -265,23 +268,35 @@ export class ModernServer {
265
268
  /* —————————————————————— private function —————————————————————— */
266
269
  // handler route.json, include api / csr / ssr
267
270
  async routeHandler(context) {
268
- const { res } = context;
271
+ const { res, req, reporter } = context;
269
272
  const matched = this.router.match(context.path);
270
273
  if (!matched) {
271
274
  this.render404(context);
272
275
  return;
273
276
  }
277
+ await reporter.init({
278
+ match: matched
279
+ });
280
+ const end = time();
281
+ res.on("finish", () => {
282
+ const cost = end();
283
+ reporter.reportTiming("server_handle_request", cost);
284
+ });
274
285
  let route = matched.generate(context.url);
275
286
  if (route.isApi) {
276
287
  await this.handleAPI(context);
277
288
  return;
278
289
  }
290
+ await bodyParser(req);
279
291
  if (route.entryName) {
280
292
  const afterMatchContext = createAfterMatchContext(context, route.entryName);
281
293
  if (this.runMode === RUN_MODE.FULL) {
294
+ const end2 = time();
282
295
  await this.runner.afterMatch(afterMatchContext, {
283
296
  onLast: noop
284
297
  });
298
+ const cost = end2();
299
+ reporter.reportTiming("server_hook_after_render", cost);
285
300
  }
286
301
  if (this.isSend(res)) {
287
302
  return;
@@ -303,7 +318,10 @@ export class ModernServer {
303
318
  if (this.frameWebHandler) {
304
319
  res.locals = res.locals || {};
305
320
  const middlewareContext = createMiddlewareContext(context);
321
+ const end2 = time();
306
322
  await this.frameWebHandler(middlewareContext);
323
+ const cost = end2();
324
+ reporter.reportTiming("server_middleware", cost);
307
325
  res.locals = {
308
326
  ...res.locals,
309
327
  ...middlewareContext.response.locals
@@ -325,9 +343,12 @@ export class ModernServer {
325
343
  if (route.entryName) {
326
344
  const afterRenderContext = createAfterRenderContext(context, response.toString());
327
345
  if (this.runMode === RUN_MODE.FULL) {
346
+ const end2 = time();
328
347
  await this.runner.afterRender(afterRenderContext, {
329
348
  onLast: noop
330
349
  });
350
+ const cost = end2();
351
+ reporter.reportTiming("server_hook_after_render", cost);
331
352
  }
332
353
  if (this.isSend(res)) {
333
354
  return;
@@ -119,3 +119,33 @@ export const isRedirect = (code) => {
119
119
  308
120
120
  ].includes(code);
121
121
  };
122
+ function parseBodyTypes(headers, body) {
123
+ switch (headers["content-type"]) {
124
+ case "application/json":
125
+ return JSON.parse(body);
126
+ default:
127
+ return body;
128
+ }
129
+ }
130
+ const getRequestBody = (req) => new Promise((resolve, reject) => {
131
+ var _req;
132
+ if (((_req = req) === null || _req === void 0 ? void 0 : _req.method) && req.method.toLowerCase() !== "get") {
133
+ let body = "";
134
+ req.on("data", (chunk) => {
135
+ body += chunk.toString();
136
+ });
137
+ req.on("end", () => {
138
+ resolve(parseBodyTypes(req.headers, body));
139
+ });
140
+ req.on("error", (err) => {
141
+ reject(err);
142
+ });
143
+ } else {
144
+ resolve(void 0);
145
+ }
146
+ });
147
+ export const bodyParser = async (req) => {
148
+ if (!req.body) {
149
+ req.body = await getRequestBody(req);
150
+ }
151
+ };
@@ -4,6 +4,7 @@ import { createAfterMatchContext, createAfterRenderContext, createMiddlewareCont
4
4
  import { Logger } from "./libs/logger";
5
5
  import { RouteMatchManager } from "./libs/route";
6
6
  import { metrics as defaultMetrics } from "./libs/metrics";
7
+ import { defaultReporter } from "./libs/reporter";
7
8
  export class ReturnResponse {
8
9
  /**
9
10
  * Iterate a Object
@@ -82,7 +83,8 @@ export const createHandler = (manifest) => {
82
83
  level: "warn"
83
84
  });
84
85
  const metrics = defaultMetrics;
85
- const hookContext = createWorkerHookContext(request.url, logger, metrics);
86
+ const reporter = defaultReporter;
87
+ const hookContext = createWorkerHookContext(request.url, logger, metrics, reporter);
86
88
  const afterMatchHookContext = createAfterMatchContext(hookContext, entryName);
87
89
  (_page = page) === null || _page === void 0 ? void 0 : (_page_serverHooks = _page.serverHooks) === null || _page_serverHooks === void 0 ? void 0 : (_page_serverHooks_afterMatch = _page_serverHooks.afterMatch) === null || _page_serverHooks_afterMatch === void 0 ? void 0 : _page_serverHooks_afterMatch.call(_page_serverHooks, afterMatchHookContext, () => void 0);
88
90
  if (checkIsSent(hookContext)) {
@@ -118,9 +120,15 @@ export const createHandler = (manifest) => {
118
120
  template: page.template,
119
121
  entryName: page.entryName,
120
122
  logger,
123
+ reporter: defaultReporter,
121
124
  metrics,
122
125
  // FIXME: pass correctly req & res
123
126
  req: request,
127
+ serverTiming: {
128
+ addServeTiming() {
129
+ return this;
130
+ }
131
+ },
124
132
  res: responseLike
125
133
  };
126
134
  const body = await page.serverRender(serverRenderContext);
@@ -165,7 +173,7 @@ function createResponse(template) {
165
173
  return RESPONSE_NOTFOUND;
166
174
  }
167
175
  }
168
- function createWorkerHookContext(url, logger, metrics) {
176
+ function createWorkerHookContext(url, logger, metrics, reporter) {
169
177
  const [res, req] = [
170
178
  {
171
179
  headers: new Headers(),
@@ -179,7 +187,8 @@ function createWorkerHookContext(url, logger, metrics) {
179
187
  res,
180
188
  req,
181
189
  logger,
182
- metrics
190
+ metrics,
191
+ reporter
183
192
  };
184
193
  }
185
194
  function applyMiddlewares(ctx, middleware) {
@@ -2,11 +2,12 @@
2
2
  /// <reference types="node" />
3
3
  /// <reference types="node" />
4
4
  /// <reference types="node/http" />
5
- /// <reference types=".dts-temp/3ag51RGwEKkAOCZCey_Qe/src/type" />
5
+ /// <reference types=".dts-temp/rFczrZA4GO714tUiIeLuz/src/type" />
6
6
  import { IncomingMessage, ServerResponse } from 'http';
7
7
  import qs from 'querystring';
8
- import type { ModernServerContext as ModernServerContextInterface } from '@modern-js/types';
8
+ import type { ModernServerContext as ModernServerContextInterface, Reporter as ModernServerReporter, ServerTiming as ModernServerTiming } from '@modern-js/types';
9
9
  export type ContextOptions = {
10
+ metaName?: string;
10
11
  etag?: boolean;
11
12
  };
12
13
  type ResponseBody = string | Buffer;
@@ -23,6 +24,8 @@ export declare class ModernServerContext implements ModernServerContextInterface
23
24
  * url params
24
25
  */
25
26
  params: Record<string, string>;
27
+ reporter: ModernServerReporter;
28
+ serverTiming: ModernServerTiming;
26
29
  get logger(): import("@modern-js/types").Logger;
27
30
  get metrics(): import("@modern-js/types").Metrics;
28
31
  serverData: Record<string, any>;
@@ -1,4 +1,4 @@
1
- import { AfterMatchContext, AfterRenderContext, HookContext, Logger, Metrics, MiddlewareContext } from '@modern-js/types/server';
1
+ import { AfterMatchContext, AfterRenderContext, HookContext, Logger, Metrics, MiddlewareContext, Reporter } from '@modern-js/types/server';
2
2
  export interface WorkerResponse {
3
3
  headers: Headers;
4
4
  status: number;
@@ -10,6 +10,7 @@ export interface WorkerServerContext {
10
10
  res: WorkerResponse;
11
11
  req: Request;
12
12
  logger: Logger;
13
+ reporter: Reporter;
13
14
  metrics: Metrics;
14
15
  }
15
16
  export declare const base: (context: WorkerServerContext) => HookContext;