@modern-js/server 1.1.4 → 1.1.5-beta.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 (40) hide show
  1. package/dist/js/modern/libs/context/context.js +15 -7
  2. package/dist/js/modern/libs/context/index.js +2 -2
  3. package/dist/js/modern/libs/{measure.js → metrics.js} +2 -2
  4. package/dist/js/modern/libs/render/index.js +6 -2
  5. package/dist/js/modern/libs/render/ssr.js +3 -2
  6. package/dist/js/modern/libs/route/route.js +1 -1
  7. package/dist/js/modern/server/dev-server/dev-server.js +11 -2
  8. package/dist/js/modern/server/index.js +2 -2
  9. package/dist/js/modern/server/modern-server.js +9 -5
  10. package/dist/js/node/libs/context/context.js +15 -7
  11. package/dist/js/node/libs/context/index.js +2 -2
  12. package/dist/js/node/libs/{measure.js → metrics.js} +3 -3
  13. package/dist/js/node/libs/render/index.js +6 -2
  14. package/dist/js/node/libs/render/ssr.js +3 -2
  15. package/dist/js/node/libs/route/route.js +1 -1
  16. package/dist/js/node/server/dev-server/dev-server.js +11 -2
  17. package/dist/js/node/server/index.js +2 -2
  18. package/dist/js/node/server/modern-server.js +9 -5
  19. package/dist/types/libs/context/context.d.ts +5 -5
  20. package/dist/types/libs/context/index.d.ts +3 -3
  21. package/dist/types/libs/metrics.d.ts +3 -0
  22. package/dist/types/libs/render/index.d.ts +10 -1
  23. package/dist/types/libs/render/ssr.d.ts +2 -1
  24. package/dist/types/libs/render/type.d.ts +2 -21
  25. package/dist/types/libs/route/route.d.ts +2 -10
  26. package/dist/types/server/modern-server.d.ts +3 -3
  27. package/dist/types/type.d.ts +6 -5
  28. package/package.json +19 -18
  29. package/src/libs/context/context.ts +12 -8
  30. package/src/libs/context/index.ts +3 -3
  31. package/src/libs/{measure.ts → metrics.ts} +3 -3
  32. package/src/libs/render/index.ts +21 -11
  33. package/src/libs/render/ssr.ts +5 -1
  34. package/src/libs/render/type.ts +3 -16
  35. package/src/libs/route/route.ts +4 -20
  36. package/src/server/dev-server/dev-server.ts +8 -2
  37. package/src/server/index.ts +2 -2
  38. package/src/server/modern-server.ts +10 -6
  39. package/src/type.ts +7 -5
  40. package/dist/types/libs/measure.d.ts +0 -3
@@ -15,17 +15,29 @@ export class ModernServerContext {
15
15
  */
16
16
  constructor(req, res, {
17
17
  logger,
18
- measure
18
+ metrics
19
19
  }) {
20
20
  this.req = void 0;
21
21
  this.res = void 0;
22
22
  this.params = {};
23
23
  this.logger = void 0;
24
- this.measure = void 0;
24
+ this.metrics = void 0;
25
25
  this.req = req;
26
26
  this.res = res;
27
27
  this.logger = logger;
28
- this.measure = measure;
28
+ this.metrics = metrics;
29
+ this.bind();
30
+ }
31
+
32
+ bind() {
33
+ const {
34
+ req,
35
+ res
36
+ } = this;
37
+
38
+ req.get = key => this.getReqHeader(key);
39
+
40
+ res.set = (key, value) => this.res.setHeader(key, value);
29
41
  }
30
42
 
31
43
  setParams(params) {
@@ -54,10 +66,6 @@ export class ModernServerContext {
54
66
  return this.req.headers;
55
67
  }
56
68
 
57
- set headers(val) {
58
- this.req.headers = val;
59
- }
60
-
61
69
  get method() {
62
70
  return this.req.method;
63
71
  }
@@ -1,9 +1,9 @@
1
1
  import { ModernServerContext } from "./context";
2
2
  export const createContext = (req, res, {
3
3
  logger,
4
- measure
4
+ metrics
5
5
  }) => new ModernServerContext(req, res, {
6
6
  logger,
7
- measure
7
+ metrics
8
8
  });
9
9
  export { ModernServerContext };
@@ -1,4 +1,4 @@
1
- const measure = {
1
+ const metrics = {
2
2
  gauges() {// no impl
3
3
  },
4
4
 
@@ -9,4 +9,4 @@ const measure = {
9
9
  }
10
10
 
11
11
  };
12
- export { measure };
12
+ export { metrics };
@@ -9,7 +9,11 @@ import { ERROR_DIGEST } from "../../constants";
9
9
  export const createRenderHandler = ({
10
10
  distDir,
11
11
  staticGenerate
12
- }) => async function render(ctx, route) {
12
+ }) => async function render({
13
+ ctx,
14
+ route,
15
+ runner
16
+ }) {
13
17
  if (ctx.resHasHandled()) {
14
18
  return null;
15
19
  }
@@ -39,7 +43,7 @@ export const createRenderHandler = ({
39
43
  bundle: route.bundle,
40
44
  template: templateHTML,
41
45
  staticGenerate
42
- });
46
+ }, runner);
43
47
  return result;
44
48
  } catch (err) {
45
49
  ctx.error(ERROR_DIGEST.ERENDER, err.stack);
@@ -2,7 +2,7 @@ import path from 'path';
2
2
  import { SERVER_RENDER_FUNCTION_NAME } from '@modern-js/utils';
3
3
  import mime from 'mime-types';
4
4
  import cache from "./cache";
5
- export const render = async (ctx, renderOptions) => {
5
+ export const render = async (ctx, renderOptions, runner) => {
6
6
  const {
7
7
  bundle,
8
8
  distDir,
@@ -25,8 +25,9 @@ export const render = async (ctx, renderOptions) => {
25
25
  distDir,
26
26
  staticGenerate,
27
27
  logger: ctx.logger,
28
- measure: ctx.measure
28
+ metrics: ctx.metrics
29
29
  };
30
+ runner.extendSSRContext(context);
30
31
 
31
32
  const serverRender = require(bundleJS)[SERVER_RENDER_FUNCTION_NAME];
32
33
 
@@ -10,7 +10,7 @@ export class ModernRoute {
10
10
  this.isSSR = void 0;
11
11
  this.isSPA = void 0;
12
12
  this.enableModernMode = void 0;
13
- this.entryName = routeSpec.entryName;
13
+ this.entryName = routeSpec.entryName || '';
14
14
  this.urlPath = routeSpec.urlPath;
15
15
  this.entryPath = routeSpec.entryPath || '';
16
16
  this.isSSR = routeSpec.isSSR || false;
@@ -1,3 +1,9 @@
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
2
+
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
+
5
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
+
1
7
  import { createServer } from 'http';
2
8
  import path from 'path';
3
9
  import { createServer as createHttpsServer } from 'https';
@@ -25,6 +31,7 @@ const DEFAULT_DEV_OPTIONS = {
25
31
  dev: {
26
32
  writeToDisk: true
27
33
  },
34
+ watch: true,
28
35
  hot: true,
29
36
  liveReload: true
30
37
  };
@@ -41,7 +48,7 @@ export class ModernDevServer extends ModernServer {
41
48
  this.devMiddleware = void 0;
42
49
  this.compiler = options.compiler; // set dev server options, like webpack-dev-server
43
50
 
44
- this.dev = typeof options.dev === 'boolean' ? DEFAULT_DEV_OPTIONS : options.dev;
51
+ this.dev = typeof options.dev === 'boolean' ? DEFAULT_DEV_OPTIONS : _objectSpread(_objectSpread({}, DEFAULT_DEV_OPTIONS), options.dev);
45
52
  enableRegister(this.pwd, this.conf);
46
53
  } // Complete the preparation of services
47
54
 
@@ -90,7 +97,9 @@ export class ModernDevServer extends ModernServer {
90
97
 
91
98
  await super.init(runner); // watch mock/ server/ api/ dir file change
92
99
 
93
- this.startWatcher();
100
+ if (this.dev.watch) {
101
+ this.startWatcher();
102
+ }
94
103
  }
95
104
 
96
105
  ready(options = {}) {
@@ -10,7 +10,7 @@ import { logger as defaultLogger } from '@modern-js/utils';
10
10
  import { AppContext, initAppContext, initAppDir, loadUserConfig, ConfigContext } from '@modern-js/core';
11
11
  import { ModernServer } from "./modern-server";
12
12
  import { ModernAPIServer, ModernSSRServer, ModernWebServer } from "./modern-server-split";
13
- import { measure as defaultMeasure } from "../libs/measure";
13
+ import { metrics as defaultMetrics } from "../libs/metrics";
14
14
  export class Server {
15
15
  constructor(options) {
16
16
  this.options = void 0;
@@ -36,7 +36,7 @@ export class Server {
36
36
  options
37
37
  } = this;
38
38
  options.logger = options.logger || defaultLogger;
39
- options.measure = options.measure || defaultMeasure; // initialize server
39
+ options.metrics = options.metrics || defaultMetrics; // initialize server
40
40
 
41
41
  if (options.dev) {
42
42
  this.server = this.createDevServer();
@@ -41,7 +41,7 @@ export class ModernServer {
41
41
  routes,
42
42
  staticGenerate,
43
43
  logger,
44
- measure,
44
+ metrics,
45
45
  proxyTarget
46
46
  }) {
47
47
  this.pwd = void 0;
@@ -53,7 +53,7 @@ export class ModernServer {
53
53
  this.presetRoutes = void 0;
54
54
  this.runner = void 0;
55
55
  this.logger = void 0;
56
- this.measure = void 0;
56
+ this.metrics = void 0;
57
57
  this.proxyTarget = void 0;
58
58
  this.isDev = false;
59
59
  this.staticFileHandler = void 0;
@@ -72,7 +72,7 @@ export class ModernServer {
72
72
  this.workDir = this.isDev ? pwd : this.distDir;
73
73
  this.conf = config;
74
74
  this.logger = logger;
75
- this.measure = measure;
75
+ this.metrics = metrics;
76
76
  this.router = new RouteMatchManager();
77
77
  this.presetRoutes = routes;
78
78
  this.proxyTarget = proxyTarget;
@@ -313,7 +313,11 @@ export class ModernServer {
313
313
  }
314
314
 
315
315
  async handleWeb(context, route) {
316
- return this.routeRenderHandler(context, route);
316
+ return this.routeRenderHandler({
317
+ ctx: context,
318
+ route,
319
+ runner: this.runner
320
+ });
317
321
  }
318
322
 
319
323
  verifyMatch(_c, _m) {// empty
@@ -522,7 +526,7 @@ export class ModernServer {
522
526
  res.statusCode = 200;
523
527
  const context = createContext(req, res, {
524
528
  logger: this.logger,
525
- measure: this.measure
529
+ metrics: this.metrics
526
530
  });
527
531
 
528
532
  try {
@@ -27,17 +27,29 @@ class ModernServerContext {
27
27
  */
28
28
  constructor(req, res, {
29
29
  logger,
30
- measure
30
+ metrics
31
31
  }) {
32
32
  this.req = void 0;
33
33
  this.res = void 0;
34
34
  this.params = {};
35
35
  this.logger = void 0;
36
- this.measure = void 0;
36
+ this.metrics = void 0;
37
37
  this.req = req;
38
38
  this.res = res;
39
39
  this.logger = logger;
40
- this.measure = measure;
40
+ this.metrics = metrics;
41
+ this.bind();
42
+ }
43
+
44
+ bind() {
45
+ const {
46
+ req,
47
+ res
48
+ } = this;
49
+
50
+ req.get = key => this.getReqHeader(key);
51
+
52
+ res.set = (key, value) => this.res.setHeader(key, value);
41
53
  }
42
54
 
43
55
  setParams(params) {
@@ -66,10 +78,6 @@ class ModernServerContext {
66
78
  return this.req.headers;
67
79
  }
68
80
 
69
- set headers(val) {
70
- this.req.headers = val;
71
- }
72
-
73
81
  get method() {
74
82
  return this.req.method;
75
83
  }
@@ -15,10 +15,10 @@ var _context = require("./context");
15
15
 
16
16
  const createContext = (req, res, {
17
17
  logger,
18
- measure
18
+ metrics
19
19
  }) => new _context.ModernServerContext(req, res, {
20
20
  logger,
21
- measure
21
+ metrics
22
22
  });
23
23
 
24
24
  exports.createContext = createContext;
@@ -3,8 +3,8 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.measure = void 0;
7
- const measure = {
6
+ exports.metrics = void 0;
7
+ const metrics = {
8
8
  gauges() {// no impl
9
9
  },
10
10
 
@@ -15,4 +15,4 @@ const measure = {
15
15
  }
16
16
 
17
17
  };
18
- exports.measure = measure;
18
+ exports.metrics = metrics;
@@ -30,7 +30,11 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
30
30
  const createRenderHandler = ({
31
31
  distDir,
32
32
  staticGenerate
33
- }) => async function render(ctx, route) {
33
+ }) => async function render({
34
+ ctx,
35
+ route,
36
+ runner
37
+ }) {
34
38
  if (ctx.resHasHandled()) {
35
39
  return null;
36
40
  }
@@ -63,7 +67,7 @@ const createRenderHandler = ({
63
67
  bundle: route.bundle,
64
68
  template: templateHTML,
65
69
  staticGenerate
66
- });
70
+ }, runner);
67
71
  return result;
68
72
  } catch (err) {
69
73
  ctx.error(_constants.ERROR_DIGEST.ERENDER, err.stack);
@@ -15,7 +15,7 @@ var _cache = _interopRequireDefault(require("./cache"));
15
15
 
16
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
17
 
18
- const render = async (ctx, renderOptions) => {
18
+ const render = async (ctx, renderOptions, runner) => {
19
19
  const {
20
20
  bundle,
21
21
  distDir,
@@ -40,8 +40,9 @@ const render = async (ctx, renderOptions) => {
40
40
  distDir,
41
41
  staticGenerate,
42
42
  logger: ctx.logger,
43
- measure: ctx.measure
43
+ metrics: ctx.metrics
44
44
  };
45
+ runner.extendSSRContext(context);
45
46
 
46
47
  const serverRender = require(bundleJS)[_utils.SERVER_RENDER_FUNCTION_NAME];
47
48
 
@@ -17,7 +17,7 @@ class ModernRoute {
17
17
  this.isSSR = void 0;
18
18
  this.isSPA = void 0;
19
19
  this.enableModernMode = void 0;
20
- this.entryName = routeSpec.entryName;
20
+ this.entryName = routeSpec.entryName || '';
21
21
  this.urlPath = routeSpec.urlPath;
22
22
  this.entryPath = routeSpec.entryPath || '';
23
23
  this.isSSR = routeSpec.isSSR || false;
@@ -41,6 +41,12 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
41
41
 
42
42
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
43
43
 
44
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
45
+
46
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
47
+
48
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
49
+
44
50
  const DEFAULT_DEV_OPTIONS = {
45
51
  client: {
46
52
  port: '8080',
@@ -53,6 +59,7 @@ const DEFAULT_DEV_OPTIONS = {
53
59
  dev: {
54
60
  writeToDisk: true
55
61
  },
62
+ watch: true,
56
63
  hot: true,
57
64
  liveReload: true
58
65
  };
@@ -70,7 +77,7 @@ class ModernDevServer extends _modernServer.ModernServer {
70
77
  this.devMiddleware = void 0;
71
78
  this.compiler = options.compiler; // set dev server options, like webpack-dev-server
72
79
 
73
- this.dev = typeof options.dev === 'boolean' ? DEFAULT_DEV_OPTIONS : options.dev;
80
+ this.dev = typeof options.dev === 'boolean' ? DEFAULT_DEV_OPTIONS : _objectSpread(_objectSpread({}, DEFAULT_DEV_OPTIONS), options.dev);
74
81
  (0, _register.enableRegister)(this.pwd, this.conf);
75
82
  } // Complete the preparation of services
76
83
 
@@ -119,7 +126,9 @@ class ModernDevServer extends _modernServer.ModernServer {
119
126
 
120
127
  await super.init(runner); // watch mock/ server/ api/ dir file change
121
128
 
122
- this.startWatcher();
129
+ if (this.dev.watch) {
130
+ this.startWatcher();
131
+ }
123
132
  }
124
133
 
125
134
  ready(options = {}) {
@@ -17,7 +17,7 @@ var _modernServer = require("./modern-server");
17
17
 
18
18
  var _modernServerSplit = require("./modern-server-split");
19
19
 
20
- var _measure = require("../libs/measure");
20
+ var _metrics = require("../libs/metrics");
21
21
 
22
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
23
 
@@ -52,7 +52,7 @@ class Server {
52
52
  options
53
53
  } = this;
54
54
  options.logger = options.logger || _utils.logger;
55
- options.measure = options.measure || _measure.measure; // initialize server
55
+ options.metrics = options.metrics || _metrics.metrics; // initialize server
56
56
 
57
57
  if (options.dev) {
58
58
  this.server = this.createDevServer();
@@ -71,7 +71,7 @@ class ModernServer {
71
71
  routes,
72
72
  staticGenerate,
73
73
  logger,
74
- measure,
74
+ metrics,
75
75
  proxyTarget
76
76
  }) {
77
77
  this.pwd = void 0;
@@ -83,7 +83,7 @@ class ModernServer {
83
83
  this.presetRoutes = void 0;
84
84
  this.runner = void 0;
85
85
  this.logger = void 0;
86
- this.measure = void 0;
86
+ this.metrics = void 0;
87
87
  this.proxyTarget = void 0;
88
88
  this.isDev = false;
89
89
  this.staticFileHandler = void 0;
@@ -102,7 +102,7 @@ class ModernServer {
102
102
  this.workDir = this.isDev ? pwd : this.distDir;
103
103
  this.conf = config;
104
104
  this.logger = logger;
105
- this.measure = measure;
105
+ this.metrics = metrics;
106
106
  this.router = new _route.RouteMatchManager();
107
107
  this.presetRoutes = routes;
108
108
  this.proxyTarget = proxyTarget;
@@ -348,7 +348,11 @@ class ModernServer {
348
348
  }
349
349
 
350
350
  async handleWeb(context, route) {
351
- return this.routeRenderHandler(context, route);
351
+ return this.routeRenderHandler({
352
+ ctx: context,
353
+ route,
354
+ runner: this.runner
355
+ });
352
356
  }
353
357
 
354
358
  verifyMatch(_c, _m) {// empty
@@ -557,7 +561,7 @@ class ModernServer {
557
561
  res.statusCode = 200;
558
562
  const context = (0, _context.createContext)(req, res, {
559
563
  logger: this.logger,
560
- measure: this.measure
564
+ metrics: this.metrics
561
565
  });
562
566
 
563
567
  try {
@@ -2,7 +2,7 @@
2
2
  import { IncomingMessage, ServerResponse } from 'http';
3
3
  import { URL } from 'url';
4
4
  import qs from 'querystring';
5
- import type { ModernServerContext as ModernServerContextInterface, Measure, Logger } from '@modern-js/types/server';
5
+ import type { ModernServerContext as ModernServerContextInterface, Metrics, Logger } from '@modern-js/types/server';
6
6
  export declare class ModernServerContext implements ModernServerContextInterface {
7
7
  /**
8
8
  * http request
@@ -19,18 +19,18 @@ export declare class ModernServerContext implements ModernServerContextInterface
19
19
 
20
20
  params: Record<string, string>;
21
21
  logger: Logger;
22
- measure?: Measure;
22
+ metrics?: Metrics;
23
23
  constructor(req: IncomingMessage, res: ServerResponse, {
24
24
  logger,
25
- measure
25
+ metrics
26
26
  }: {
27
27
  logger: Logger;
28
- measure: Measure;
28
+ metrics: Metrics;
29
29
  });
30
+ private bind;
30
31
  setParams(params: Record<string, string>): void;
31
32
  getReqHeader(key: string): string | string[];
32
33
  get headers(): import("http").IncomingHttpHeaders;
33
- set headers(val: import("http").IncomingHttpHeaders);
34
34
  get method(): string;
35
35
  get url(): string;
36
36
  set url(val: string);
@@ -1,11 +1,11 @@
1
1
  import { IncomingMessage, ServerResponse } from 'http';
2
- import { Measure, Logger } from '../../type';
2
+ import { Metrics, Logger } from '../../type';
3
3
  import { ModernServerContext } from './context';
4
4
  export declare const createContext: (req: IncomingMessage, res: ServerResponse, {
5
5
  logger,
6
- measure
6
+ metrics
7
7
  }: {
8
8
  logger: Logger;
9
- measure: Measure;
9
+ metrics: Metrics;
10
10
  }) => ModernServerContext;
11
11
  export { ModernServerContext };
@@ -0,0 +1,3 @@
1
+ import { Metrics } from "../type.d";
2
+ declare const metrics: Metrics;
3
+ export { metrics };
@@ -1,10 +1,19 @@
1
1
  import { RenderResult } from '../../type';
2
2
  import { ModernRoute } from '../route';
3
3
  import { ModernServerContext } from '../context';
4
+ import { ServerHookRunner } from "../../type.d";
4
5
  export declare const createRenderHandler: ({
5
6
  distDir,
6
7
  staticGenerate
7
8
  }: {
8
9
  distDir: string;
9
10
  staticGenerate: boolean;
10
- }) => (ctx: ModernServerContext, route: ModernRoute) => Promise<RenderResult | null>;
11
+ }) => ({
12
+ ctx,
13
+ route,
14
+ runner
15
+ }: {
16
+ ctx: ModernServerContext;
17
+ route: ModernRoute;
18
+ runner: ServerHookRunner;
19
+ }) => Promise<RenderResult | null>;
@@ -1,9 +1,10 @@
1
1
  import { ModernServerContext } from '../context';
2
2
  import { RenderResult } from '../../type';
3
+ import { ServerHookRunner } from "../../type.d";
3
4
  export declare const render: (ctx: ModernServerContext, renderOptions: {
4
5
  distDir: string;
5
6
  bundle: string;
6
7
  template: string;
7
8
  entryName: string;
8
9
  staticGenerate: boolean;
9
- }) => Promise<RenderResult>;
10
+ }, runner: ServerHookRunner) => Promise<RenderResult>;
@@ -1,7 +1,5 @@
1
- /// <reference types="node" />
2
1
  /// <reference types="react" />
3
- import { IncomingHttpHeaders } from 'http';
4
- import { Measure, Logger } from '../../type';
2
+ import { BaseSSRServerContext } from '@modern-js/types/server';
5
3
  declare type MetaKeyMap = {
6
4
  header?: string[];
7
5
  query?: string[];
@@ -24,24 +22,7 @@ export declare enum RenderLevel {
24
22
  SERVER_PREFETCH = 1,
25
23
  SERVER_RENDER = 2,
26
24
  }
27
- export declare type SSRServerContext = {
28
- request: {
29
- params: Record<string, string>;
30
- pathname: string;
31
- query: Record<string, string>;
32
- headers: IncomingHttpHeaders;
33
- cookie?: string;
34
- };
35
- redirection: {
36
- url?: string;
37
- status?: number;
38
- };
39
- distDir: string;
40
- template: string;
41
- entryName: string;
42
- logger: Logger;
43
- measure?: Measure;
44
- loadableManifest?: string;
25
+ export declare type SSRServerContext = BaseSSRServerContext & {
45
26
  cacheConfig?: CacheConfig;
46
27
  staticGenerate?: boolean;
47
28
  };
@@ -1,13 +1,5 @@
1
- export interface ModernRouteInterface {
2
- entryName: string;
3
- urlPath: string;
4
- entryPath?: string;
5
- isSPA?: boolean;
6
- isSSR?: boolean;
7
- isApi?: boolean;
8
- bundle?: string;
9
- enableModernMode?: boolean;
10
- }
1
+ import { ServerRoute as ModernRouteInterface } from '@modern-js/types';
2
+ export type { ModernRouteInterface };
11
3
  export declare class ModernRoute implements ModernRouteInterface {
12
4
  entryName: string;
13
5
  urlPath: string;
@@ -2,7 +2,7 @@
2
2
  import { IncomingMessage, ServerResponse, Server } from 'http';
3
3
  import { Adapter, APIServerStartInput } from '@modern-js/server-plugin';
4
4
  import type { NormalizedConfig } from '@modern-js/core';
5
- import { ModernServerOptions, NextFunction, ServerHookRunner, Measure, Logger, ReadyOptions } from "../type.d";
5
+ import { ModernServerOptions, NextFunction, ServerHookRunner, Metrics, Logger, ReadyOptions } from "../type.d";
6
6
  import { RouteMatchManager, ModernRouteInterface, ModernRoute, RouteMatcher } from "../libs/route";
7
7
  import { mergeExtension } from "../utils.d";
8
8
  import { ModernServerContext } from "../libs/context";
@@ -19,7 +19,7 @@ export declare class ModernServer {
19
19
  protected presetRoutes?: ModernRouteInterface[];
20
20
  protected runner: ServerHookRunner;
21
21
  protected readonly logger: Logger;
22
- protected readonly measure: Measure;
22
+ protected readonly metrics: Metrics;
23
23
  protected readonly proxyTarget: ModernServerOptions['proxyTarget'];
24
24
  private readonly isDev;
25
25
  private staticFileHandler;
@@ -36,7 +36,7 @@ export declare class ModernServer {
36
36
  routes,
37
37
  staticGenerate,
38
38
  logger,
39
- measure,
39
+ metrics,
40
40
  proxyTarget
41
41
  }: ModernServerOptions);
42
42
  getRequestHandler(): (req: IncomingMessage, res: ServerResponse, next?: () => void) => void;
@@ -2,7 +2,7 @@
2
2
  import type Webpack from 'webpack';
3
3
  import { serverManager } from '@modern-js/server-plugin';
4
4
  import type { NormalizedConfig } from '@modern-js/core';
5
- import type { Measure, Logger, NextFunction } from '@modern-js/types/server';
5
+ import type { Metrics, Logger, NextFunction } from '@modern-js/types/server';
6
6
  import { ModernRouteInterface } from './libs/route';
7
7
  declare module '@modern-js/core' {
8
8
  interface UserConfig {
@@ -23,6 +23,7 @@ export declare type DevServerOptions = {
23
23
  dev: {
24
24
  writeToDisk: boolean | ((filename: string) => boolean);
25
25
  };
26
+ watch: boolean;
26
27
  hot: boolean | string;
27
28
  liveReload: boolean;
28
29
  https?: boolean | {
@@ -35,15 +36,15 @@ export declare type ModernServerOptions = {
35
36
  pwd: string;
36
37
  config: NormalizedConfig;
37
38
  plugins?: any[];
38
- dev?: boolean | DevServerOptions;
39
+ dev?: boolean | Partial<DevServerOptions>;
39
40
  compiler?: Webpack.MultiCompiler | Webpack.Compiler;
40
41
  routes?: ModernRouteInterface[];
41
42
  staticGenerate?: boolean;
42
43
  customServer?: boolean;
43
44
  loggerOptions?: Record<string, string>;
44
- measureOptions?: Record<string, string>;
45
+ metricsOptions?: Record<string, string>;
45
46
  logger?: Logger;
46
- measure?: Measure;
47
+ metrics?: Metrics;
47
48
  apiOnly?: boolean;
48
49
  ssrOnly?: boolean;
49
50
  webOnly?: boolean;
@@ -68,4 +69,4 @@ export declare type ServerHookRunner = Then<ReturnType<typeof serverManager.init
68
69
  export declare type ReadyOptions = {
69
70
  routes?: ModernRouteInterface[];
70
71
  };
71
- export type { Measure, Logger, NextFunction };
72
+ export type { Metrics, Logger, NextFunction };
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "modern",
12
12
  "modern.js"
13
13
  ],
14
- "version": "1.1.4",
14
+ "version": "1.1.5-beta.0",
15
15
  "jsnext:source": "./src/index.ts",
16
16
  "types": "./dist/types/index.d.ts",
17
17
  "main": "./dist/js/node/index.js",
@@ -26,6 +26,14 @@
26
26
  "default": "./dist/js/treeshaking/index.js"
27
27
  }
28
28
  },
29
+ "scripts": {
30
+ "prepare": "pnpm build",
31
+ "prepublishOnly": "pnpm build --platform",
32
+ "new": "modern new",
33
+ "build": "modern build",
34
+ "dev": "modern build --watch",
35
+ "test": "modern test --passWithNoTests"
36
+ },
29
37
  "dependencies": {
30
38
  "@babel/core": "^7.15.0",
31
39
  "@babel/compat-data": "^7.15.0",
@@ -33,12 +41,12 @@
33
41
  "@babel/preset-typescript": "^7.15.0",
34
42
  "@babel/register": "^7.15.3",
35
43
  "@babel/runtime": "^7",
36
- "@modern-js/core": "^1.1.4",
37
- "@modern-js/hmr-client": "^1.1.1",
38
- "@modern-js/server-plugin": "^1.1.2",
39
- "@modern-js/server-utils": "^1.1.2",
40
- "@modern-js/bff-utils": "^1.1.1",
41
- "@modern-js/utils": "^1.1.4",
44
+ "@modern-js/core": "workspace:^1.1.4",
45
+ "@modern-js/hmr-client": "workspace:^1.1.1",
46
+ "@modern-js/server-plugin": "workspace:^1.1.2",
47
+ "@modern-js/server-utils": "workspace:^1.1.2",
48
+ "@modern-js/bff-utils": "workspace:^1.1.1",
49
+ "@modern-js/utils": "workspace:^1.1.4",
42
50
  "axios": "^0.21.4",
43
51
  "babel-plugin-module-resolver": "^4.1.0",
44
52
  "chokidar": "^3.5.2",
@@ -61,9 +69,9 @@
61
69
  "ws": "^8.2.0"
62
70
  },
63
71
  "devDependencies": {
64
- "@modern-js/module-tools": "^1.1.1",
72
+ "@modern-js/module-tools": "^1.1.2",
65
73
  "@modern-js/plugin-testing": "^1.1.1",
66
- "@modern-js/types": "^1.1.3",
74
+ "@modern-js/types": "workspace:^1.1.3",
67
75
  "@types/jest": "^26",
68
76
  "@types/lru-cache": "^5.1.1",
69
77
  "@types/mime-types": "^2.1.0",
@@ -92,12 +100,5 @@
92
100
  "publishConfig": {
93
101
  "registry": "https://registry.npmjs.org/",
94
102
  "access": "public"
95
- },
96
- "scripts": {
97
- "new": "modern new",
98
- "build": "modern build",
99
- "dev": "modern build --watch",
100
- "test": "modern test --passWithNoTests"
101
- },
102
- "readme": "\n<p align=\"center\">\n <a href=\"https://modernjs.dev\" target=\"blank\"><img src=\"https://lf3-static.bytednsdoc.com/obj/eden-cn/ylaelkeh7nuhfnuhf/modernjs-cover.png\" width=\"300\" alt=\"Modern.js Logo\" /></a>\n</p>\n<p align=\"center\">\n现代 Web 工程体系\n <br/>\n <a href=\"https://modernjs.dev\" target=\"blank\">\n modernjs.dev\n </a>\n</p>\n<p align=\"center\">\n The meta-framework suite designed from scratch for frontend-focused modern web development\n</p>\n\n# Introduction\n\n> The doc site ([modernjs.dev](https://modernjs.dev)) and articles are only available in Chinese for now, we are planning to add English versions soon.\n\n- [Modern.js: Hello, World!](https://zhuanlan.zhihu.com/p/426707646)\n\n## Getting Started\n\n- [Quick Start](https://modernjs.dev/docs/start)\n- [Guides](https://modernjs.dev/docs/guides)\n- [API References](https://modernjs.dev/docs/apis)\n\n## Contributing\n\n- [Contributing Guide](https://github.com/modern-js-dev/modern.js/blob/main/CONTRIBUTING.md)\n"
103
- }
103
+ }
104
+ }
@@ -3,7 +3,7 @@ import { URL } from 'url';
3
3
  import qs from 'querystring';
4
4
  import type {
5
5
  ModernServerContext as ModernServerContextInterface,
6
- Measure,
6
+ Metrics,
7
7
  Logger,
8
8
  } from '@modern-js/types/server';
9
9
  import { toMessage } from '../../utils';
@@ -26,17 +26,25 @@ export class ModernServerContext implements ModernServerContextInterface {
26
26
 
27
27
  public logger: Logger;
28
28
 
29
- public measure?: Measure;
29
+ public metrics?: Metrics;
30
30
 
31
31
  constructor(
32
32
  req: IncomingMessage,
33
33
  res: ServerResponse,
34
- { logger, measure }: { logger: Logger; measure: Measure },
34
+ { logger, metrics }: { logger: Logger; metrics: Metrics },
35
35
  ) {
36
36
  this.req = req;
37
37
  this.res = res;
38
38
  this.logger = logger;
39
- this.measure = measure;
39
+ this.metrics = metrics;
40
+
41
+ this.bind();
42
+ }
43
+
44
+ private bind() {
45
+ const { req, res } = this as any;
46
+ req.get = (key: string) => this.getReqHeader(key);
47
+ res.set = (key: string, value: any) => this.res.setHeader(key, value);
40
48
  }
41
49
 
42
50
  public setParams(params: Record<string, string>) {
@@ -60,10 +68,6 @@ export class ModernServerContext implements ModernServerContextInterface {
60
68
  return this.req.headers;
61
69
  }
62
70
 
63
- public set headers(val) {
64
- this.req.headers = val;
65
- }
66
-
67
71
  public get method(): string {
68
72
  return this.req.method!;
69
73
  }
@@ -1,11 +1,11 @@
1
1
  import { IncomingMessage, ServerResponse } from 'http';
2
- import { Measure, Logger } from '../../type';
2
+ import { Metrics, Logger } from '../../type';
3
3
  import { ModernServerContext } from './context';
4
4
 
5
5
  export const createContext = (
6
6
  req: IncomingMessage,
7
7
  res: ServerResponse,
8
- { logger, measure }: { logger: Logger; measure: Measure },
9
- ) => new ModernServerContext(req, res, { logger, measure });
8
+ { logger, metrics }: { logger: Logger; metrics: Metrics },
9
+ ) => new ModernServerContext(req, res, { logger, metrics });
10
10
 
11
11
  export { ModernServerContext };
@@ -1,6 +1,6 @@
1
- import { Measure } from '@/type';
1
+ import { Metrics } from '@/type';
2
2
 
3
- const measure: Measure = {
3
+ const metrics: Metrics = {
4
4
  gauges() {
5
5
  // no impl
6
6
  },
@@ -12,4 +12,4 @@ const measure: Measure = {
12
12
  },
13
13
  };
14
14
 
15
- export { measure };
15
+ export { metrics };
@@ -9,6 +9,7 @@ import { readFile } from './reader';
9
9
  import * as ssr from './ssr';
10
10
  import { supportModern, getModernEntry } from './modern';
11
11
  import { ERROR_DIGEST } from '@/constants';
12
+ import { ServerHookRunner } from '@/type';
12
13
 
13
14
  export const createRenderHandler = ({
14
15
  distDir,
@@ -17,10 +18,15 @@ export const createRenderHandler = ({
17
18
  distDir: string;
18
19
  staticGenerate: boolean;
19
20
  }) =>
20
- async function render(
21
- ctx: ModernServerContext,
22
- route: ModernRoute,
23
- ): Promise<RenderResult | null> {
21
+ async function render({
22
+ ctx,
23
+ route,
24
+ runner,
25
+ }: {
26
+ ctx: ModernServerContext;
27
+ route: ModernRoute;
28
+ runner: ServerHookRunner;
29
+ }): Promise<RenderResult | null> {
24
30
  if (ctx.resHasHandled()) {
25
31
  return null;
26
32
  }
@@ -43,13 +49,17 @@ export const createRenderHandler = ({
43
49
  // handles ssr first
44
50
  if (route.isSSR) {
45
51
  try {
46
- const result = await ssr.render(ctx, {
47
- distDir,
48
- entryName: route.entryName,
49
- bundle: route.bundle,
50
- template: templateHTML,
51
- staticGenerate,
52
- });
52
+ const result = await ssr.render(
53
+ ctx,
54
+ {
55
+ distDir,
56
+ entryName: route.entryName,
57
+ bundle: route.bundle,
58
+ template: templateHTML,
59
+ staticGenerate,
60
+ },
61
+ runner,
62
+ );
53
63
  return result;
54
64
  } catch (err) {
55
65
  ctx.error(ERROR_DIGEST.ERENDER, (err as Error).stack);
@@ -5,6 +5,7 @@ import { ModernServerContext } from '../context';
5
5
  import { RenderResult } from '../../type';
6
6
  import cache from './cache';
7
7
  import { SSRServerContext } from './type';
8
+ import { ServerHookRunner } from '@/type';
8
9
 
9
10
  export const render = async (
10
11
  ctx: ModernServerContext,
@@ -15,6 +16,7 @@ export const render = async (
15
16
  entryName: string;
16
17
  staticGenerate: boolean;
17
18
  },
19
+ runner: ServerHookRunner,
18
20
  ): Promise<RenderResult> => {
19
21
  const { bundle, distDir, template, entryName, staticGenerate } =
20
22
  renderOptions;
@@ -34,9 +36,11 @@ export const render = async (
34
36
  distDir,
35
37
  staticGenerate,
36
38
  logger: ctx.logger,
37
- measure: ctx.measure,
39
+ metrics: ctx.metrics,
38
40
  };
39
41
 
42
+ runner.extendSSRContext(context);
43
+
40
44
  const serverRender = require(bundleJS)[SERVER_RENDER_FUNCTION_NAME];
41
45
 
42
46
  const html = await cache(serverRender, ctx)(context);
@@ -1,5 +1,6 @@
1
1
  import { IncomingHttpHeaders } from 'http';
2
- import { Measure, Logger } from '../../type';
2
+ import { BaseSSRServerContext } from '@modern-js/types/server';
3
+ import { Metrics, Logger } from '../../type';
3
4
 
4
5
  type MetaKeyMap = {
5
6
  header?: string[];
@@ -26,21 +27,7 @@ export enum RenderLevel {
26
27
  SERVER_RENDER,
27
28
  }
28
29
 
29
- export type SSRServerContext = {
30
- request: {
31
- params: Record<string, string>;
32
- pathname: string;
33
- query: Record<string, string>;
34
- headers: IncomingHttpHeaders;
35
- cookie?: string;
36
- };
37
- redirection: { url?: string; status?: number };
38
- distDir: string;
39
- template: string;
40
- entryName: string;
41
- logger: Logger;
42
- measure?: Measure;
43
- loadableManifest?: string;
30
+ export type SSRServerContext = BaseSSRServerContext & {
44
31
  cacheConfig?: CacheConfig;
45
32
  staticGenerate?: boolean;
46
33
  };
@@ -1,22 +1,6 @@
1
- export interface ModernRouteInterface {
2
- // modern js web entry name
3
- entryName: string;
4
- // the url path for request match
5
- urlPath: string;
6
- // the default resource file to response to route
7
- entryPath?: string;
8
- // if route is spa page
9
- isSPA?: boolean;
10
- // if route is ssr page
11
- isSSR?: boolean;
12
- // if route is api service
13
- isApi?: boolean;
14
- // ssr js bundle for ssr page
15
- bundle?: string;
16
- // if route has modern product
17
- enableModernMode?: boolean;
18
- // specialHeader?: SpecialHeader[];
19
- }
1
+ import { ServerRoute as ModernRouteInterface } from '@modern-js/types';
2
+
3
+ export type { ModernRouteInterface };
20
4
 
21
5
  export class ModernRoute implements ModernRouteInterface {
22
6
  public entryName: string;
@@ -36,7 +20,7 @@ export class ModernRoute implements ModernRouteInterface {
36
20
  public enableModernMode?: boolean;
37
21
 
38
22
  constructor(routeSpec: ModernRouteInterface) {
39
- this.entryName = routeSpec.entryName;
23
+ this.entryName = routeSpec.entryName || '';
40
24
  this.urlPath = routeSpec.urlPath;
41
25
  this.entryPath = routeSpec.entryPath || '';
42
26
  this.isSSR = routeSpec.isSSR || false;
@@ -43,9 +43,11 @@ const DEFAULT_DEV_OPTIONS: DevServerOptions = {
43
43
  },
44
44
  https: false,
45
45
  dev: { writeToDisk: true },
46
+ watch: true,
46
47
  hot: true,
47
48
  liveReload: true,
48
49
  };
50
+
49
51
  export class ModernDevServer extends ModernServer {
50
52
  private devProxyHandler: ReturnType<typeof createProxyHandler> = null;
51
53
 
@@ -72,7 +74,9 @@ export class ModernDevServer extends ModernServer {
72
74
 
73
75
  // set dev server options, like webpack-dev-server
74
76
  this.dev =
75
- typeof options.dev === 'boolean' ? DEFAULT_DEV_OPTIONS : options.dev!;
77
+ typeof options.dev === 'boolean'
78
+ ? DEFAULT_DEV_OPTIONS
79
+ : { ...DEFAULT_DEV_OPTIONS, ...options.dev };
76
80
 
77
81
  enableRegister(this.pwd, this.conf);
78
82
  }
@@ -120,7 +124,9 @@ export class ModernDevServer extends ModernServer {
120
124
  await super.init(runner);
121
125
 
122
126
  // watch mock/ server/ api/ dir file change
123
- this.startWatcher();
127
+ if (this.dev.watch) {
128
+ this.startWatcher();
129
+ }
124
130
  }
125
131
 
126
132
  public ready(options: ReadyOptions = {}) {
@@ -18,7 +18,7 @@ import {
18
18
  ModernWebServer,
19
19
  } from './modern-server-split';
20
20
  import { ModernServerOptions, ServerHookRunner, ReadyOptions } from '@/type';
21
- import { measure as defaultMeasure } from '@/libs/measure';
21
+ import { metrics as defaultMetrics } from '@/libs/metrics';
22
22
 
23
23
  export class Server {
24
24
  public options: ModernServerOptions;
@@ -48,7 +48,7 @@ export class Server {
48
48
  const { options } = this;
49
49
 
50
50
  options.logger = options.logger || defaultLogger;
51
- options.measure = options.measure || defaultMeasure;
51
+ options.metrics = options.metrics || defaultMetrics;
52
52
 
53
53
  // initialize server
54
54
  if (options.dev) {
@@ -12,7 +12,7 @@ import {
12
12
  ModernServerOptions,
13
13
  NextFunction,
14
14
  ServerHookRunner,
15
- Measure,
15
+ Metrics,
16
16
  Logger,
17
17
  ReadyOptions,
18
18
  ConfWithBFF,
@@ -73,7 +73,7 @@ export class ModernServer {
73
73
 
74
74
  protected readonly logger: Logger;
75
75
 
76
- protected readonly measure: Measure;
76
+ protected readonly metrics: Metrics;
77
77
 
78
78
  protected readonly proxyTarget: ModernServerOptions['proxyTarget'];
79
79
 
@@ -100,7 +100,7 @@ export class ModernServer {
100
100
  routes,
101
101
  staticGenerate,
102
102
  logger,
103
- measure,
103
+ metrics,
104
104
  proxyTarget,
105
105
  }: ModernServerOptions) {
106
106
  require('ignore-styles');
@@ -111,7 +111,7 @@ export class ModernServer {
111
111
  this.workDir = this.isDev ? pwd : this.distDir;
112
112
  this.conf = config;
113
113
  this.logger = logger!;
114
- this.measure = measure!;
114
+ this.metrics = metrics!;
115
115
  this.router = new RouteMatchManager();
116
116
  this.presetRoutes = routes;
117
117
  this.proxyTarget = proxyTarget;
@@ -356,7 +356,11 @@ export class ModernServer {
356
356
  }
357
357
 
358
358
  protected async handleWeb(context: ModernServerContext, route: ModernRoute) {
359
- return this.routeRenderHandler(context, route);
359
+ return this.routeRenderHandler({
360
+ ctx: context,
361
+ route,
362
+ runner: this.runner,
363
+ });
360
364
  }
361
365
 
362
366
  protected verifyMatch(_c: ModernServerContext, _m: RouteMatcher) {
@@ -548,7 +552,7 @@ export class ModernServer {
548
552
  res.statusCode = 200;
549
553
  const context: ModernServerContext = createContext(req, res, {
550
554
  logger: this.logger,
551
- measure: this.measure,
555
+ metrics: this.metrics,
552
556
  });
553
557
 
554
558
  try {
package/src/type.ts CHANGED
@@ -2,7 +2,7 @@ import { Buffer } from 'buffer';
2
2
  import type Webpack from 'webpack';
3
3
  import { serverManager } from '@modern-js/server-plugin';
4
4
  import type { NormalizedConfig } from '@modern-js/core';
5
- import type { Measure, Logger, NextFunction } from '@modern-js/types/server';
5
+ import type { Metrics, Logger, NextFunction } from '@modern-js/types/server';
6
6
  import { ModernRouteInterface } from './libs/route';
7
7
 
8
8
  declare module '@modern-js/core' {
@@ -26,6 +26,8 @@ export type DevServerOptions = {
26
26
  dev: {
27
27
  writeToDisk: boolean | ((filename: string) => boolean);
28
28
  };
29
+ // 是否监听文件变化
30
+ watch: boolean;
29
31
  // 是否开启 hot reload
30
32
  hot: boolean | string;
31
33
  // 是否开启 page reload
@@ -39,15 +41,15 @@ export type ModernServerOptions = {
39
41
  pwd: string;
40
42
  config: NormalizedConfig;
41
43
  plugins?: any[];
42
- dev?: boolean | DevServerOptions;
44
+ dev?: boolean | Partial<DevServerOptions>;
43
45
  compiler?: Webpack.MultiCompiler | Webpack.Compiler;
44
46
  routes?: ModernRouteInterface[];
45
47
  staticGenerate?: boolean;
46
48
  customServer?: boolean;
47
49
  loggerOptions?: Record<string, string>;
48
- measureOptions?: Record<string, string>;
50
+ metricsOptions?: Record<string, string>;
49
51
  logger?: Logger;
50
- measure?: Measure;
52
+ metrics?: Metrics;
51
53
  apiOnly?: boolean;
52
54
  ssrOnly?: boolean;
53
55
  webOnly?: boolean;
@@ -76,4 +78,4 @@ export type ServerHookRunner = Then<ReturnType<typeof serverManager.init>>;
76
78
 
77
79
  export type ReadyOptions = { routes?: ModernRouteInterface[] };
78
80
 
79
- export type { Measure, Logger, NextFunction };
81
+ export type { Metrics, Logger, NextFunction };
@@ -1,3 +0,0 @@
1
- import { Measure } from "../type.d";
2
- declare const measure: Measure;
3
- export { measure };