@modern-js/prod-server 1.22.1 → 2.0.0-alpha.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 (132) hide show
  1. package/CHANGELOG.md +271 -17
  2. package/dist/js/modern/constants.js +32 -27
  3. package/dist/js/modern/index.js +11 -7
  4. package/dist/js/modern/libs/context/context.js +54 -132
  5. package/dist/js/modern/libs/context/index.js +5 -2
  6. package/dist/js/modern/libs/hook-api/index.js +134 -0
  7. package/dist/js/modern/libs/hook-api/route.js +13 -37
  8. package/dist/js/modern/libs/hook-api/template.js +41 -32
  9. package/dist/js/modern/libs/loadConfig.js +46 -32
  10. package/dist/js/modern/libs/metrics.js +6 -7
  11. package/dist/js/modern/libs/proxy.js +70 -44
  12. package/dist/js/modern/libs/render/cache/__tests__/cache.fun.test.js +112 -68
  13. package/dist/js/modern/libs/render/cache/__tests__/cache.test.js +246 -225
  14. package/dist/js/modern/libs/render/cache/__tests__/cacheable.js +43 -49
  15. package/dist/js/modern/libs/render/cache/__tests__/error-configuration.js +36 -34
  16. package/dist/js/modern/libs/render/cache/__tests__/matched-cache.js +83 -113
  17. package/dist/js/modern/libs/render/cache/index.js +93 -50
  18. package/dist/js/modern/libs/render/cache/page-caches/index.js +31 -8
  19. package/dist/js/modern/libs/render/cache/page-caches/lru.js +6 -16
  20. package/dist/js/modern/libs/render/cache/spr.js +133 -167
  21. package/dist/js/modern/libs/render/cache/type.js +0 -1
  22. package/dist/js/modern/libs/render/cache/util.js +71 -45
  23. package/dist/js/modern/libs/render/index.js +76 -61
  24. package/dist/js/modern/libs/render/measure.js +42 -34
  25. package/dist/js/modern/libs/render/reader.js +68 -76
  26. package/dist/js/modern/libs/render/ssr.js +63 -33
  27. package/dist/js/modern/libs/render/static.js +51 -37
  28. package/dist/js/modern/libs/render/type.js +9 -7
  29. package/dist/js/modern/libs/route/index.js +12 -30
  30. package/dist/js/modern/libs/route/matcher.js +28 -50
  31. package/dist/js/modern/libs/route/route.js +9 -31
  32. package/dist/js/modern/libs/serve-file.js +40 -20
  33. package/dist/js/modern/server/index.js +152 -168
  34. package/dist/js/modern/server/modern-server-split.js +44 -60
  35. package/dist/js/modern/server/modern-server.js +416 -526
  36. package/dist/js/modern/type.js +0 -1
  37. package/dist/js/modern/utils.js +62 -58
  38. package/dist/js/modern/worker-server.js +54 -0
  39. package/dist/js/node/constants.js +53 -32
  40. package/dist/js/node/index.js +37 -67
  41. package/dist/js/node/libs/context/context.js +84 -150
  42. package/dist/js/node/libs/context/index.js +28 -16
  43. package/dist/js/node/libs/hook-api/index.js +164 -0
  44. package/dist/js/node/libs/hook-api/route.js +35 -45
  45. package/dist/js/node/libs/hook-api/template.js +64 -40
  46. package/dist/js/node/libs/loadConfig.js +74 -55
  47. package/dist/js/node/libs/metrics.js +28 -12
  48. package/dist/js/node/libs/proxy.js +90 -55
  49. package/dist/js/node/libs/render/cache/__tests__/cache.fun.test.js +99 -61
  50. package/dist/js/node/libs/render/cache/__tests__/cache.test.js +147 -140
  51. package/dist/js/node/libs/render/cache/__tests__/cacheable.js +65 -55
  52. package/dist/js/node/libs/render/cache/__tests__/error-configuration.js +58 -40
  53. package/dist/js/node/libs/render/cache/__tests__/matched-cache.js +105 -119
  54. package/dist/js/node/libs/render/cache/index.js +115 -65
  55. package/dist/js/node/libs/render/cache/page-caches/index.js +54 -16
  56. package/dist/js/node/libs/render/cache/page-caches/lru.js +33 -26
  57. package/dist/js/node/libs/render/cache/spr.js +161 -188
  58. package/dist/js/node/libs/render/cache/type.js +15 -5
  59. package/dist/js/node/libs/render/cache/util.js +99 -63
  60. package/dist/js/node/libs/render/index.js +106 -87
  61. package/dist/js/node/libs/render/measure.js +61 -44
  62. package/dist/js/node/libs/render/reader.js +98 -100
  63. package/dist/js/node/libs/render/ssr.js +92 -58
  64. package/dist/js/node/libs/render/static.js +80 -53
  65. package/dist/js/node/libs/render/type.js +31 -13
  66. package/dist/js/node/libs/route/index.js +35 -44
  67. package/dist/js/node/libs/route/matcher.js +48 -65
  68. package/dist/js/node/libs/route/route.js +29 -37
  69. package/dist/js/node/libs/serve-file.js +74 -37
  70. package/dist/js/node/server/index.js +170 -203
  71. package/dist/js/node/server/modern-server-split.js +70 -73
  72. package/dist/js/node/server/modern-server.js +432 -577
  73. package/dist/js/node/type.js +15 -3
  74. package/dist/js/node/utils.js +87 -93
  75. package/dist/js/node/worker-server.js +77 -0
  76. package/dist/js/treeshaking/constants.js +29 -0
  77. package/dist/js/treeshaking/index.js +13 -0
  78. package/dist/js/treeshaking/libs/context/context.js +274 -0
  79. package/dist/js/treeshaking/libs/context/index.js +5 -0
  80. package/dist/js/treeshaking/libs/hook-api/index.js +281 -0
  81. package/dist/js/treeshaking/libs/hook-api/route.js +68 -0
  82. package/dist/js/treeshaking/libs/hook-api/template.js +127 -0
  83. package/dist/js/treeshaking/libs/loadConfig.js +82 -0
  84. package/dist/js/treeshaking/libs/metrics.js +6 -0
  85. package/dist/js/treeshaking/libs/proxy.js +244 -0
  86. package/dist/js/treeshaking/libs/render/cache/__tests__/cache.fun.test.js +291 -0
  87. package/dist/js/treeshaking/libs/render/cache/__tests__/cache.test.js +781 -0
  88. package/dist/js/treeshaking/libs/render/cache/__tests__/cacheable.js +67 -0
  89. package/dist/js/treeshaking/libs/render/cache/__tests__/error-configuration.js +45 -0
  90. package/dist/js/treeshaking/libs/render/cache/__tests__/matched-cache.js +147 -0
  91. package/dist/js/treeshaking/libs/render/cache/index.js +346 -0
  92. package/dist/js/treeshaking/libs/render/cache/page-caches/index.js +154 -0
  93. package/dist/js/treeshaking/libs/render/cache/page-caches/lru.js +84 -0
  94. package/dist/js/treeshaking/libs/render/cache/spr.js +492 -0
  95. package/dist/js/treeshaking/libs/render/cache/type.js +1 -0
  96. package/dist/js/treeshaking/libs/render/cache/util.js +280 -0
  97. package/dist/js/treeshaking/libs/render/index.js +233 -0
  98. package/dist/js/treeshaking/libs/render/measure.js +146 -0
  99. package/dist/js/treeshaking/libs/render/reader.js +339 -0
  100. package/dist/js/treeshaking/libs/render/ssr.js +223 -0
  101. package/dist/js/treeshaking/libs/render/static.js +216 -0
  102. package/dist/js/treeshaking/libs/render/type.js +7 -0
  103. package/dist/js/treeshaking/libs/route/index.js +130 -0
  104. package/dist/js/treeshaking/libs/route/matcher.js +138 -0
  105. package/dist/js/treeshaking/libs/route/route.js +40 -0
  106. package/dist/js/treeshaking/libs/serve-file.js +184 -0
  107. package/dist/js/treeshaking/server/index.js +505 -0
  108. package/dist/js/treeshaking/server/modern-server-split.js +360 -0
  109. package/dist/js/treeshaking/server/modern-server.js +1083 -0
  110. package/dist/js/treeshaking/type.js +1 -0
  111. package/dist/js/treeshaking/utils.js +147 -0
  112. package/dist/js/treeshaking/worker-server.js +177 -0
  113. package/dist/types/libs/context/context.d.ts +1 -1
  114. package/dist/types/libs/hook-api/index.d.ts +5 -0
  115. package/dist/types/libs/hook-api/route.d.ts +9 -14
  116. package/dist/types/libs/hook-api/template.d.ts +19 -9
  117. package/dist/types/libs/render/cache/index.d.ts +4 -2
  118. package/dist/types/libs/render/type.d.ts +3 -1
  119. package/dist/types/libs/route/route.d.ts +0 -1
  120. package/dist/types/libs/serve-file.d.ts +2 -1
  121. package/dist/types/server/index.d.ts +2 -0
  122. package/dist/types/server/modern-server.d.ts +11 -11
  123. package/dist/types/type.d.ts +8 -10
  124. package/dist/types/utils.d.ts +3 -4
  125. package/dist/types/worker-server.d.ts +15 -0
  126. package/package.json +31 -45
  127. package/dist/js/modern/libs/render/modern/browser-list.js +0 -7
  128. package/dist/js/modern/libs/render/modern/index.js +0 -48
  129. package/dist/js/node/libs/render/modern/browser-list.js +0 -14
  130. package/dist/js/node/libs/render/modern/index.js +0 -64
  131. package/dist/types/libs/render/modern/browser-list.d.ts +0 -1
  132. package/dist/types/libs/render/modern/index.d.ts +0 -3
@@ -1,38 +1,89 @@
1
- const _excluded = ["getMiddlewares"];
2
-
3
- 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; }
4
-
5
- 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; }
6
-
7
- function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
8
-
9
- function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
10
-
11
- 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; }
12
-
13
- /* eslint-disable max-lines */
14
- import { createServer } from 'http';
15
- import util from 'util';
16
- import path from 'path';
17
- import { fs, mime, ROUTE_SPEC_FILE } from '@modern-js/utils';
18
- import axios from 'axios';
19
- import { clone } from '@modern-js/utils/lodash';
20
- import { RouteMatchManager } from "../libs/route";
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __spreadValues = (a, b) => {
7
+ for (var prop in b || (b = {}))
8
+ if (__hasOwnProp.call(b, prop))
9
+ __defNormalProp(a, prop, b[prop]);
10
+ if (__getOwnPropSymbols)
11
+ for (var prop of __getOwnPropSymbols(b)) {
12
+ if (__propIsEnum.call(b, prop))
13
+ __defNormalProp(a, prop, b[prop]);
14
+ }
15
+ return a;
16
+ };
17
+ var __objRest = (source, exclude) => {
18
+ var target = {};
19
+ for (var prop in source)
20
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
21
+ target[prop] = source[prop];
22
+ if (source != null && __getOwnPropSymbols)
23
+ for (var prop of __getOwnPropSymbols(source)) {
24
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
25
+ target[prop] = source[prop];
26
+ }
27
+ return target;
28
+ };
29
+ var __async = (__this, __arguments, generator) => {
30
+ return new Promise((resolve, reject) => {
31
+ var fulfilled = (value) => {
32
+ try {
33
+ step(generator.next(value));
34
+ } catch (e) {
35
+ reject(e);
36
+ }
37
+ };
38
+ var rejected = (value) => {
39
+ try {
40
+ step(generator.throw(value));
41
+ } catch (e) {
42
+ reject(e);
43
+ }
44
+ };
45
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
46
+ step((generator = generator.apply(__this, __arguments)).next());
47
+ });
48
+ };
49
+ import { createServer } from "http";
50
+ import path from "path";
51
+ import { fs, isPromise, mime, ROUTE_SPEC_FILE } from "@modern-js/utils";
52
+ import {
53
+ RouteMatchManager
54
+ } from "../libs/route";
21
55
  import { createRenderHandler } from "../libs/render";
22
- import { createStaticFileHandler } from "../libs/serve-file";
23
- import { createErrorDocument, createMiddlewareCollecter, getStaticReg, mergeExtension, noop, debug, isRedirect } from "../utils";
56
+ import {
57
+ createStaticFileHandler,
58
+ faviconFallbackHandler
59
+ } from "../libs/serve-file";
60
+ import {
61
+ createErrorDocument,
62
+ createMiddlewareCollecter,
63
+ getStaticReg,
64
+ mergeExtension,
65
+ noop,
66
+ debug,
67
+ isRedirect
68
+ } from "../utils";
24
69
  import * as reader from "../libs/render/reader";
25
70
  import { createProxyHandler } from "../libs/proxy";
26
71
  import { createContext } from "../libs/context";
27
- import { AGGRED_DIR, ERROR_DIGEST, ERROR_PAGE_TEXT, RUN_MODE } from "../constants";
28
- import { createTemplateAPI } from "../libs/hook-api/template";
29
- import { createRouteAPI } from "../libs/hook-api/route";
30
- const API_DIR = './api';
31
- const SERVER_DIR = './server';
32
- export class ModernServer {
33
- // appDirectory
34
- // product dist dir
35
- // work on src or dist
72
+ import { templateInjectableStream } from "../libs/hook-api/template";
73
+ import {
74
+ AGGRED_DIR,
75
+ ERROR_DIGEST,
76
+ ERROR_PAGE_TEXT,
77
+ RUN_MODE
78
+ } from "../constants";
79
+ import {
80
+ createAfterMatchContext,
81
+ createAfterRenderContext,
82
+ createMiddlewareContext
83
+ } from "../libs/hook-api";
84
+ const API_DIR = "./api";
85
+ const SERVER_DIR = "./server";
86
+ class ModernServer {
36
87
  constructor({
37
88
  pwd,
38
89
  config,
@@ -43,616 +94,455 @@ export class ModernServer {
43
94
  runMode,
44
95
  proxyTarget
45
96
  }) {
46
- var _config$output;
47
-
48
- _defineProperty(this, "pwd", void 0);
49
-
50
- _defineProperty(this, "distDir", void 0);
51
-
52
- _defineProperty(this, "workDir", void 0);
53
-
54
- _defineProperty(this, "router", void 0);
55
-
56
- _defineProperty(this, "conf", void 0);
57
-
58
- _defineProperty(this, "handlers", []);
59
-
60
- _defineProperty(this, "presetRoutes", void 0);
61
-
62
- _defineProperty(this, "runner", void 0);
63
-
64
- _defineProperty(this, "logger", void 0);
65
-
66
- _defineProperty(this, "metrics", void 0);
67
-
68
- _defineProperty(this, "runMode", void 0);
69
-
70
- _defineProperty(this, "reader", reader);
71
-
72
- _defineProperty(this, "proxyTarget", void 0);
73
-
74
- _defineProperty(this, "staticFileHandler", void 0);
75
-
76
- _defineProperty(this, "routeRenderHandler", void 0);
77
-
78
- _defineProperty(this, "frameWebHandler", null);
79
-
80
- _defineProperty(this, "frameAPIHandler", null);
81
-
82
- _defineProperty(this, "proxyHandler", null);
83
-
84
- _defineProperty(this, "_handler", void 0);
85
-
86
- _defineProperty(this, "staticGenerate", void 0);
87
-
88
- require('ignore-styles');
89
-
97
+ this.handlers = [];
98
+ this.reader = reader;
99
+ this.beforeRouteHandler = null;
100
+ this.frameWebHandler = null;
101
+ this.frameAPIHandler = null;
102
+ this.proxyHandler = null;
103
+ require("ignore-styles");
90
104
  this.pwd = pwd;
91
- this.distDir = path.join(pwd, ((_config$output = config.output) === null || _config$output === void 0 ? void 0 : _config$output.path) || 'dist');
105
+ this.distDir = path.join(pwd, config.output.path || "dist");
92
106
  this.workDir = this.distDir;
93
107
  this.conf = config;
94
- debug('server conf', this.conf);
108
+ debug("server conf", this.conf);
95
109
  this.logger = logger;
96
110
  this.metrics = metrics;
97
111
  this.router = new RouteMatchManager();
98
112
  this.presetRoutes = routes;
99
113
  this.proxyTarget = proxyTarget;
100
114
  this.staticGenerate = staticGenerate || false;
101
- this.runMode = runMode || RUN_MODE.TYPE;
102
- process.env.BUILD_TYPE = `${this.staticGenerate ? 'ssg' : 'ssr'}`;
103
- } // server prepare
104
-
105
-
106
- async onInit(runner, app) {
107
- var _conf$bff;
108
-
109
- this.runner = runner;
110
- const {
111
- distDir,
112
- staticGenerate,
113
- conf
114
- } = this;
115
- debug('final server conf', this.conf); // proxy handler, each proxy has own handler
116
-
117
- this.proxyHandler = createProxyHandler((_conf$bff = conf.bff) === null || _conf$bff === void 0 ? void 0 : _conf$bff.proxy);
118
-
119
- if (this.proxyHandler) {
120
- this.proxyHandler.forEach(handler => {
121
- this.addHandler(handler);
115
+ this.runMode = runMode || RUN_MODE.FULL;
116
+ }
117
+ onInit(runner, app) {
118
+ return __async(this, null, function* () {
119
+ var _a;
120
+ this.runner = runner;
121
+ const { distDir, staticGenerate, conf } = this;
122
+ debug("final server conf", this.conf);
123
+ this.proxyHandler = createProxyHandler((_a = conf.bff) == null ? void 0 : _a.proxy);
124
+ if (this.proxyHandler) {
125
+ this.proxyHandler.forEach((handler) => {
126
+ this.addHandler(handler);
127
+ });
128
+ }
129
+ this.reader.init();
130
+ app.on("close", () => {
131
+ this.reader.close();
132
+ });
133
+ const usageRoutes = this.filterRoutes(this.getRoutes());
134
+ this.router.reset(usageRoutes);
135
+ this.warmupSSRBundle();
136
+ yield this.prepareFrameHandler();
137
+ yield this.prepareBeforeRouteHandler(usageRoutes, distDir);
138
+ const staticPathRegExp = getStaticReg(
139
+ this.conf.output || {},
140
+ this.conf.html
141
+ );
142
+ this.staticFileHandler = createStaticFileHandler(
143
+ [
144
+ {
145
+ path: staticPathRegExp,
146
+ target: distDir
147
+ }
148
+ ],
149
+ this.conf.output
150
+ );
151
+ this.routeRenderHandler = createRenderHandler({
152
+ distDir,
153
+ staticGenerate
122
154
  });
123
- } // start file reader
124
-
125
-
126
- this.reader.init();
127
- app.on('close', () => {
128
- this.reader.close();
129
- }); // use preset routes priority
130
-
131
- const usageRoutes = this.filterRoutes(this.getRoutes());
132
- this.router.reset(usageRoutes); // warmup ssr bundle in production env
133
-
134
- this.warmupSSRBundle();
135
- await this.prepareFrameHandler(); // Only work when without setting `assetPrefix`.
136
- // Setting `assetPrefix` means these resources should be uploaded to CDN.
137
-
138
- const staticPathRegExp = getStaticReg(this.conf.output || {});
139
- this.staticFileHandler = createStaticFileHandler([{
140
- path: staticPathRegExp,
141
- target: distDir
142
- }], this.conf.output);
143
- this.routeRenderHandler = createRenderHandler({
144
- distDir,
145
- staticGenerate
155
+ yield this.setupBeforeProdMiddleware();
156
+ this.addHandler(this.staticFileHandler);
157
+ this.addHandler(faviconFallbackHandler);
158
+ this.addBeforeRouteHandler();
159
+ this.addHandler(this.routeHandler.bind(this));
160
+ this.compose();
146
161
  });
147
- await this.setupBeforeProdMiddleware();
148
- this.addHandler(this.staticFileHandler);
149
- this.addHandler(this.routeHandler.bind(this)); // compose middlewares to http handler
150
-
151
- this.compose();
152
- } // server ready
153
-
154
-
155
- onRepack(_) {// empty
156
162
  }
157
-
158
- onServerChange({
159
- filepath
160
- }) {
161
- const {
162
- pwd
163
- } = this;
164
- const {
165
- api,
166
- server
167
- } = AGGRED_DIR;
163
+ onRepack(_) {
164
+ }
165
+ addBeforeRouteHandler() {
166
+ this.addHandler((context, next) => __async(this, null, function* () {
167
+ if (this.beforeRouteHandler) {
168
+ yield this.beforeRouteHandler(context);
169
+ if (this.isSend(context.res)) {
170
+ return;
171
+ }
172
+ }
173
+ return next();
174
+ }));
175
+ }
176
+ onServerChange({ filepath }) {
177
+ const { pwd } = this;
178
+ const { api, server } = AGGRED_DIR;
168
179
  const apiPath = path.normalize(path.join(pwd, api));
169
180
  const serverPath = path.normalize(path.join(pwd, server));
170
181
  const onlyApi = filepath.startsWith(apiPath);
171
182
  const onlyWeb = filepath.startsWith(serverPath);
172
- this.prepareFrameHandler({
173
- onlyWeb,
174
- onlyApi
175
- });
176
- } // exposed requestHandler
177
-
178
-
183
+ this.prepareFrameHandler({ onlyWeb, onlyApi });
184
+ }
179
185
  getRequestHandler() {
180
186
  return this.requestHandler.bind(this);
181
187
  }
182
-
183
- async createHTTPServer(handler) {
184
- return createServer(handler);
188
+ render(req, res, url) {
189
+ return __async(this, null, function* () {
190
+ req.logger = this.logger;
191
+ req.metrics = this.metrics;
192
+ const context = createContext(req, res);
193
+ const matched = this.router.match(url || context.path);
194
+ if (!matched) {
195
+ return null;
196
+ }
197
+ const route = matched.generate(context.url);
198
+ const result = yield this.handleWeb(context, route);
199
+ if (!result) {
200
+ return null;
201
+ }
202
+ return result.content.toString();
203
+ });
204
+ }
205
+ createHTTPServer(handler) {
206
+ return __async(this, null, function* () {
207
+ return createServer(handler);
208
+ });
185
209
  }
186
- /* —————————————————————— function will be overwrite —————————————————————— */
187
- // get routes info
188
-
189
-
190
210
  getRoutes() {
191
- // Preferred to use preset routes
192
211
  if (this.presetRoutes) {
193
212
  return this.presetRoutes;
194
- } // read routes from spec file
195
-
196
-
213
+ }
197
214
  const file = path.join(this.distDir, ROUTE_SPEC_FILE);
198
-
199
215
  if (fs.existsSync(file)) {
200
216
  const content = fs.readJSONSync(file);
201
217
  return content.routes;
202
218
  }
203
-
204
219
  return [];
205
- } // add promisify request handler to server
206
- // handler should do not do more things after invoke next
207
-
208
-
220
+ }
209
221
  addHandler(handler) {
210
- if (handler[Symbol.toStringTag] === 'AsyncFunction') {
211
- this.handlers.push(handler);
212
- } else {
213
- this.handlers.push(util.promisify(handler));
214
- }
215
- } // return 404 page
216
-
217
-
222
+ this.handlers.push(handler);
223
+ }
218
224
  render404(context) {
219
- context.error(ERROR_DIGEST.ENOTF, '404 Not Found');
225
+ context.error(ERROR_DIGEST.ENOTF, "404 Not Found");
220
226
  this.renderErrorPage(context, 404);
221
- } // gather frame extension and get framework handler
222
-
223
-
224
- async prepareFrameHandler(options) {
225
- const {
226
- workDir,
227
- runner
228
- } = this;
229
- const {
230
- onlyApi,
231
- onlyWeb
232
- } = options || {}; // server hook, gather plugin inject
233
-
234
- const _createMiddlewareColl = createMiddlewareCollecter(),
235
- {
236
- getMiddlewares
237
- } = _createMiddlewareColl,
238
- collector = _objectWithoutProperties(_createMiddlewareColl, _excluded);
239
-
240
- await runner.gather(collector);
241
- const {
242
- api: pluginAPIExt,
243
- web: pluginWebExt
244
- } = getMiddlewares();
245
- const apiDir = path.join(workDir, API_DIR);
246
- const serverDir = path.join(workDir, SERVER_DIR); // get api or web server handler from server-framework plugin
247
-
248
- if ((await fs.pathExists(path.join(serverDir))) && !onlyApi) {
249
- const webExtension = mergeExtension(pluginWebExt);
250
- this.frameWebHandler = await this.prepareWebHandler(webExtension);
251
- }
252
-
253
- if (fs.existsSync(apiDir) && !onlyWeb) {
254
- const apiExtension = mergeExtension(pluginAPIExt);
255
- this.frameAPIHandler = await this.prepareAPIHandler(apiExtension);
256
- }
257
227
  }
258
-
259
- async prepareWebHandler(extension) {
260
- const {
261
- workDir,
262
- runner
263
- } = this;
264
- return runner.prepareWebServer({
265
- pwd: workDir,
266
- config: extension
267
- }, {
268
- onLast: () => null
228
+ prepareBeforeRouteHandler(specs, distDir) {
229
+ return __async(this, null, function* () {
230
+ const { runner } = this;
231
+ const handler = yield runner.preparebeforeRouteHandler(
232
+ {
233
+ serverRoutes: specs,
234
+ distDir
235
+ },
236
+ {
237
+ onLast: () => null
238
+ }
239
+ );
240
+ this.beforeRouteHandler = handler;
241
+ });
242
+ }
243
+ prepareFrameHandler(options) {
244
+ return __async(this, null, function* () {
245
+ const { workDir, runner } = this;
246
+ const { onlyApi, onlyWeb } = options || {};
247
+ const _a = createMiddlewareCollecter(), { getMiddlewares } = _a, collector = __objRest(_a, ["getMiddlewares"]);
248
+ yield runner.gather(collector);
249
+ const { api: pluginAPIExt, web: pluginWebExt } = getMiddlewares();
250
+ const apiDir = path.join(workDir, API_DIR);
251
+ const serverDir = path.join(workDir, SERVER_DIR);
252
+ if ((yield fs.pathExists(path.join(serverDir))) && !onlyApi) {
253
+ const webExtension = mergeExtension(pluginWebExt);
254
+ this.frameWebHandler = yield this.prepareWebHandler(webExtension);
255
+ }
256
+ if (fs.existsSync(apiDir) && !onlyWeb) {
257
+ const apiExtension = mergeExtension(pluginAPIExt);
258
+ this.frameAPIHandler = yield this.prepareAPIHandler(apiExtension);
259
+ }
260
+ });
261
+ }
262
+ prepareWebHandler(extension) {
263
+ return __async(this, null, function* () {
264
+ const { workDir, runner } = this;
265
+ const handler = yield runner.prepareWebServer(
266
+ {
267
+ pwd: workDir,
268
+ config: extension
269
+ },
270
+ { onLast: () => null }
271
+ );
272
+ return handler;
269
273
  });
270
274
  }
271
-
272
- async prepareAPIHandler(extension) {
273
- const {
274
- workDir,
275
- runner,
276
- conf
277
- } = this;
278
- const {
279
- bff
280
- } = conf;
281
- const prefix = (bff === null || bff === void 0 ? void 0 : bff.prefix) || '/api';
282
- return runner.prepareApiServer({
283
- pwd: workDir,
284
- config: extension,
285
- prefix: Array.isArray(prefix) ? prefix[0] : prefix
286
- }, {
287
- onLast: () => null
275
+ prepareAPIHandler(extension) {
276
+ return __async(this, null, function* () {
277
+ const { workDir, runner, conf } = this;
278
+ const { bff } = conf;
279
+ const prefix = (bff == null ? void 0 : bff.prefix) || "/api";
280
+ return runner.prepareApiServer(
281
+ {
282
+ pwd: workDir,
283
+ config: extension,
284
+ prefix: Array.isArray(prefix) ? prefix[0] : prefix
285
+ },
286
+ { onLast: () => null }
287
+ );
288
288
  });
289
289
  }
290
-
291
290
  filterRoutes(routes) {
292
291
  return routes;
293
292
  }
294
-
295
- async emitRouteHook(eventName, input) {
296
- input.context = clone(input.context);
297
- return this.runner[eventName](input, {
298
- onLast: noop
293
+ setupBeforeProdMiddleware() {
294
+ return __async(this, null, function* () {
295
+ const { conf, runner } = this;
296
+ const preMiddleware = yield runner.beforeProdServer(conf);
297
+ preMiddleware.flat().forEach((mid) => {
298
+ this.addHandler(mid);
299
+ });
299
300
  });
300
301
  }
301
-
302
- async setupBeforeProdMiddleware() {
303
- const {
304
- conf,
305
- runner
306
- } = this;
307
- const preMiddleware = await runner.beforeProdServer(conf);
308
- preMiddleware.flat().forEach(mid => {
309
- this.addHandler(mid);
302
+ handleAPI(context) {
303
+ return __async(this, null, function* () {
304
+ const { req, res } = context;
305
+ if (!this.frameAPIHandler) {
306
+ throw new Error("can not found api handler");
307
+ }
308
+ yield this.frameAPIHandler(req, res);
310
309
  });
311
310
  }
312
-
313
- async handleAPI(context) {
314
- const {
315
- req,
316
- res
317
- } = context;
318
-
319
- if (!this.frameAPIHandler) {
320
- throw new Error('can not found api handler');
321
- }
322
-
323
- await this.frameAPIHandler(req, res);
311
+ handleWeb(context, route) {
312
+ return __async(this, null, function* () {
313
+ return this.routeRenderHandler({
314
+ ctx: context,
315
+ route,
316
+ runner: this.runner
317
+ });
318
+ });
324
319
  }
325
-
326
- async handleWeb(context, route) {
327
- return this.routeRenderHandler({
328
- ctx: context,
329
- route,
330
- runner: this.runner
320
+ proxy() {
321
+ return __async(this, null, function* () {
322
+ return null;
331
323
  });
332
324
  }
333
-
334
- async proxy() {
335
- return null;
336
- } // warmup ssr function
337
-
338
-
339
325
  warmupSSRBundle() {
340
- const {
341
- distDir
342
- } = this;
326
+ const { distDir } = this;
343
327
  const bundles = this.router.getBundles();
344
- bundles.forEach(bundle => {
345
- const filepath = path.join(distDir, bundle); // if error, just throw and let process die
346
-
328
+ bundles.forEach((bundle) => {
329
+ const filepath = path.join(distDir, bundle);
347
330
  require(filepath);
348
331
  });
349
332
  }
350
-
351
333
  createContext(req, res, options = {}) {
352
334
  return createContext(req, res, options);
353
335
  }
354
- /* —————————————————————— private function —————————————————————— */
355
- // handler route.json, include api / csr / ssr
356
-
357
-
358
- async routeHandler(context) {
359
- const {
360
- req,
361
- res
362
- } = context;
363
- await this.emitRouteHook('beforeMatch', {
364
- context
365
- }); // match routes in the route spec
366
-
367
- const matched = this.router.match(context.path);
368
-
369
- if (!matched) {
370
- this.render404(context);
371
- return;
372
- }
373
-
374
- if (res.headersSent) {
375
- return;
376
- }
377
-
378
- const routeAPI = createRouteAPI(matched, this.router, context.url);
379
- await this.emitRouteHook('afterMatch', {
380
- context,
381
- routeAPI
382
- });
383
-
384
- if (this.isSend(res)) {
385
- return;
386
- }
387
-
388
- const {
389
- current
390
- } = routeAPI;
391
- const route = current.generate(context.url);
392
- context.setParams(route.params);
393
- context.setServerData('router', {
394
- baseUrl: route.urlPath,
395
- params: route.params
396
- }); // route is api service
397
-
398
- if (route.isApi) {
399
- await this.handleAPI(context);
400
- return;
401
- }
402
-
403
- if (this.frameWebHandler) {
404
- await this.frameWebHandler(req, res);
405
- } // frameWebHandler has process request
406
-
407
-
408
- if (this.isSend(res)) {
409
- return;
410
- }
411
-
412
- if (route.responseHeaders) {
413
- Object.keys(route.responseHeaders).forEach(key => {
414
- const value = route.responseHeaders[key];
415
-
416
- if (value) {
417
- context.res.setHeader(key, value);
336
+ routeHandler(context) {
337
+ return __async(this, null, function* () {
338
+ const { res } = context;
339
+ const matched = this.router.match(context.path);
340
+ if (!matched) {
341
+ this.render404(context);
342
+ return;
343
+ }
344
+ let route = matched.generate(context.url);
345
+ if (route.isApi) {
346
+ yield this.handleAPI(context);
347
+ return;
348
+ }
349
+ const afterMatchContext = createAfterMatchContext(context, route.entryName);
350
+ if (this.runMode === RUN_MODE.FULL) {
351
+ yield this.runner.afterMatch(afterMatchContext, { onLast: noop });
352
+ }
353
+ if (this.isSend(res)) {
354
+ return;
355
+ }
356
+ const { current, url, status } = afterMatchContext.router;
357
+ if (url) {
358
+ this.redirect(res, url, status);
359
+ return;
360
+ }
361
+ if (route.entryName !== current) {
362
+ const matched2 = this.router.matchEntry(current);
363
+ if (!matched2) {
364
+ this.render404(context);
365
+ return;
418
366
  }
367
+ route = matched2.generate(context.url);
368
+ }
369
+ context.setParams(route.params);
370
+ context.setServerData("router", {
371
+ baseUrl: route.urlPath,
372
+ params: route.params
419
373
  });
420
- }
421
-
422
- if (route.entryName) {
423
- await this.emitRouteHook('beforeRender', {
424
- context
425
- });
426
- }
427
-
428
- const file = await this.handleWeb(context, route);
429
-
430
- if (!file) {
431
- this.render404(context);
432
- return;
433
- }
434
-
435
- if (file.redirect) {
436
- res.statusCode = file.statusCode;
437
- res.setHeader('Location', file.content);
438
- res.end();
439
- return;
440
- }
441
-
442
- if (this.isSend(res)) {
443
- return;
444
- }
445
-
446
- let response = file.content;
447
-
448
- if (route.entryName) {
449
- const templateAPI = createTemplateAPI(file.content.toString());
450
- await this.emitRouteHook('afterRender', {
451
- context,
452
- templateAPI
453
- });
454
-
374
+ if (this.frameWebHandler) {
375
+ res.locals = res.locals || {};
376
+ const middlewareContext = createMiddlewareContext(context);
377
+ yield this.frameWebHandler(middlewareContext);
378
+ res.locals = __spreadValues(__spreadValues({}, res.locals), middlewareContext.response.locals);
379
+ }
455
380
  if (this.isSend(res)) {
456
381
  return;
457
382
  }
458
-
459
- await this.injectMicroFE(context, templateAPI); // It will inject _SERVER_DATA twice, when SSG mode.
460
- // The first time was in ssg html created, the seoncd time was in prod-server start.
461
- // but the second wound causes route error.
462
- // To ensure that the second injection fails, the _SERVER_DATA inject at the front of head,
463
-
464
- templateAPI.prependHead(`<script>window._SERVER_DATA=${JSON.stringify(context.serverData)}</script>`);
465
- response = templateAPI.get();
466
- }
467
-
468
- res.setHeader('content-type', file.contentType);
469
- res.end(response);
383
+ if (route.responseHeaders) {
384
+ Object.keys(route.responseHeaders).forEach((key) => {
385
+ const value = route.responseHeaders[key];
386
+ if (value) {
387
+ context.res.setHeader(key, value);
388
+ }
389
+ });
390
+ }
391
+ const renderResult = yield this.handleWeb(context, route);
392
+ if (!renderResult) {
393
+ this.render404(context);
394
+ return;
395
+ }
396
+ if (renderResult.redirect) {
397
+ this.redirect(
398
+ res,
399
+ renderResult.content,
400
+ renderResult.statusCode
401
+ );
402
+ return;
403
+ }
404
+ if (this.isSend(res)) {
405
+ return;
406
+ }
407
+ res.setHeader("content-type", renderResult.contentType);
408
+ const { contentStream } = renderResult;
409
+ if (contentStream) {
410
+ contentStream.pipe(
411
+ templateInjectableStream({
412
+ prependHead: route.entryName ? `<script>window._SERVER_DATA=${JSON.stringify(
413
+ context.serverData
414
+ )}<\/script>` : void 0
415
+ })
416
+ ).pipe(res);
417
+ return;
418
+ }
419
+ let response = renderResult.content;
420
+ if (route.entryName) {
421
+ const afterRenderContext = createAfterRenderContext(
422
+ context,
423
+ response.toString()
424
+ );
425
+ if (this.runMode === RUN_MODE.FULL) {
426
+ yield this.runner.afterRender(afterRenderContext, { onLast: noop });
427
+ }
428
+ if (this.isSend(res)) {
429
+ return;
430
+ }
431
+ afterRenderContext.template.prependHead(
432
+ `<script>window._SERVER_DATA=${JSON.stringify(
433
+ context.serverData
434
+ )}<\/script>`
435
+ );
436
+ response = afterRenderContext.template.get();
437
+ }
438
+ res.end(response);
439
+ });
470
440
  }
471
-
472
441
  isSend(res) {
473
442
  if (res.headersSent) {
474
443
  return true;
475
444
  }
476
-
477
- if (res.getHeader('Location') && isRedirect(res.statusCode)) {
445
+ if (res.getHeader("Location") && isRedirect(res.statusCode)) {
478
446
  res.end();
479
447
  return true;
480
448
  }
481
-
482
449
  return false;
483
450
  }
484
-
485
- async injectMicroFE(context, templateAPI) {
486
- var _conf$runtime, _conf$server;
487
-
488
- const {
489
- conf
490
- } = this;
491
- const masterApp = (_conf$runtime = conf.runtime) === null || _conf$runtime === void 0 ? void 0 : _conf$runtime.masterApp; // no inject if not master App
492
-
493
- if (!masterApp) {
494
- return;
495
- }
496
-
497
- const manifest = masterApp.manifest || {};
498
- let modules = [];
499
- const {
500
- modules: configModules = []
501
- } = manifest; // while config modules is an string, fetch data from remote
502
-
503
- if (typeof configModules === 'string') {
504
- const moduleRequestUrl = configModules;
505
-
506
- try {
507
- const {
508
- data: remoteModules
509
- } = await axios.get(moduleRequestUrl);
510
-
511
- if (Array.isArray(remoteModules)) {
512
- modules.push(...remoteModules);
513
- }
514
- } catch (e) {
515
- context.error(ERROR_DIGEST.EMICROINJ, e);
516
- }
517
- } else if (Array.isArray(configModules)) {
518
- modules.push(...configModules);
519
- }
520
-
521
- const {
522
- headers
523
- } = context.req;
524
- const debugName = headers['x-micro-frontend-module-name'] || context.query['__debug__micro-frontend-module-name'];
525
- const debugEntry = headers['x-micro-frontend-module-entry'] || context.query['__debug__micro-frontend-module-entry']; // add debug micro App to first
526
-
527
- if (debugName && debugEntry && (_conf$server = conf.server) !== null && _conf$server !== void 0 && _conf$server.enableMicroFrontendDebug) {
528
- modules = modules.map(m => {
529
- if (m.name === debugName) {
530
- return {
531
- name: debugName,
532
- entry: debugEntry
533
- };
534
- }
535
-
536
- return m;
537
- });
538
- }
539
-
540
- try {
541
- // Todo Safety xss
542
- const injection = JSON.stringify(_objectSpread(_objectSpread({}, manifest), {}, {
543
- modules
544
- }));
545
- templateAPI.appendHead(`<script>window.modern_manifest=${injection}</script>`);
546
- } catch (e) {
547
- context.error(ERROR_DIGEST.EMICROINJ, e);
548
- }
549
- } // compose handlers and create the final handler
550
-
551
-
552
451
  compose() {
553
- const {
554
- handlers
555
- } = this;
556
-
452
+ const { handlers } = this;
557
453
  if (!Array.isArray(handlers)) {
558
- throw new TypeError('Middleware stack must be an array!');
454
+ throw new TypeError("Middleware stack must be an array!");
559
455
  }
560
-
561
456
  for (const fn of handlers) {
562
- if (typeof fn !== 'function') {
563
- throw new TypeError('Middleware must be composed of functions!');
457
+ if (typeof fn !== "function") {
458
+ throw new TypeError("Middleware must be composed of functions!");
564
459
  }
565
460
  }
566
-
567
461
  this._handler = (context, next) => {
568
462
  let i = 0;
569
-
570
- const dispatch = error => {
463
+ const dispatch = (error) => {
571
464
  if (error) {
572
465
  return this.onError(context, error);
573
466
  }
574
-
575
467
  const handler = handlers[i++];
576
-
577
468
  if (!handler) {
578
469
  return next();
579
470
  }
580
-
581
- return handler(context, dispatch).catch(onError);
471
+ try {
472
+ const result = handler(context, dispatch);
473
+ if (isPromise(result)) {
474
+ return result.catch(onError);
475
+ }
476
+ } catch (e) {
477
+ return onError(e);
478
+ }
582
479
  };
583
-
584
- const onError = err => {
480
+ const onError = (err) => {
585
481
  this.onError(context, err);
586
482
  };
587
-
588
483
  return dispatch();
589
484
  };
590
485
  }
591
-
592
- requestHandler(req, res, next = () => {// empty
486
+ requestHandler(req, res, next = () => {
593
487
  }) {
594
488
  res.statusCode = 200;
595
489
  req.logger = this.logger;
596
490
  req.metrics = this.metrics;
597
491
  let context;
598
-
599
492
  try {
600
493
  context = this.createContext(req, res);
601
494
  } catch (e) {
602
495
  this.logger.error(e);
603
496
  res.statusCode = 500;
604
- res.setHeader('content-type', mime.contentType('html'));
497
+ res.setHeader("content-type", mime.contentType("html"));
605
498
  return res.end(createErrorDocument(500, ERROR_PAGE_TEXT[500]));
606
499
  }
607
-
608
500
  try {
609
501
  return this._handler(context, next);
610
502
  } catch (err) {
611
503
  return this.onError(context, err);
612
504
  }
613
505
  }
614
-
506
+ redirect(res, url, status = 302) {
507
+ res.setHeader("Location", url);
508
+ res.statusCode = status;
509
+ res.end();
510
+ }
615
511
  onError(context, err) {
616
512
  context.error(ERROR_DIGEST.EINTER, err);
617
513
  this.renderErrorPage(context, 500);
618
514
  }
619
-
620
- async renderErrorPage(context, status) {
621
- const {
622
- res
623
- } = context;
624
- context.status = status;
625
- res.setHeader('content-type', mime.contentType('html'));
626
- const statusPage = `/${status}`;
627
- const customErrorPage = `/_error`;
628
- const matched = this.router.match(statusPage) || this.router.match(customErrorPage); // if no custom status page find
629
-
630
- if (matched) {
631
- const route = matched.generate(context.url);
632
- const {
633
- entryName
634
- } = route; // check entryName, avoid matched '/' route
635
-
636
- if (entryName === status.toString() || entryName === '_error') {
637
- try {
638
- const file = await this.routeRenderHandler({
639
- route,
640
- ctx: context,
641
- runner: this.runner
642
- });
643
-
644
- if (file) {
645
- context.res.end(file.content);
646
- return;
515
+ renderErrorPage(context, status) {
516
+ return __async(this, null, function* () {
517
+ const { res } = context;
518
+ context.status = status;
519
+ res.setHeader("content-type", mime.contentType("html"));
520
+ const statusPage = `/${status}`;
521
+ const customErrorPage = `/_error`;
522
+ const matched = this.router.match(statusPage) || this.router.match(customErrorPage);
523
+ if (matched) {
524
+ const route = matched.generate(context.url);
525
+ const { entryName } = route;
526
+ if (entryName === status.toString() || entryName === "_error") {
527
+ try {
528
+ const file = yield this.routeRenderHandler({
529
+ route,
530
+ ctx: context,
531
+ runner: this.runner
532
+ });
533
+ if (file) {
534
+ context.res.end(file.content);
535
+ return;
536
+ }
537
+ } catch (e) {
647
538
  }
648
- } catch (e) {// just catch error when the rendering error occurred in the custom error page.
649
539
  }
650
540
  }
651
- }
652
-
653
- const text = ERROR_PAGE_TEXT[status] || ERROR_PAGE_TEXT[500];
654
- context.res.end(createErrorDocument(status, text));
541
+ const text = ERROR_PAGE_TEXT[status] || ERROR_PAGE_TEXT[500];
542
+ context.res.end(createErrorDocument(status, text));
543
+ });
655
544
  }
656
-
657
545
  }
658
- /* eslint-enable max-lines */
546
+ export {
547
+ ModernServer
548
+ };