@modern-js/prod-server 1.0.1 → 1.0.3

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 (34) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/js/modern/constants.js +4 -0
  3. package/dist/js/modern/libs/render/modern/index.js +3 -1
  4. package/dist/js/modern/server/index.js +47 -57
  5. package/dist/js/modern/server/modern-server-split.js +42 -33
  6. package/dist/js/modern/server/modern-server.js +55 -48
  7. package/dist/js/modern/type.js +1 -1
  8. package/dist/js/node/constants.js +7 -2
  9. package/dist/js/node/libs/render/modern/index.js +3 -1
  10. package/dist/js/node/server/index.js +45 -57
  11. package/dist/js/node/server/modern-server-split.js +40 -37
  12. package/dist/js/node/server/modern-server.js +55 -48
  13. package/dist/js/node/type.js +1 -3
  14. package/dist/types/constants.d.ts +5 -1
  15. package/dist/types/server/index.d.ts +5 -9
  16. package/dist/types/server/modern-server-split.d.ts +2 -26
  17. package/dist/types/server/modern-server.d.ts +16 -14
  18. package/dist/types/type.d.ts +16 -2
  19. package/package.json +4 -4
  20. package/src/constants.ts +5 -0
  21. package/src/libs/render/index.ts +1 -0
  22. package/src/libs/render/modern/index.ts +1 -1
  23. package/src/server/index.ts +51 -71
  24. package/src/server/modern-server-split.ts +42 -46
  25. package/src/server/modern-server.ts +61 -53
  26. package/src/type.ts +41 -1
  27. package/tests/fixtures/pure/test-dist/bundles/main.js +5 -0
  28. package/tests/fixtures/pure/test-dist/html/main/index.html +36 -0
  29. package/tests/fixtures/pure/test-dist/route.json +31 -0
  30. package/tests/fixtures/ssr/bundle-error.js +3 -0
  31. package/tests/fixtures/ssr/tpl.html +11 -0
  32. package/tests/render.test.ts +106 -2
  33. package/tests/server.test.ts +192 -5
  34. package/tests/spr.test.ts +38 -0
package/CHANGELOG.md CHANGED
@@ -1,6 +1,23 @@
1
1
  # @modern-js/prod-server
2
2
 
3
+ ## 1.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - a78e32d8: remove server hook when api only
8
+ - e11eaafc: fix runner error in dev
9
+ - cbba492b: add serverless pre-render unit-test
10
+ - 59010b7a: rewrite server lifecycle, add unit test
11
+ - Updated dependencies [cc5e8001]
12
+ - Updated dependencies [2520ea86]
13
+ - Updated dependencies [db43dce6]
14
+ - Updated dependencies [e81fd9b7]
15
+ - Updated dependencies [1c411e71]
16
+ - @modern-js/core@1.4.6
17
+ - @modern-js/utils@1.3.4
18
+
3
19
  ## 1.0.1
20
+
4
21
  ### Patch Changes
5
22
 
6
23
  - 02fb4146: support product server
@@ -23,4 +23,8 @@ export const ERROR_DIGEST = {
23
23
  export const ERROR_PAGE_TEXT = {
24
24
  404: 'This page could not be found.',
25
25
  500: 'Internal Server Error.'
26
+ };
27
+ export const RUN_MODE = {
28
+ FULL: 'full',
29
+ TYPE: 'type'
26
30
  };
@@ -5,7 +5,9 @@ import { NativeModuleNameMap } from "./browser-list";
5
5
  const nativeModules = require('@babel/compat-data/native-modules');
6
6
 
7
7
  export const supportModern = context => {
8
- if (context.query.modern_es6) {
8
+ var _context$query;
9
+
10
+ if ((_context$query = context.query) !== null && _context$query !== void 0 && _context$query.modern_es6) {
9
11
  return true;
10
12
  } // no ua in request headers
11
13
 
@@ -6,24 +6,9 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
6
6
 
7
7
  import path from 'path';
8
8
  import { serverManager, AppContext, ConfigContext } from '@modern-js/server-core';
9
- import { compatRequire, logger as defaultLogger } from '@modern-js/utils';
10
- import { initAppContext, initAppDir, loadUserConfig } from '@modern-js/core';
9
+ import { compatRequire, logger as defaultLogger, SHARED_DIR } from '@modern-js/utils';
11
10
  import { metrics as defaultMetrics } from "../libs/metrics";
12
- import { ModernServer } from "./modern-server";
13
- import { ModernAPIServer, ModernSSRServer, ModernWebServer } from "./modern-server-split";
14
-
15
- const createProdServer = options => {
16
- if (options.apiOnly) {
17
- return new ModernAPIServer(options);
18
- } else if (options.ssrOnly) {
19
- return new ModernSSRServer(options);
20
- } else if (options.webOnly) {
21
- return new ModernWebServer(options);
22
- } else {
23
- return new ModernServer(options);
24
- }
25
- };
26
-
11
+ import { createProdServer } from "./modern-server-split";
27
12
  export class Server {
28
13
  constructor(options) {
29
14
  this.options = void 0;
@@ -31,68 +16,64 @@ export class Server {
31
16
  this.server = void 0;
32
17
  this.app = void 0;
33
18
  this.runner = void 0;
19
+ options.logger = options.logger || defaultLogger;
20
+ options.metrics = options.metrics || defaultMetrics;
34
21
  this.options = options;
35
22
  }
36
23
 
37
- getRequestHandler() {
38
- return (req, res, next) => {
39
- const requestHandler = this.server.getRequestHandler();
40
- return requestHandler(req, res, next);
41
- };
42
- }
43
-
44
- ready(readyOptions = {}) {
45
- this.server.ready(readyOptions);
46
- }
47
-
48
24
  async init() {
49
25
  const {
50
26
  options
51
- } = this;
52
- options.logger = options.logger || defaultLogger;
53
- options.metrics = options.metrics || defaultMetrics; // initialize server
27
+ } = this; // initialize server
54
28
 
55
29
  this.server = this.serverImpl(options); // create http-server
56
30
 
57
- this.app = await this.server.createHTTPServer(this.getRequestHandler());
31
+ this.app = await this.server.createHTTPServer(this.getRequestHandler()); // initialize server runner
32
+
58
33
  this.runner = await this.createHookRunner(); // runner can only be used after server init
59
34
 
60
- await this.server.init(this.runner);
35
+ await this.server.onInit(this.runner);
61
36
  return this;
62
37
  }
63
38
 
39
+ async close() {
40
+ await this.server.onClose();
41
+ await new Promise(resolve => this.app.close(() => {
42
+ resolve();
43
+ }));
44
+ }
45
+
64
46
  listen(port = 8080, listener) {
65
47
  this.app.listen(process.env.PORT || port, () => {
66
48
  if (listener) {
67
49
  listener();
68
50
  }
69
51
 
70
- this.listener(this.app);
52
+ this.server.onListening(this.app);
71
53
  });
72
54
  }
73
55
 
74
- listener(app) {
75
- this.server.onListening(app);
76
- }
77
-
78
- async close() {
79
- await this.server.close();
80
- await new Promise(resolve => this.app.close(() => {
81
- resolve();
82
- }));
56
+ getRequestHandler() {
57
+ return (req, res, next) => {
58
+ const requestHandler = this.server.getRequestHandler();
59
+ return requestHandler(req, res, next);
60
+ };
83
61
  }
84
62
 
85
63
  async createHookRunner() {
86
- var _options$plugins;
87
-
64
+ // clear server manager every create time
65
+ serverManager.clear();
88
66
  const {
89
67
  options
90
68
  } = this;
91
- serverManager.clear();
92
- (_options$plugins = options.plugins) === null || _options$plugins === void 0 ? void 0 : _options$plugins.forEach(p => {
69
+ const {
70
+ plugins = []
71
+ } = options; // server app context for serve plugin
72
+
73
+ plugins.forEach(p => {
93
74
  serverManager.usePlugin(compatRequire(p.pluginPath));
94
75
  });
95
- const appContext = await this.initAppContext();
76
+ const appContext = this.initAppContext();
96
77
  serverManager.run(() => {
97
78
  var _options$config$outpu;
98
79
 
@@ -104,17 +85,26 @@ export class Server {
104
85
  return serverManager.init({});
105
86
  }
106
87
 
107
- async initAppContext() {
108
- var _this$options$plugins;
88
+ initAppContext() {
89
+ var _config$output;
109
90
 
110
- const appDirectory = await initAppDir();
111
- const loaded = await loadUserConfig(appDirectory);
112
- const plugins = (_this$options$plugins = this.options.plugins) === null || _this$options$plugins === void 0 ? void 0 : _this$options$plugins.map(p => ({
113
- server: p,
114
- cli: undefined
91
+ const {
92
+ options
93
+ } = this;
94
+ const {
95
+ pwd: appDirectory,
96
+ plugins = [],
97
+ config
98
+ } = options;
99
+ const serverPlugins = plugins.map(p => ({
100
+ server: p
115
101
  }));
116
- const appContext = initAppContext(appDirectory, plugins || [], loaded.filePath);
117
- return appContext;
102
+ return {
103
+ appDirectory,
104
+ distDirectory: path.join(appDirectory, ((_config$output = config.output) === null || _config$output === void 0 ? void 0 : _config$output.path) || 'dist'),
105
+ sharedDirectory: path.resolve(appDirectory, SHARED_DIR),
106
+ plugins: serverPlugins
107
+ };
118
108
  }
119
109
 
120
110
  }
@@ -1,55 +1,52 @@
1
+ import { RUN_MODE } from "../constants";
1
2
  import { ModernServer } from "./modern-server";
2
- export class ModernSSRServer extends ModernServer {
3
- // Todo should not invoke any route hook in modernSSRServer
4
- async warmupSSRBundle() {// empty
5
- }
6
-
7
- verifyMatch(context, matched) {
8
- if (matched.generate(context.url).isApi) {
9
- this.render404(context);
10
- }
11
- }
12
3
 
4
+ class ModernSSRServer extends ModernServer {
13
5
  prepareAPIHandler(_m, _) {
14
6
  return null;
15
7
  }
16
8
 
17
- async prepareWebHandler(extension) {
18
- return super.prepareWebHandler(extension);
19
- } // protected filterRoutes(routes: ModernRouteInterface[]) {
20
- // return routes.filter(route => route.entryName);
21
- // }
22
-
23
-
24
- async preServerInit() {// empty
9
+ filterRoutes(routes) {
10
+ return routes.filter(route => route.isSSR);
25
11
  }
26
12
 
27
- }
28
- export class ModernAPIServer extends ModernServer {
29
- async emitRouteHook(_, _input) {// empty
13
+ async preServerInit() {
14
+ if (this.runMode === RUN_MODE.FULL) {
15
+ await super.preServerInit();
16
+ }
30
17
  }
31
18
 
32
- async warmupSSRBundle() {// empty
19
+ async emitRouteHook(_, _input) {
20
+ if (this.runMode === RUN_MODE.FULL) {
21
+ await super.emitRouteHook(_, _input);
22
+ }
33
23
  }
34
24
 
25
+ }
26
+
27
+ class ModernAPIServer extends ModernServer {
35
28
  prepareWebHandler(_) {
36
29
  return null;
37
30
  }
38
31
 
39
- async prepareAPIHandler(mode, extension) {
40
- return super.prepareAPIHandler(mode, extension);
41
- }
42
-
43
32
  filterRoutes(routes) {
44
33
  return routes.filter(route => route.isApi);
45
34
  }
46
35
 
47
- async preServerInit() {// empty
36
+ async preServerInit() {
37
+ if (this.runMode === RUN_MODE.FULL) {
38
+ await super.preServerInit();
39
+ }
40
+ }
41
+
42
+ async emitRouteHook(_, _input) {// empty
48
43
  }
49
44
 
50
45
  }
51
- export class ModernWebServer extends ModernServer {
52
- async warmupSSRBundle() {// empty
46
+
47
+ class ModernWebServer extends ModernServer {
48
+ async warmupSSRBundle() {
49
+ return null;
53
50
  }
54
51
 
55
52
  async handleAPI(context) {
@@ -57,10 +54,10 @@ export class ModernWebServer extends ModernServer {
57
54
  proxyTarget
58
55
  } = this;
59
56
 
60
- if (!(proxyTarget !== null && proxyTarget !== void 0 && proxyTarget.api)) {
61
- this.proxy();
57
+ if (proxyTarget !== null && proxyTarget !== void 0 && proxyTarget.api) {
58
+ return this.proxy();
62
59
  } else {
63
- this.render404(context);
60
+ return this.render404(context);
64
61
  }
65
62
  }
66
63
 
@@ -78,4 +75,16 @@ export class ModernWebServer extends ModernServer {
78
75
  }
79
76
  }
80
77
 
81
- }
78
+ }
79
+
80
+ export const createProdServer = options => {
81
+ if (options.apiOnly) {
82
+ return new ModernAPIServer(options);
83
+ } else if (options.ssrOnly) {
84
+ return new ModernSSRServer(options);
85
+ } else if (options.webOnly) {
86
+ return new ModernWebServer(options);
87
+ } else {
88
+ return new ModernServer(options);
89
+ }
90
+ };
@@ -25,7 +25,7 @@ import { createErrorDocument, createMiddlewareCollecter, getStaticReg, mergeExte
25
25
  import * as reader from "../libs/render/reader";
26
26
  import { createProxyHandler } from "../libs/proxy";
27
27
  import { createContext } from "../libs/context";
28
- import { AGGRED_DIR, ApiServerMode, ERROR_DIGEST, ERROR_PAGE_TEXT } from "../constants";
28
+ import { AGGRED_DIR, ApiServerMode, ERROR_DIGEST, ERROR_PAGE_TEXT, RUN_MODE } from "../constants";
29
29
  import { createTemplateAPI } from "../libs/hook-api/template";
30
30
  import { createRouteAPI } from "../libs/hook-api/route";
31
31
  const API_DIR = './api';
@@ -41,6 +41,7 @@ export class ModernServer {
41
41
  staticGenerate,
42
42
  logger,
43
43
  metrics,
44
+ runMode,
44
45
  proxyTarget
45
46
  }) {
46
47
  var _config$output;
@@ -55,6 +56,7 @@ export class ModernServer {
55
56
  this.runner = void 0;
56
57
  this.logger = void 0;
57
58
  this.metrics = void 0;
59
+ this.runMode = void 0;
58
60
  this.reader = reader;
59
61
  this.proxyTarget = void 0;
60
62
  this.staticFileHandler = void 0;
@@ -63,7 +65,7 @@ export class ModernServer {
63
65
  this.frameAPIHandler = null;
64
66
  this.proxyHandler = null;
65
67
  this._handler = void 0;
66
- this.staticGenerate = false;
68
+ this.staticGenerate = void 0;
67
69
 
68
70
  require('ignore-styles');
69
71
 
@@ -76,21 +78,13 @@ export class ModernServer {
76
78
  this.router = new RouteMatchManager();
77
79
  this.presetRoutes = routes;
78
80
  this.proxyTarget = proxyTarget;
79
-
80
- if (staticGenerate) {
81
- this.staticGenerate = staticGenerate;
82
- }
83
-
81
+ this.staticGenerate = staticGenerate || false;
82
+ this.runMode = runMode || RUN_MODE.TYPE;
84
83
  process.env.BUILD_TYPE = `${this.staticGenerate ? 'ssg' : 'ssr'}`;
85
- } // exposed requestHandler
86
-
87
-
88
- getRequestHandler() {
89
- return this.requestHandler.bind(this);
90
84
  } // server prepare
91
85
 
92
86
 
93
- async init(runner) {
87
+ async onInit(runner) {
94
88
  var _conf$bff;
95
89
 
96
90
  this.runner = runner;
@@ -98,7 +92,8 @@ export class ModernServer {
98
92
  distDir,
99
93
  staticGenerate,
100
94
  conf
101
- } = this;
95
+ } = this; // Todo: why add this middleware
96
+
102
97
  this.addHandler((ctx, next) => {
103
98
  ctx.res.setHeader('Access-Control-Allow-Origin', '*');
104
99
  ctx.res.setHeader('Access-Control-Allow-Credentials', 'false');
@@ -111,12 +106,14 @@ export class ModernServer {
111
106
  this.proxyHandler.forEach(handler => {
112
107
  this.addHandler(handler);
113
108
  });
114
- } // start reader, include an time interval
109
+ } // start file reader
115
110
 
116
111
 
117
112
  this.reader.init(); // use preset routes priority
118
113
 
119
- this.router.reset(this.filterRoutes(this.presetRoutes || this.readRouteSpec()));
114
+ const usageRoutes = this.filterRoutes(this.getRoutes());
115
+ this.router.reset(usageRoutes); // warmup ssr bundle in production env
116
+
120
117
  this.warmupSSRBundle();
121
118
  await this.prepareFrameHandler(); // Only work when without setting `assetPrefix`.
122
119
  // Setting `assetPrefix` means these resources should be uploaded to CDN.
@@ -132,29 +129,47 @@ export class ModernServer {
132
129
  });
133
130
  await this.preServerInit();
134
131
  this.addHandler(this.staticFileHandler);
135
- this.addHandler(this.routeHandler.bind(this));
132
+ this.addHandler(this.routeHandler.bind(this)); // compose middlewares to http handler
133
+
136
134
  this.compose();
135
+ } // close any thing run in server
136
+
137
+
138
+ async onClose() {
139
+ this.reader.close();
137
140
  } // server ready
138
- // eslint-disable-next-line @typescript-eslint/no-empty-function
139
141
 
140
142
 
141
- ready(_) {} // invoke when http server listen
143
+ onRepack(_) {// empty
144
+ } // invoke when http server listen
142
145
 
143
146
 
144
147
  onListening(_) {// empty
145
- } // close any thing run in server
148
+ }
146
149
 
150
+ onServerChange(_) {
151
+ this.prepareFrameHandler();
152
+ } // exposed requestHandler
147
153
 
148
- async close() {
149
- this.reader.close();
154
+
155
+ getRequestHandler() {
156
+ return this.requestHandler.bind(this);
150
157
  }
151
158
 
152
159
  async createHTTPServer(handler) {
153
160
  return createServer(handler);
154
- } // read route spec from route.json
161
+ }
162
+ /* —————————————————————— function will be overwrite —————————————————————— */
163
+ // get routes info
164
+
165
+
166
+ getRoutes() {
167
+ // Preferred to use preset routes
168
+ if (this.presetRoutes) {
169
+ return this.presetRoutes;
170
+ } // read routes from spec file
155
171
 
156
172
 
157
- readRouteSpec() {
158
173
  const file = path.join(this.distDir, ROUTE_SPEC_FILE);
159
174
 
160
175
  if (fs.existsSync(file)) {
@@ -213,14 +228,7 @@ export class ModernServer {
213
228
  const apiExtension = mergeExtension(pluginAPIExt);
214
229
  this.frameAPIHandler = await this.prepareAPIHandler(mode, apiExtension);
215
230
  }
216
- } // Todo
217
-
218
-
219
- async proxy() {
220
- return null;
221
231
  }
222
- /* —————————————————————— function will be overwrite —————————————————————— */
223
-
224
232
 
225
233
  async prepareWebHandler(extension) {
226
234
  const {
@@ -264,19 +272,6 @@ export class ModernServer {
264
272
  return this.runner[eventName](input, {
265
273
  onLast: noop
266
274
  });
267
- } // warmup ssr function
268
-
269
-
270
- warmupSSRBundle() {
271
- const {
272
- distDir
273
- } = this;
274
- const bundles = this.router.getBundles();
275
- bundles.forEach(bundle => {
276
- const filepath = path.join(distDir, bundle); // if error, just throw and let process die
277
-
278
- require(filepath);
279
- });
280
275
  }
281
276
 
282
277
  async preServerInit() {
@@ -311,7 +306,21 @@ export class ModernServer {
311
306
  });
312
307
  }
313
308
 
314
- verifyMatch(_c, _m) {// empty
309
+ async proxy() {
310
+ return null;
311
+ } // warmup ssr function
312
+
313
+
314
+ warmupSSRBundle() {
315
+ const {
316
+ distDir
317
+ } = this;
318
+ const bundles = this.router.getBundles();
319
+ bundles.forEach(bundle => {
320
+ const filepath = path.join(distDir, bundle); // if error, just throw and let process die
321
+
322
+ require(filepath);
323
+ });
315
324
  }
316
325
  /* —————————————————————— private function —————————————————————— */
317
326
  // handler route.json, include api / csr / ssr
@@ -332,8 +341,6 @@ export class ModernServer {
332
341
  if (!matched) {
333
342
  this.render404(context);
334
343
  return;
335
- } else {
336
- this.verifyMatch(context, matched);
337
344
  }
338
345
 
339
346
  if (res.headersSent) {
@@ -569,7 +576,7 @@ export class ModernServer {
569
576
  }
570
577
 
571
578
  const text = ERROR_PAGE_TEXT[status] || ERROR_PAGE_TEXT[500];
572
- res.end(createErrorDocument(status, text));
579
+ context.res.end(createErrorDocument(status, text));
573
580
  }
574
581
 
575
582
  }
@@ -1 +1 @@
1
- export {};
1
+ import { IncomingMessage } from 'http';
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.ERROR_PAGE_TEXT = exports.ERROR_DIGEST = exports.ApiServerMode = exports.AGGRED_DIR = void 0;
6
+ exports.RUN_MODE = exports.ERROR_PAGE_TEXT = exports.ERROR_DIGEST = exports.ApiServerMode = exports.AGGRED_DIR = void 0;
7
7
  const AGGRED_DIR = {
8
8
  mock: 'config/mock',
9
9
  server: 'server',
@@ -33,4 +33,9 @@ const ERROR_PAGE_TEXT = {
33
33
  404: 'This page could not be found.',
34
34
  500: 'Internal Server Error.'
35
35
  };
36
- exports.ERROR_PAGE_TEXT = ERROR_PAGE_TEXT;
36
+ exports.ERROR_PAGE_TEXT = ERROR_PAGE_TEXT;
37
+ const RUN_MODE = {
38
+ FULL: 'full',
39
+ TYPE: 'type'
40
+ };
41
+ exports.RUN_MODE = RUN_MODE;
@@ -16,7 +16,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
16
16
  const nativeModules = require('@babel/compat-data/native-modules');
17
17
 
18
18
  const supportModern = context => {
19
- if (context.query.modern_es6) {
19
+ var _context$query;
20
+
21
+ if ((_context$query = context.query) !== null && _context$query !== void 0 && _context$query.modern_es6) {
20
22
  return true;
21
23
  } // no ua in request headers
22
24