@modern-js/server 1.1.3-beta.0 → 1.1.4

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 (42) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/js/modern/dev-tools/babel/register.js +2 -2
  3. package/dist/js/modern/dev-tools/mock/getMockData.js +2 -2
  4. package/dist/js/modern/libs/proxy.js +2 -2
  5. package/dist/js/modern/libs/render/cache/__tests__/cache.test.js +2 -2
  6. package/dist/js/modern/libs/render/cache/index.js +2 -2
  7. package/dist/js/modern/libs/render/cache/type.js +0 -1
  8. package/dist/js/modern/server/dev-server/dev-server-split.js +2 -6
  9. package/dist/js/modern/server/dev-server/dev-server.js +1 -1
  10. package/dist/js/modern/server/dev-server/index.js +1 -1
  11. package/dist/js/modern/server/index.js +17 -14
  12. package/dist/js/modern/server/modern-server-split.js +55 -6
  13. package/dist/js/modern/server/modern-server.js +85 -55
  14. package/dist/js/modern/type.js +0 -1
  15. package/dist/js/modern/utils.js +9 -1
  16. package/dist/js/node/dev-tools/babel/register.js +2 -2
  17. package/dist/js/node/dev-tools/mock/getMockData.js +2 -2
  18. package/dist/js/node/libs/proxy.js +2 -2
  19. package/dist/js/node/libs/render/cache/__tests__/cache.test.js +2 -2
  20. package/dist/js/node/libs/render/cache/index.js +2 -2
  21. package/dist/js/node/server/dev-server/dev-server-split.js +5 -9
  22. package/dist/js/node/server/dev-server/dev-server.js +1 -1
  23. package/dist/js/node/server/dev-server/index.js +4 -4
  24. package/dist/js/node/server/index.js +16 -12
  25. package/dist/js/node/server/modern-server-split.js +61 -9
  26. package/dist/js/node/server/modern-server.js +86 -56
  27. package/dist/js/node/utils.js +12 -2
  28. package/dist/types/server/dev-server/dev-server-split.d.ts +3 -4
  29. package/dist/types/server/dev-server/index.d.ts +1 -1
  30. package/dist/types/server/modern-server-split.d.ts +15 -5
  31. package/dist/types/server/modern-server.d.ts +13 -6
  32. package/dist/types/type.d.ts +5 -0
  33. package/dist/types/utils.d.ts +2 -1
  34. package/package.json +17 -18
  35. package/src/server/dev-server/dev-server-split.ts +3 -7
  36. package/src/server/dev-server/dev-server.ts +7 -11
  37. package/src/server/dev-server/index.ts +1 -1
  38. package/src/server/index.ts +22 -12
  39. package/src/server/modern-server-split.ts +59 -7
  40. package/src/server/modern-server.ts +96 -62
  41. package/src/type.ts +5 -0
  42. package/src/utils.ts +14 -0
@@ -45,7 +45,12 @@ export declare type ModernServerOptions = {
45
45
  logger?: Logger;
46
46
  measure?: Measure;
47
47
  apiOnly?: boolean;
48
+ ssrOnly?: boolean;
48
49
  webOnly?: boolean;
50
+ proxyTarget?: {
51
+ ssr?: string;
52
+ api?: string;
53
+ };
49
54
  };
50
55
  export declare type RenderResult = {
51
56
  content: string | Buffer;
@@ -3,4 +3,5 @@ export declare const mergeExtension: (users: any[]) => {
3
3
  };
4
4
  export declare const toMessage: (dig: string, e: Error | string) => string;
5
5
  export declare const noop: () => void;
6
- export declare const createErrorDocument: (status: number, text: string) => string;
6
+ export declare const createErrorDocument: (status: number, text: string) => string;
7
+ export declare function applyMixins(derivedCtor: any, constructors: any[]): void;
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "modern",
12
12
  "modern.js"
13
13
  ],
14
- "version": "1.1.3-beta.0",
14
+ "version": "1.1.4",
15
15
  "jsnext:source": "./src/index.ts",
16
16
  "types": "./dist/types/index.d.ts",
17
17
  "main": "./dist/js/node/index.js",
@@ -26,14 +26,6 @@
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
- },
37
29
  "dependencies": {
38
30
  "@babel/core": "^7.15.0",
39
31
  "@babel/compat-data": "^7.15.0",
@@ -41,12 +33,12 @@
41
33
  "@babel/preset-typescript": "^7.15.0",
42
34
  "@babel/register": "^7.15.3",
43
35
  "@babel/runtime": "^7",
44
- "@modern-js/core": "workspace:^1.1.2",
45
- "@modern-js/hmr-client": "workspace:^1.1.1",
46
- "@modern-js/server-plugin": "workspace:^1.1.1",
47
- "@modern-js/server-utils": "workspace:^1.1.1",
48
- "@modern-js/bff-utils": "workspace:^1.1.1",
49
- "@modern-js/utils": "workspace:^1.1.2",
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",
50
42
  "axios": "^0.21.4",
51
43
  "babel-plugin-module-resolver": "^4.1.0",
52
44
  "chokidar": "^3.5.2",
@@ -71,7 +63,7 @@
71
63
  "devDependencies": {
72
64
  "@modern-js/module-tools": "^1.1.1",
73
65
  "@modern-js/plugin-testing": "^1.1.1",
74
- "@modern-js/types": "workspace:^1.1.2",
66
+ "@modern-js/types": "^1.1.3",
75
67
  "@types/jest": "^26",
76
68
  "@types/lru-cache": "^5.1.1",
77
69
  "@types/mime-types": "^2.1.0",
@@ -100,5 +92,12 @@
100
92
  "publishConfig": {
101
93
  "registry": "https://registry.npmjs.org/",
102
94
  "access": "public"
103
- }
104
- }
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
+ }
@@ -4,7 +4,7 @@ import { mergeExtension } from '@/utils';
4
4
  import { ModernRouteInterface } from '@/libs/route';
5
5
  import { ApiServerMode } from '@/constants';
6
6
 
7
- export class WebModernDevServer extends ModernDevServer {
7
+ export class ModernSSRDevServer extends ModernDevServer {
8
8
  protected prepareAPIHandler(
9
9
  _m: ApiServerMode,
10
10
  _: APIServerStartInput['config'],
@@ -23,14 +23,10 @@ export class WebModernDevServer extends ModernDevServer {
23
23
  }
24
24
  }
25
25
 
26
- export class APIModernDevServer extends ModernDevServer {
27
- protected prepareWebHandler(_: ReturnType<typeof mergeExtension>) {
28
- return null as any;
29
- }
30
-
26
+ export class ModernAPIDevServer extends ModernDevServer {
31
27
  protected async prepareAPIHandler(
32
28
  mode: ApiServerMode,
33
- extension: ReturnType<typeof mergeExtension>,
29
+ extension: APIServerStartInput['config'],
34
30
  ) {
35
31
  return super.prepareAPIHandler(mode, extension);
36
32
  }
@@ -13,9 +13,7 @@ import {
13
13
  SHARED_DIR,
14
14
  } from '@modern-js/utils';
15
15
  import type { MultiCompiler, Compiler } from 'webpack';
16
- import webpackDevMiddleware, {
17
- WebpackDevMiddleware,
18
- } from 'webpack-dev-middleware';
16
+ import webpackDevMiddleware from 'webpack-dev-middleware';
19
17
  import { ModernServer } from '../modern-server';
20
18
  import { createMockHandler } from '@/dev-tools/mock';
21
19
  import { createProxyHandler, ProxyOptions } from '@/libs/proxy';
@@ -61,12 +59,10 @@ export class ModernDevServer extends ModernServer {
61
59
 
62
60
  private watcher!: Watcher;
63
61
 
64
- private devMiddleware!: WebpackDevMiddleware &
65
- ((
66
- req: http.IncomingMessage,
67
- res: http.ServerResponse,
68
- next: NextFunction,
69
- ) => void);
62
+ private devMiddleware!: webpackDevMiddleware.API<
63
+ http.IncomingMessage,
64
+ http.ServerResponse
65
+ >;
70
66
 
71
67
  constructor(options: ModernServerOptions) {
72
68
  super(options);
@@ -239,7 +235,7 @@ export class ModernDevServer extends ModernServer {
239
235
  const bundles = this.router.getBundles();
240
236
 
241
237
  bundles.forEach(bundle => {
242
- const filepath = path.join(distDir, bundle!);
238
+ const filepath = path.join(distDir, bundle as string);
243
239
  if (require.cache[filepath]) {
244
240
  delete require.cache[filepath];
245
241
  }
@@ -252,7 +248,7 @@ export class ModernDevServer extends ModernServer {
252
248
  const defaultWatched = [
253
249
  `${pwd}/${mock}/**/*`,
254
250
  `${pwd}/${SERVER_DIR}/**/*`,
255
- `${pwd}/${API_DIR}/**/*`,
251
+ `${pwd}/${API_DIR}/!(typings)/**`,
256
252
  `${pwd}/${SHARED_DIR}/**/*`,
257
253
  ];
258
254
 
@@ -1,2 +1,2 @@
1
- export { APIModernDevServer, WebModernDevServer } from './dev-server-split';
1
+ export { ModernAPIDevServer, ModernSSRDevServer } from './dev-server-split';
2
2
  export { ModernDevServer } from './dev-server';
@@ -7,10 +7,16 @@ import {
7
7
  initAppContext,
8
8
  initAppDir,
9
9
  loadUserConfig,
10
+ ConfigContext,
11
+ UserConfig,
10
12
  } from '@modern-js/core';
11
13
  import { ModernServer } from './modern-server';
12
14
  import type { ModernDevServer } from './dev-server';
13
- import { APIModernServer, WebModernServer } from './modern-server-split';
15
+ import {
16
+ ModernAPIServer,
17
+ ModernSSRServer,
18
+ ModernWebServer,
19
+ } from './modern-server-split';
14
20
  import { ModernServerOptions, ServerHookRunner, ReadyOptions } from '@/type';
15
21
  import { measure as defaultMeasure } from '@/libs/measure';
16
22
 
@@ -88,9 +94,11 @@ export class Server {
88
94
  const { options } = this;
89
95
 
90
96
  if (options.apiOnly) {
91
- return new APIModernServer(options);
97
+ return new ModernAPIServer(options);
98
+ } else if (options.ssrOnly) {
99
+ return new ModernSSRServer(options);
92
100
  } else if (options.webOnly) {
93
- return new WebModernServer(options);
101
+ return new ModernWebServer(options);
94
102
  } else {
95
103
  return new ModernServer(options);
96
104
  }
@@ -99,15 +107,15 @@ export class Server {
99
107
  private createDevServer() {
100
108
  const { options } = this;
101
109
  const {
102
- APIModernDevServer,
103
- WebModernDevServer,
110
+ ModernAPIDevServer,
111
+ ModernSSRDevServer,
104
112
  ModernDevServer,
105
113
  } = require('./dev-server');
106
114
 
107
115
  if (options.apiOnly) {
108
- return new APIModernDevServer(options);
109
- } else if (options.webOnly) {
110
- return new WebModernDevServer(options);
116
+ return new ModernAPIDevServer(options);
117
+ } else if (options.ssrOnly) {
118
+ return new ModernSSRDevServer(options);
111
119
  } else {
112
120
  return new ModernDevServer(options);
113
121
  }
@@ -115,8 +123,14 @@ export class Server {
115
123
 
116
124
  private async createHookRunner() {
117
125
  const { options } = this;
126
+
127
+ options.plugins?.forEach(p => {
128
+ serverManager.usePlugin(p);
129
+ });
130
+
118
131
  const appContext = await this.initAppContext();
119
132
  serverManager.run(() => {
133
+ ConfigContext.set(this.options.config as UserConfig);
120
134
  AppContext.set({
121
135
  ...appContext,
122
136
  distDirectory: path.join(
@@ -126,10 +140,6 @@ export class Server {
126
140
  });
127
141
  });
128
142
 
129
- options.plugins?.forEach(p => {
130
- serverManager.usePlugin(p);
131
- });
132
-
133
143
  return serverManager.init({});
134
144
  }
135
145
 
@@ -1,13 +1,26 @@
1
1
  import { APIServerStartInput } from '@modern-js/server-plugin';
2
2
  import { ModernServer } from './modern-server';
3
3
  import { mergeExtension } from '@/utils';
4
- import { ModernRouteInterface } from '@/libs/route';
4
+ import { ModernRoute, ModernRouteInterface, RouteMatcher } from '@/libs/route';
5
5
  import { ApiServerMode } from '@/constants';
6
+ import { ModernServerContext } from '@/libs/context';
7
+
8
+ export class ModernSSRServer extends ModernServer {
9
+ // Todo should not invoke any route hook in modernSSRServer
10
+
11
+ protected async warmupSSRBundle() {
12
+ // empty
13
+ }
14
+
15
+ protected verifyMatch(context: ModernServerContext, matched: RouteMatcher) {
16
+ if (matched.generate().isApi) {
17
+ this.render404(context);
18
+ }
19
+ }
6
20
 
7
- export class WebModernServer extends ModernServer {
8
21
  protected prepareAPIHandler(
9
22
  _m: ApiServerMode,
10
- _: ReturnType<typeof mergeExtension>,
23
+ _: APIServerStartInput['config'],
11
24
  ) {
12
25
  return null as any;
13
26
  }
@@ -18,12 +31,24 @@ export class WebModernServer extends ModernServer {
18
31
  return super.prepareWebHandler(extension);
19
32
  }
20
33
 
21
- protected filterRoutes(routes: ModernRouteInterface[]) {
22
- return routes.filter(route => route.entryName);
34
+ // protected filterRoutes(routes: ModernRouteInterface[]) {
35
+ // return routes.filter(route => route.entryName);
36
+ // }
37
+
38
+ protected async preServerInit() {
39
+ // empty
23
40
  }
24
41
  }
25
42
 
26
- export class APIModernServer extends ModernServer {
43
+ export class ModernAPIServer extends ModernServer {
44
+ protected async emitRouteHook(_: string, _input: any) {
45
+ // empty
46
+ }
47
+
48
+ protected async warmupSSRBundle() {
49
+ // empty
50
+ }
51
+
27
52
  protected prepareWebHandler(_: ReturnType<typeof mergeExtension>) {
28
53
  return null as any;
29
54
  }
@@ -40,6 +65,33 @@ export class APIModernServer extends ModernServer {
40
65
  }
41
66
 
42
67
  protected async preServerInit() {
43
- // noop
68
+ // empty
69
+ }
70
+ }
71
+
72
+ export class ModernWebServer extends ModernServer {
73
+ protected async warmupSSRBundle() {
74
+ // empty
75
+ }
76
+
77
+ protected async handleAPI(context: ModernServerContext) {
78
+ const { proxyTarget } = this;
79
+ if (!proxyTarget?.api) {
80
+ this.proxy();
81
+ } else {
82
+ this.render404(context);
83
+ }
84
+ }
85
+
86
+ protected async handleWeb(context: ModernServerContext, route: ModernRoute) {
87
+ const { proxyTarget } = this;
88
+
89
+ if (route.isSSR && proxyTarget?.ssr) {
90
+ return this.proxy();
91
+ } else {
92
+ // if no proxyTarget but access web server, degradation to csr
93
+ route.isSSR = false;
94
+ return super.handleWeb(context, route);
95
+ }
44
96
  }
45
97
  }
@@ -16,13 +16,18 @@ import {
16
16
  Logger,
17
17
  ReadyOptions,
18
18
  ConfWithBFF,
19
- } from '../type';
20
- import { RouteMatchManager, ModernRouteInterface } from '../libs/route';
21
- import { createRenderHandler } from '../libs/render';
22
- import { createStaticFileHandler } from '../libs/serve-file';
23
- import { createErrorDocument, mergeExtension, noop } from '../utils';
24
- import * as reader from '../libs/render/reader';
25
- import { createProxyHandler, ProxyOptions } from '../libs/proxy';
19
+ } from '@/type';
20
+ import {
21
+ RouteMatchManager,
22
+ ModernRouteInterface,
23
+ ModernRoute,
24
+ RouteMatcher,
25
+ } from '@/libs/route';
26
+ import { createRenderHandler } from '@/libs/render';
27
+ import { createStaticFileHandler } from '@/libs/serve-file';
28
+ import { createErrorDocument, mergeExtension, noop } from '@/utils';
29
+ import * as reader from '@/libs/render/reader';
30
+ import { createProxyHandler, ProxyOptions } from '@/libs/proxy';
26
31
  import { createContext, ModernServerContext } from '@/libs/context';
27
32
  import {
28
33
  AGGRED_DIR,
@@ -70,6 +75,8 @@ export class ModernServer {
70
75
 
71
76
  protected readonly measure: Measure;
72
77
 
78
+ protected readonly proxyTarget: ModernServerOptions['proxyTarget'];
79
+
73
80
  private readonly isDev: boolean = false;
74
81
 
75
82
  private staticFileHandler!: ReturnType<typeof createStaticFileHandler>;
@@ -94,18 +101,20 @@ export class ModernServer {
94
101
  staticGenerate,
95
102
  logger,
96
103
  measure,
104
+ proxyTarget,
97
105
  }: ModernServerOptions) {
98
106
  require('ignore-styles');
99
107
  this.isDev = Boolean(dev);
100
108
 
101
109
  this.pwd = pwd;
102
- this.distDir = path.join(pwd, config.output.path || '');
110
+ this.distDir = path.join(pwd, config.output.path || 'dist');
103
111
  this.workDir = this.isDev ? pwd : this.distDir;
104
112
  this.conf = config;
105
113
  this.logger = logger!;
106
114
  this.measure = measure!;
107
115
  this.router = new RouteMatchManager();
108
116
  this.presetRoutes = routes;
117
+ this.proxyTarget = proxyTarget;
109
118
 
110
119
  if (staticGenerate) {
111
120
  this.staticGenerate = staticGenerate;
@@ -207,18 +216,6 @@ export class ModernServer {
207
216
  return createServer(handler);
208
217
  }
209
218
 
210
- // warmup ssr function
211
- protected warmupSSRBundle() {
212
- const { distDir } = this;
213
- const bundles = this.router.getBundles();
214
-
215
- bundles.forEach(bundle => {
216
- const filepath = path.join(distDir, bundle!);
217
- // if error, just throw and let process die
218
- require(filepath);
219
- });
220
- }
221
-
222
219
  // read route spec from route.json
223
220
  protected readRouteSpec() {
224
221
  const file = path.join(this.distDir, ROUTE_SPEC_FILE);
@@ -272,13 +269,15 @@ export class ModernServer {
272
269
 
273
270
  // if use lambda/, mean framework style of writing, then discard user extension
274
271
  const apiExtension = mergeExtension(pluginAPIExt);
275
- this.frameAPIHandler = await this.prepareAPIHandler(mode, {
276
- ...apiExtension,
277
- modernJsConfig: this.conf,
278
- });
272
+ this.frameAPIHandler = await this.prepareAPIHandler(mode, apiExtension);
279
273
  }
280
274
  }
281
275
 
276
+ // Todo
277
+ protected async proxy() {
278
+ return null as any;
279
+ }
280
+
282
281
  /* —————————————————————— function will be overwrite —————————————————————— */
283
282
  protected async prepareWebHandler(
284
283
  extension: ReturnType<typeof mergeExtension>,
@@ -317,75 +316,89 @@ export class ModernServer {
317
316
  return routes;
318
317
  }
319
318
 
319
+ protected async emitRouteHook(
320
+ eventName: 'beforeMatch' | 'afterMatch' | 'beforeRender' | 'afterRender',
321
+ input: any,
322
+ ) {
323
+ return this.runner[eventName](input, { onLast: noop as any });
324
+ }
325
+
326
+ // warmup ssr function
327
+ protected warmupSSRBundle() {
328
+ const { distDir } = this;
329
+ const bundles = this.router.getBundles();
330
+
331
+ bundles.forEach(bundle => {
332
+ const filepath = path.join(distDir, bundle as string);
333
+ // if error, just throw and let process die
334
+ require(filepath);
335
+ });
336
+ }
337
+
320
338
  protected async preServerInit() {
321
- const { conf } = this;
339
+ const { conf, runner } = this;
322
340
  const preMiddleware: ModernServerAsyncHandler[] =
323
- await this.runner.preServerInit(conf);
341
+ await runner.preServerInit(conf);
324
342
 
325
343
  preMiddleware.flat().forEach(mid => {
326
344
  this.addHandler(mid);
327
345
  });
328
346
  }
329
347
 
330
- private prepareFavicons(
331
- favicon: string | undefined,
332
- faviconByEntries?: Record<string, string | undefined>,
333
- ) {
334
- const faviconNames = [];
335
- if (favicon) {
336
- faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
337
- }
338
- if (faviconByEntries) {
339
- Object.keys(faviconByEntries).forEach(f => {
340
- const curFavicon = faviconByEntries[f];
341
- if (curFavicon) {
342
- faviconNames.push(
343
- curFavicon.substring(curFavicon.lastIndexOf('/') + 1),
344
- );
345
- }
346
- });
348
+ protected async handleAPI(context: ModernServerContext) {
349
+ const { req, res } = context;
350
+
351
+ if (!this.frameAPIHandler) {
352
+ throw new Error('can not found api hanlder');
347
353
  }
348
- return faviconNames;
354
+
355
+ await this.frameAPIHandler(req, res);
349
356
  }
350
357
 
351
- /* —————————————————————— private function —————————————————————— */
358
+ protected async handleWeb(context: ModernServerContext, route: ModernRoute) {
359
+ return this.routeRenderHandler(context, route);
360
+ }
361
+
362
+ protected verifyMatch(_c: ModernServerContext, _m: RouteMatcher) {
363
+ // empty
364
+ }
352
365
 
366
+ /* —————————————————————— private function —————————————————————— */
353
367
  // handler route.json, include api / csr / ssr
354
368
  // eslint-disable-next-line max-statements
355
369
  private async routeHandler(context: ModernServerContext) {
356
370
  const { req, res } = context;
357
371
 
358
- await this.runner.beforeMatch({ context }, { onLast: noop as any });
372
+ await this.emitRouteHook('beforeMatch', { context });
359
373
 
360
374
  // match routes in the route spec
361
375
  const matched = this.router.match(context.url);
362
376
  if (!matched) {
363
377
  this.render404(context);
364
378
  return;
379
+ } else {
380
+ this.verifyMatch(context, matched);
381
+ }
382
+
383
+ if (res.headersSent) {
384
+ return;
365
385
  }
366
386
 
367
387
  const routeAPI = createRouteAPI(matched, this.router);
368
- await this.runner.afterMatch(
369
- { context, routeAPI },
370
- { onLast: noop as any },
371
- );
388
+ await this.emitRouteHook('afterMatch', { context, routeAPI });
372
389
 
373
390
  if (res.headersSent) {
374
391
  return;
375
392
  }
376
393
 
377
394
  const { current } = routeAPI as any;
378
- const route = current.generate();
395
+ const route: ModernRoute = current.generate();
379
396
  const params = current.parseURLParams(context.url);
380
397
  context.setParams(params);
381
398
 
382
399
  // route is api service
383
400
  if (route.isApi) {
384
- if (!this.frameAPIHandler) {
385
- throw new Error('can not found api hanlder');
386
- }
387
-
388
- await this.frameAPIHandler(req, res);
401
+ this.handleAPI(context);
389
402
  return;
390
403
  }
391
404
 
@@ -398,8 +411,11 @@ export class ModernServer {
398
411
  return;
399
412
  }
400
413
 
401
- await this.runner.beforeRender({ context }, { onLast: noop as any });
402
- const file = await this.routeRenderHandler(context, route);
414
+ if (route.entryName) {
415
+ await this.emitRouteHook('beforeRender', { context });
416
+ }
417
+
418
+ const file = await this.handleWeb(context, route);
403
419
  if (!file) {
404
420
  this.render404(context);
405
421
  return;
@@ -415,10 +431,7 @@ export class ModernServer {
415
431
  let response = file.content;
416
432
  if (route.entryName) {
417
433
  const templateAPI = createTemplateAPI(file.content.toString());
418
- await this.runner.afterRender(
419
- { context, templateAPI },
420
- { onLast: noop as any },
421
- );
434
+ await this.emitRouteHook('afterRender', { context, templateAPI });
422
435
  await this.injectMicroFE(context, templateAPI);
423
436
  response = templateAPI.get();
424
437
  }
@@ -581,5 +594,26 @@ export class ModernServer {
581
594
  const text = ERROR_PAGE_TEXT[status] || ERROR_PAGE_TEXT[500];
582
595
  res.end(createErrorDocument(status, text));
583
596
  }
597
+
598
+ private prepareFavicons(
599
+ favicon: string | undefined,
600
+ faviconByEntries?: Record<string, string | undefined>,
601
+ ) {
602
+ const faviconNames = [];
603
+ if (favicon) {
604
+ faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
605
+ }
606
+ if (faviconByEntries) {
607
+ Object.keys(faviconByEntries).forEach(f => {
608
+ const curFavicon = faviconByEntries[f];
609
+ if (curFavicon) {
610
+ faviconNames.push(
611
+ curFavicon.substring(curFavicon.lastIndexOf('/') + 1),
612
+ );
613
+ }
614
+ });
615
+ }
616
+ return faviconNames;
617
+ }
584
618
  }
585
619
  /* eslint-enable max-lines */
package/src/type.ts CHANGED
@@ -49,7 +49,12 @@ export type ModernServerOptions = {
49
49
  logger?: Logger;
50
50
  measure?: Measure;
51
51
  apiOnly?: boolean;
52
+ ssrOnly?: boolean;
52
53
  webOnly?: boolean;
54
+ proxyTarget?: {
55
+ ssr?: string;
56
+ api?: string;
57
+ };
53
58
  };
54
59
 
55
60
  export type RenderResult = {
package/src/utils.ts CHANGED
@@ -49,3 +49,17 @@ export const createErrorDocument = (status: number, text: string) => {
49
49
  </html>
50
50
  `;
51
51
  };
52
+
53
+ // This can live anywhere in your codebase:
54
+ export function applyMixins(derivedCtor: any, constructors: any[]) {
55
+ constructors.forEach(baseCtor => {
56
+ Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
57
+ Object.defineProperty(
58
+ derivedCtor.prototype,
59
+ name,
60
+ Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
61
+ Object.create(null),
62
+ );
63
+ });
64
+ });
65
+ }