@modern-js/prod-server 1.21.2 → 2.0.0-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 (31) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/js/modern/libs/hook-api/index.js +156 -0
  3. package/dist/js/modern/libs/hook-api/route.js +14 -29
  4. package/dist/js/modern/libs/hook-api/template.js +43 -4
  5. package/dist/js/modern/libs/render/cache/index.js +33 -16
  6. package/dist/js/modern/libs/render/measure.js +8 -1
  7. package/dist/js/modern/libs/render/ssr.js +20 -7
  8. package/dist/js/modern/libs/serve-file.js +8 -0
  9. package/dist/js/modern/server/index.js +9 -3
  10. package/dist/js/modern/server/modern-server-split.js +5 -44
  11. package/dist/js/modern/server/modern-server.js +140 -130
  12. package/dist/js/node/libs/hook-api/index.js +178 -0
  13. package/dist/js/node/libs/hook-api/route.js +14 -29
  14. package/dist/js/node/libs/hook-api/template.js +48 -4
  15. package/dist/js/node/libs/render/cache/index.js +34 -16
  16. package/dist/js/node/libs/render/measure.js +7 -0
  17. package/dist/js/node/libs/render/ssr.js +20 -7
  18. package/dist/js/node/libs/serve-file.js +12 -1
  19. package/dist/js/node/server/index.js +8 -2
  20. package/dist/js/node/server/modern-server-split.js +5 -45
  21. package/dist/js/node/server/modern-server.js +140 -132
  22. package/dist/types/libs/hook-api/index.d.ts +5 -0
  23. package/dist/types/libs/hook-api/route.d.ts +9 -14
  24. package/dist/types/libs/hook-api/template.d.ts +19 -9
  25. package/dist/types/libs/render/cache/index.d.ts +4 -2
  26. package/dist/types/libs/render/type.d.ts +3 -1
  27. package/dist/types/libs/serve-file.d.ts +2 -1
  28. package/dist/types/server/index.d.ts +2 -0
  29. package/dist/types/server/modern-server.d.ts +11 -11
  30. package/dist/types/type.d.ts +8 -10
  31. package/package.json +9 -32
@@ -15,18 +15,16 @@ import { createServer } from 'http';
15
15
  import util from 'util';
16
16
  import path from 'path';
17
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
18
  import { RouteMatchManager } from "../libs/route";
21
19
  import { createRenderHandler } from "../libs/render";
22
- import { createStaticFileHandler } from "../libs/serve-file";
20
+ import { createStaticFileHandler, faviconFallbackHandler } from "../libs/serve-file";
23
21
  import { createErrorDocument, createMiddlewareCollecter, getStaticReg, mergeExtension, noop, debug, isRedirect } from "../utils";
24
22
  import * as reader from "../libs/render/reader";
25
23
  import { createProxyHandler } from "../libs/proxy";
26
24
  import { createContext } from "../libs/context";
25
+ import { templateInjectableStream } from "../libs/hook-api/template";
27
26
  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";
27
+ import { createAfterMatchContext, createAfterRenderContext, createMiddlewareContext } from "../libs/hook-api";
30
28
  const API_DIR = './api';
31
29
  const SERVER_DIR = './server';
32
30
  export class ModernServer {
@@ -75,6 +73,8 @@ export class ModernServer {
75
73
 
76
74
  _defineProperty(this, "routeRenderHandler", void 0);
77
75
 
76
+ _defineProperty(this, "beforeRouteHandler", null);
77
+
78
78
  _defineProperty(this, "frameWebHandler", null);
79
79
 
80
80
  _defineProperty(this, "frameAPIHandler", null);
@@ -98,8 +98,7 @@ export class ModernServer {
98
98
  this.presetRoutes = routes;
99
99
  this.proxyTarget = proxyTarget;
100
100
  this.staticGenerate = staticGenerate || false;
101
- this.runMode = runMode || RUN_MODE.TYPE;
102
- process.env.BUILD_TYPE = `${this.staticGenerate ? 'ssg' : 'ssr'}`;
101
+ this.runMode = runMode || RUN_MODE.FULL; // process.env.BUILD_TYPE = `${this.staticGenerate ? 'ssg' : 'ssr'}`;
103
102
  } // server prepare
104
103
 
105
104
 
@@ -132,7 +131,8 @@ export class ModernServer {
132
131
  this.router.reset(usageRoutes); // warmup ssr bundle in production env
133
132
 
134
133
  this.warmupSSRBundle();
135
- await this.prepareFrameHandler(); // Only work when without setting `assetPrefix`.
134
+ await this.prepareFrameHandler();
135
+ await this.prepareBeforeRouteHandler(usageRoutes, distDir); // Only work when without setting `assetPrefix`.
136
136
  // Setting `assetPrefix` means these resources should be uploaded to CDN.
137
137
 
138
138
  const staticPathRegExp = getStaticReg(this.conf.output || {});
@@ -145,7 +145,10 @@ export class ModernServer {
145
145
  staticGenerate
146
146
  });
147
147
  await this.setupBeforeProdMiddleware();
148
- this.addHandler(this.staticFileHandler);
148
+ this.addHandler(this.staticFileHandler); // execute after staticFileHandler, can rename to staticFallbackHandler if needed.
149
+
150
+ this.addHandler(faviconFallbackHandler);
151
+ this.addBeforeRouteHandler();
149
152
  this.addHandler(this.routeHandler.bind(this)); // compose middlewares to http handler
150
153
 
151
154
  this.compose();
@@ -155,6 +158,21 @@ export class ModernServer {
155
158
  onRepack(_) {// empty
156
159
  }
157
160
 
161
+ addBeforeRouteHandler() {
162
+ this.addHandler(async (context, next) => {
163
+ if (this.beforeRouteHandler) {
164
+ await this.beforeRouteHandler(context);
165
+
166
+ if (this.isSend(context.res)) {
167
+ return;
168
+ }
169
+ } // eslint-disable-next-line consistent-return
170
+
171
+
172
+ return next();
173
+ });
174
+ }
175
+
158
176
  onServerChange({
159
177
  filepath
160
178
  }) {
@@ -180,6 +198,26 @@ export class ModernServer {
180
198
  return this.requestHandler.bind(this);
181
199
  }
182
200
 
201
+ async render(req, res, url) {
202
+ req.logger = this.logger;
203
+ req.metrics = this.metrics;
204
+ const context = createContext(req, res);
205
+ const matched = this.router.match(url || context.path);
206
+
207
+ if (!matched) {
208
+ return null;
209
+ }
210
+
211
+ const route = matched.generate(context.url);
212
+ const result = await this.handleWeb(context, route);
213
+
214
+ if (!result) {
215
+ return null;
216
+ }
217
+
218
+ return result.content.toString();
219
+ }
220
+
183
221
  async createHTTPServer(handler) {
184
222
  return createServer(handler);
185
223
  }
@@ -218,6 +256,19 @@ export class ModernServer {
218
256
  render404(context) {
219
257
  context.error(ERROR_DIGEST.ENOTF, '404 Not Found');
220
258
  this.renderErrorPage(context, 404);
259
+ }
260
+
261
+ async prepareBeforeRouteHandler(specs, distDir) {
262
+ const {
263
+ runner
264
+ } = this;
265
+ const handler = await runner.preparebeforeRouteHandler({
266
+ serverRoutes: specs,
267
+ distDir
268
+ }, {
269
+ onLast: () => null
270
+ });
271
+ this.beforeRouteHandler = handler;
221
272
  } // gather frame extension and get framework handler
222
273
 
223
274
 
@@ -261,12 +312,13 @@ export class ModernServer {
261
312
  workDir,
262
313
  runner
263
314
  } = this;
264
- return runner.prepareWebServer({
315
+ const handler = await runner.prepareWebServer({
265
316
  pwd: workDir,
266
317
  config: extension
267
318
  }, {
268
319
  onLast: () => null
269
320
  });
321
+ return handler;
270
322
  }
271
323
 
272
324
  async prepareAPIHandler(extension) {
@@ -292,13 +344,6 @@ export class ModernServer {
292
344
  return routes;
293
345
  }
294
346
 
295
- async emitRouteHook(eventName, input) {
296
- input.context = clone(input.context);
297
- return this.runner[eventName](input, {
298
- onLast: noop
299
- });
300
- }
301
-
302
347
  async setupBeforeProdMiddleware() {
303
348
  const {
304
349
  conf,
@@ -357,51 +402,70 @@ export class ModernServer {
357
402
 
358
403
  async routeHandler(context) {
359
404
  const {
360
- req,
361
405
  res
362
- } = context;
363
- await this.emitRouteHook('beforeMatch', {
364
- context
365
- }); // match routes in the route spec
406
+ } = context; // match routes in the route spec
366
407
 
367
408
  const matched = this.router.match(context.path);
368
409
 
369
410
  if (!matched) {
370
411
  this.render404(context);
371
412
  return;
372
- }
413
+ } // route is api service
373
414
 
374
- if (res.headersSent) {
415
+
416
+ let route = matched.generate(context.url);
417
+
418
+ if (route.isApi) {
419
+ await this.handleAPI(context);
375
420
  return;
376
421
  }
377
422
 
378
- const routeAPI = createRouteAPI(matched, this.router, context.url);
379
- await this.emitRouteHook('afterMatch', {
380
- context,
381
- routeAPI
382
- });
423
+ const afterMatchContext = createAfterMatchContext(context, route.entryName); // only full mode run server hook
424
+
425
+ if (this.runMode === RUN_MODE.FULL) {
426
+ await this.runner.afterMatch(afterMatchContext, {
427
+ onLast: noop
428
+ });
429
+ }
383
430
 
384
431
  if (this.isSend(res)) {
385
432
  return;
386
433
  }
387
434
 
388
435
  const {
389
- current
390
- } = routeAPI;
391
- const route = current.generate(context.url);
436
+ current,
437
+ url,
438
+ status
439
+ } = afterMatchContext.router; // redirect to another url
440
+
441
+ if (url) {
442
+ this.redirect(res, url, status);
443
+ return;
444
+ } // rewrite to another entry
445
+
446
+
447
+ if (route.entryName !== current) {
448
+ const matched = this.router.matchEntry(current);
449
+
450
+ if (!matched) {
451
+ this.render404(context);
452
+ return;
453
+ }
454
+
455
+ route = matched.generate(context.url);
456
+ }
457
+
392
458
  context.setParams(route.params);
393
459
  context.setServerData('router', {
394
460
  baseUrl: route.urlPath,
395
461
  params: route.params
396
- }); // route is api service
397
-
398
- if (route.isApi) {
399
- await this.handleAPI(context);
400
- return;
401
- }
462
+ });
402
463
 
403
464
  if (this.frameWebHandler) {
404
- await this.frameWebHandler(req, res);
465
+ res.locals = res.locals || {};
466
+ const middlewareContext = createMiddlewareContext(context);
467
+ await this.frameWebHandler(middlewareContext);
468
+ res.locals = _objectSpread(_objectSpread({}, res.locals), middlewareContext.response.locals);
405
469
  } // frameWebHandler has process request
406
470
 
407
471
 
@@ -419,23 +483,16 @@ export class ModernServer {
419
483
  });
420
484
  }
421
485
 
422
- if (route.entryName) {
423
- await this.emitRouteHook('beforeRender', {
424
- context
425
- });
426
- }
427
-
428
- const file = await this.handleWeb(context, route);
486
+ const renderResult = await this.handleWeb(context, route);
429
487
 
430
- if (!file) {
488
+ if (!renderResult) {
431
489
  this.render404(context);
432
490
  return;
433
- }
491
+ } // React Router navigation
434
492
 
435
- if (file.redirect) {
436
- res.statusCode = file.statusCode;
437
- res.setHeader('Location', file.content);
438
- res.end();
493
+
494
+ if (renderResult.redirect) {
495
+ this.redirect(res, renderResult.content, renderResult.statusCode);
439
496
  return;
440
497
  }
441
498
 
@@ -443,29 +500,42 @@ export class ModernServer {
443
500
  return;
444
501
  }
445
502
 
446
- let response = file.content;
503
+ res.setHeader('content-type', renderResult.contentType);
504
+ const {
505
+ contentStream
506
+ } = renderResult;
507
+
508
+ if (contentStream) {
509
+ contentStream.pipe(templateInjectableStream({
510
+ prependHead: route.entryName ? `<script>window._SERVER_DATA=${JSON.stringify(context.serverData)}</script>` : undefined
511
+ })).pipe(res);
512
+ return;
513
+ }
514
+
515
+ let response = renderResult.content;
447
516
 
448
517
  if (route.entryName) {
449
- const templateAPI = createTemplateAPI(file.content.toString());
450
- await this.emitRouteHook('afterRender', {
451
- context,
452
- templateAPI
453
- });
518
+ const afterRenderContext = createAfterRenderContext(context, response.toString()); // only full mode run server hook
519
+ // FIXME: how to run server hook in streaming
454
520
 
455
- if (this.isSend(res)) {
456
- return;
521
+ if (this.runMode === RUN_MODE.FULL) {
522
+ await this.runner.afterRender(afterRenderContext, {
523
+ onLast: noop
524
+ });
457
525
  }
458
526
 
459
- await this.injectMicroFE(context, templateAPI); // It will inject _SERVER_DATA twice, when SSG mode.
527
+ if (this.isSend(res)) {
528
+ return;
529
+ } // It will inject _SERVER_DATA twice, when SSG mode.
460
530
  // The first time was in ssg html created, the seoncd time was in prod-server start.
461
531
  // but the second wound causes route error.
462
532
  // To ensure that the second injection fails, the _SERVER_DATA inject at the front of head,
463
533
 
464
- templateAPI.prependHead(`<script>window._SERVER_DATA=${JSON.stringify(context.serverData)}</script>`);
465
- response = templateAPI.get();
534
+
535
+ afterRenderContext.template.prependHead(`<script>window._SERVER_DATA=${JSON.stringify(context.serverData)}</script>`);
536
+ response = afterRenderContext.template.get();
466
537
  }
467
538
 
468
- res.setHeader('content-type', file.contentType);
469
539
  res.end(response);
470
540
  }
471
541
 
@@ -480,72 +550,6 @@ export class ModernServer {
480
550
  }
481
551
 
482
552
  return false;
483
- }
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
553
  } // compose handlers and create the final handler
550
554
 
551
555
 
@@ -612,6 +616,12 @@ export class ModernServer {
612
616
  }
613
617
  }
614
618
 
619
+ redirect(res, url, status = 302) {
620
+ res.setHeader('Location', url);
621
+ res.statusCode = status;
622
+ res.end();
623
+ }
624
+
615
625
  onError(context, err) {
616
626
  context.error(ERROR_DIGEST.EINTER, err);
617
627
  this.renderErrorPage(context, 500);
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createMiddlewareContext = exports.createAfterRenderContext = exports.createAfterMatchContext = exports.base = void 0;
7
+
8
+ var _cookie = _interopRequireDefault(require("cookie"));
9
+
10
+ var _route = require("./route");
11
+
12
+ var _template = require("./template");
13
+
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+
16
+ 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; }
17
+
18
+ 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; }
19
+
20
+ 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; }
21
+
22
+ class Response {
23
+ constructor(res) {
24
+ _defineProperty(this, "cookies", void 0);
25
+
26
+ _defineProperty(this, "res", void 0);
27
+
28
+ _defineProperty(this, "_cookie", void 0);
29
+
30
+ this.res = res;
31
+ this._cookie = _cookie.default.parse(res.getHeader('set-cookie') || '');
32
+ this.cookies = {
33
+ get: this.getCookie.bind(this),
34
+ set: this.setCookie.bind(this),
35
+ delete: this.deleteCookie.bind(this),
36
+ clear: this.clearCookie.bind(this),
37
+ apply: this.applyCookie.bind(this)
38
+ };
39
+ }
40
+
41
+ get(key) {
42
+ return this.res.getHeader(key);
43
+ }
44
+
45
+ set(key, value) {
46
+ return this.res.setHeader(key, value);
47
+ }
48
+
49
+ status(code) {
50
+ this.res.statusCode = code;
51
+ }
52
+
53
+ getCookie(key) {
54
+ return this._cookie[key];
55
+ }
56
+
57
+ setCookie(key, value) {
58
+ this._cookie[key] = value;
59
+ }
60
+
61
+ deleteCookie(key) {
62
+ if (this._cookie[key]) {
63
+ delete this._cookie[key];
64
+ }
65
+ }
66
+
67
+ clearCookie() {
68
+ this._cookie = {};
69
+ }
70
+
71
+ applyCookie() {
72
+ const str = Object.entries(this._cookie).map(([key, value]) => {
73
+ return _cookie.default.serialize(key, value);
74
+ }).join('; ');
75
+
76
+ if (str) {
77
+ this.res.setHeader('set-cookie', str);
78
+ } else {
79
+ this.res.removeHeader('set-cookie');
80
+ }
81
+ }
82
+
83
+ raw(body, {
84
+ status,
85
+ headers
86
+ }) {
87
+ Object.entries(headers).forEach(([key, value]) => {
88
+ this.res.setHeader(key, value);
89
+ });
90
+
91
+ if (status) {
92
+ this.res.statusCode = status;
93
+ }
94
+
95
+ this.res.end(body);
96
+ }
97
+
98
+ }
99
+
100
+ class Request {
101
+ constructor(ctx) {
102
+ _defineProperty(this, "host", void 0);
103
+
104
+ _defineProperty(this, "pathname", void 0);
105
+
106
+ _defineProperty(this, "query", void 0);
107
+
108
+ _defineProperty(this, "headers", void 0);
109
+
110
+ _defineProperty(this, "cookie", void 0);
111
+
112
+ _defineProperty(this, "cookies", void 0);
113
+
114
+ _defineProperty(this, "_cookie", void 0);
115
+
116
+ this.host = ctx.host;
117
+ this.pathname = ctx.path;
118
+ this.query = ctx.query;
119
+ this.headers = ctx.headers;
120
+ this.cookie = ctx.headers.cookie || '';
121
+ this._cookie = _cookie.default.parse(this.cookie);
122
+ this.cookies = {
123
+ get: this.getCookie.bind(this)
124
+ };
125
+ }
126
+
127
+ getCookie(key) {
128
+ return this._cookie[key];
129
+ }
130
+
131
+ }
132
+
133
+ const base = context => {
134
+ const {
135
+ res
136
+ } = context;
137
+ return {
138
+ response: new Response(res),
139
+ request: new Request(context),
140
+ logger: context.logger,
141
+ metrics: context.metrics
142
+ };
143
+ };
144
+
145
+ exports.base = base;
146
+
147
+ const createAfterMatchContext = (context, entryName) => {
148
+ const baseContext = base(context);
149
+ return _objectSpread(_objectSpread({}, baseContext), {}, {
150
+ router: new _route.RouteAPI(entryName)
151
+ });
152
+ };
153
+
154
+ exports.createAfterMatchContext = createAfterMatchContext;
155
+
156
+ const createAfterRenderContext = (context, content) => {
157
+ const baseContext = base(context);
158
+ return _objectSpread(_objectSpread({}, baseContext), {}, {
159
+ template: new _template.TemplateAPI(content)
160
+ });
161
+ };
162
+
163
+ exports.createAfterRenderContext = createAfterRenderContext;
164
+
165
+ const createMiddlewareContext = context => {
166
+ const baseContext = base(context);
167
+ return _objectSpread(_objectSpread({}, baseContext), {}, {
168
+ response: _objectSpread(_objectSpread({}, baseContext.response), {}, {
169
+ locals: context.res.locals || {}
170
+ }),
171
+ source: {
172
+ req: context.req,
173
+ res: context.res
174
+ }
175
+ });
176
+ };
177
+
178
+ exports.createMiddlewareContext = createMiddlewareContext;
@@ -3,51 +3,36 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.createRouteAPI = void 0;
6
+ exports.RouteAPI = void 0;
7
7
 
8
8
  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; }
9
9
 
10
10
  class RouteAPI {
11
- constructor(matched, router, url) {
12
- _defineProperty(this, "router", void 0);
13
-
11
+ constructor(entryName) {
14
12
  _defineProperty(this, "current", void 0);
15
13
 
14
+ _defineProperty(this, "status", void 0);
15
+
16
16
  _defineProperty(this, "url", void 0);
17
17
 
18
- this.current = matched;
19
- this.router = router;
20
- this.url = url;
18
+ this.current = entryName;
19
+ this.status = 200;
20
+ this.url = '';
21
21
  }
22
22
 
23
- cur() {
24
- return this.current.generate(this.url);
23
+ redirect(url, status = 302) {
24
+ this.url = url;
25
+ this.status = status;
25
26
  }
26
27
 
27
- get(entryName) {
28
- const {
29
- router
30
- } = this;
31
- const matched = router.matchEntry(entryName);
32
- return matched ? matched.generate(this.url) : null;
28
+ rewrite(entryName) {
29
+ this.current = entryName;
33
30
  }
34
31
 
35
32
  use(entryName) {
36
- const {
37
- router
38
- } = this;
39
- const matched = router.matchEntry(entryName);
40
-
41
- if (matched) {
42
- this.current = matched;
43
- return true;
44
- } else {
45
- return false;
46
- }
33
+ this.rewrite(entryName);
47
34
  }
48
35
 
49
36
  }
50
37
 
51
- const createRouteAPI = (matched, router, url) => new RouteAPI(matched, router, url);
52
-
53
- exports.createRouteAPI = createRouteAPI;
38
+ exports.RouteAPI = RouteAPI;