@modern-js/server 1.3.1-beta.0 → 1.4.1

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 (126) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/js/modern/dev-tools/babel/register.js +1 -0
  3. package/dist/js/modern/dev-tools/dev-server-plugin.js +1 -2
  4. package/dist/js/modern/dev-tools/mock/getMockData.js +24 -1
  5. package/dist/js/modern/dev-tools/mock/index.js +1 -26
  6. package/dist/js/modern/dev-tools/socket-server.js +4 -2
  7. package/dist/js/modern/dev-tools/watcher/index.js +4 -7
  8. package/dist/js/modern/dev-tools/watcher/stats-cache.js +32 -20
  9. package/dist/js/modern/libs/context/context.js +6 -0
  10. package/dist/js/modern/libs/hook-api/route.js +6 -4
  11. package/dist/js/modern/libs/render/index.js +1 -0
  12. package/dist/js/modern/libs/render/reader.js +1 -2
  13. package/dist/js/modern/libs/render/ssr.js +7 -2
  14. package/dist/js/modern/libs/route/index.js +0 -1
  15. package/dist/js/modern/libs/route/matcher.js +15 -3
  16. package/dist/js/modern/libs/route/route.js +1 -0
  17. package/dist/js/modern/server/dev-server/dev-server.js +3 -0
  18. package/dist/js/modern/server/index.js +5 -4
  19. package/dist/js/modern/server/modern-server-split.js +1 -1
  20. package/dist/js/modern/server/modern-server.js +13 -34
  21. package/dist/js/modern/utils.js +39 -0
  22. package/dist/js/node/dev-tools/babel/register.js +1 -0
  23. package/dist/js/node/dev-tools/dev-server-plugin.js +1 -2
  24. package/dist/js/node/dev-tools/mock/getMockData.js +29 -2
  25. package/dist/js/node/dev-tools/mock/index.js +5 -26
  26. package/dist/js/node/dev-tools/socket-server.js +4 -2
  27. package/dist/js/node/dev-tools/watcher/index.js +7 -5
  28. package/dist/js/node/dev-tools/watcher/stats-cache.js +33 -20
  29. package/dist/js/node/libs/context/context.js +6 -0
  30. package/dist/js/node/libs/hook-api/route.js +6 -4
  31. package/dist/js/node/libs/render/index.js +1 -0
  32. package/dist/js/node/libs/render/reader.js +2 -1
  33. package/dist/js/node/libs/render/ssr.js +8 -2
  34. package/dist/js/node/libs/route/index.js +0 -1
  35. package/dist/js/node/libs/route/matcher.js +16 -3
  36. package/dist/js/node/libs/route/route.js +1 -0
  37. package/dist/js/node/server/dev-server/dev-server.js +3 -0
  38. package/dist/js/node/server/index.js +9 -6
  39. package/dist/js/node/server/modern-server-split.js +1 -1
  40. package/dist/js/node/server/modern-server.js +12 -33
  41. package/dist/js/node/utils.js +51 -2
  42. package/dist/types/dev-tools/mock/getMockData.d.ts +2 -1
  43. package/dist/types/dev-tools/socket-server.d.ts +1 -2
  44. package/dist/types/dev-tools/watcher/index.d.ts +2 -1
  45. package/dist/types/dev-tools/watcher/stats-cache.d.ts +3 -2
  46. package/dist/types/libs/context/context.d.ts +2 -0
  47. package/dist/types/libs/hook-api/route.d.ts +3 -2
  48. package/dist/types/libs/render/reader.d.ts +13 -0
  49. package/dist/types/libs/render/ssr.d.ts +1 -0
  50. package/dist/types/libs/route/matcher.d.ts +1 -1
  51. package/dist/types/libs/route/route.d.ts +1 -0
  52. package/dist/types/server/dev-server/dev-server-split.d.ts +3 -3
  53. package/dist/types/server/modern-server-split.d.ts +3 -3
  54. package/dist/types/server/modern-server.d.ts +1 -2
  55. package/dist/types/type.d.ts +6 -4
  56. package/dist/types/utils.d.ts +5 -1
  57. package/package.json +13 -12
  58. package/tests/context.test.ts +12 -1
  59. package/tests/dev.test.ts +306 -7
  60. package/tests/fixtures/mock/exist/config/mock/index.ts +11 -0
  61. package/tests/fixtures/mock/zero/config/mock/index.ts +1 -0
  62. package/tests/fixtures/pure/tsconfig.json +0 -1
  63. package/tests/fixtures/reader/index.ts +3 -0
  64. package/tests/fixtures/route-spec/dynamic.json +13 -0
  65. package/tests/fixtures/ssr/bundle.js +5 -0
  66. package/tests/fixtures/static-dir/bar.html +11 -0
  67. package/tests/fixtures/static-dir/baz/index.html +11 -0
  68. package/tests/fixtures/static-dir/foo/index.html +11 -0
  69. package/tests/fixtures/watch/a.ts +3 -0
  70. package/tests/fixtures/watch/index.ts +5 -0
  71. package/tests/fixtures/watch/stats.txt +1 -0
  72. package/tests/hook.test.ts +1 -1
  73. package/tests/render.test.ts +102 -0
  74. package/tests/route.test.ts +26 -3
  75. package/tests/utils.test.ts +35 -0
  76. package/tests/watcher.test.ts +6 -4
  77. package/src/constants.ts +0 -26
  78. package/src/dev-tools/babel/register.ts +0 -37
  79. package/src/dev-tools/dev-server-plugin.ts +0 -48
  80. package/src/dev-tools/https/global.d.ts +0 -3
  81. package/src/dev-tools/https/index.ts +0 -12
  82. package/src/dev-tools/launch-editor/index.ts +0 -29
  83. package/src/dev-tools/mock/getMockData.ts +0 -109
  84. package/src/dev-tools/mock/index.ts +0 -63
  85. package/src/dev-tools/socket-server.ts +0 -192
  86. package/src/dev-tools/watcher/dependency-tree.ts +0 -94
  87. package/src/dev-tools/watcher/index.ts +0 -81
  88. package/src/dev-tools/watcher/stats-cache.ts +0 -53
  89. package/src/index.ts +0 -16
  90. package/src/libs/context/context.ts +0 -176
  91. package/src/libs/context/index.ts +0 -7
  92. package/src/libs/hook-api/route.ts +0 -38
  93. package/src/libs/hook-api/template.ts +0 -53
  94. package/src/libs/metrics.ts +0 -15
  95. package/src/libs/proxy.ts +0 -85
  96. package/src/libs/render/cache/__tests__/cache.fun.test.ts +0 -94
  97. package/src/libs/render/cache/__tests__/cache.test.ts +0 -240
  98. package/src/libs/render/cache/__tests__/cacheable.ts +0 -44
  99. package/src/libs/render/cache/__tests__/error-configuration.ts +0 -34
  100. package/src/libs/render/cache/__tests__/matched-cache.ts +0 -88
  101. package/src/libs/render/cache/index.ts +0 -75
  102. package/src/libs/render/cache/page-caches/index.ts +0 -11
  103. package/src/libs/render/cache/page-caches/lru.ts +0 -38
  104. package/src/libs/render/cache/spr.ts +0 -301
  105. package/src/libs/render/cache/type.ts +0 -59
  106. package/src/libs/render/cache/util.ts +0 -97
  107. package/src/libs/render/index.ts +0 -78
  108. package/src/libs/render/modern/browser-list.ts +0 -7
  109. package/src/libs/render/modern/index.ts +0 -41
  110. package/src/libs/render/modern/module.d.ts +0 -4
  111. package/src/libs/render/reader.ts +0 -119
  112. package/src/libs/render/ssr.ts +0 -62
  113. package/src/libs/render/static.ts +0 -52
  114. package/src/libs/render/type.ts +0 -38
  115. package/src/libs/route/index.ts +0 -77
  116. package/src/libs/route/matcher.ts +0 -93
  117. package/src/libs/route/route.ts +0 -32
  118. package/src/libs/serve-file.ts +0 -34
  119. package/src/server/dev-server/dev-server-split.ts +0 -41
  120. package/src/server/dev-server/dev-server.ts +0 -300
  121. package/src/server/dev-server/index.ts +0 -2
  122. package/src/server/index.ts +0 -163
  123. package/src/server/modern-server-split.ts +0 -97
  124. package/src/server/modern-server.ts +0 -636
  125. package/src/type.ts +0 -88
  126. package/src/utils.ts +0 -79
package/CHANGELOG.md CHANGED
@@ -1,5 +1,73 @@
1
1
  # @modern-js/server
2
2
 
3
+ ## 1.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 2cfc4235: support cssPath/jsPath/mediaPath in production mode
8
+ - 8d55e234: fix: catch api error
9
+ - Updated dependencies [53aca274]
10
+ - Updated dependencies [78279953]
11
+ - Updated dependencies [e116ace5]
12
+ - Updated dependencies [4d72edea]
13
+ - @modern-js/core@1.4.1
14
+ - @modern-js/utils@1.3.1
15
+
16
+ ## 1.4.0
17
+
18
+ ### Minor Changes
19
+
20
+ - ec4dbffb: feat: support as a pure api service
21
+
22
+ ### Patch Changes
23
+
24
+ - 816fd721: support more server context
25
+ - d9cc5ea9: support resatrt options transfer
26
+ - bfbea9a7: support multi base url and dynamic base url
27
+ - d099e5c5: fix error when modify modern.config.js
28
+ - 24f616ca: feat: support custom meta info
29
+ - 272cab15: refactor server plugin manager
30
+ - Updated dependencies [d9cc5ea9]
31
+ - Updated dependencies [bd819a8d]
32
+ - Updated dependencies [ec4dbffb]
33
+ - Updated dependencies [d099e5c5]
34
+ - Updated dependencies [bada2879]
35
+ - Updated dependencies [24f616ca]
36
+ - Updated dependencies [bd819a8d]
37
+ - Updated dependencies [272cab15]
38
+ - @modern-js/core@1.4.0
39
+ - @modern-js/utils@1.3.0
40
+ - @modern-js/server-core@1.2.2
41
+
42
+ ## 1.3.2
43
+
44
+ ### Patch Changes
45
+
46
+ - 83166714: change .npmignore
47
+ - Updated dependencies [83166714]
48
+ - Updated dependencies [c3de9882]
49
+ - Updated dependencies [33ff48af]
50
+ - @modern-js/core@1.3.2
51
+ - @modern-js/bff-utils@1.2.2
52
+ - @modern-js/hmr-client@1.2.1
53
+ - @modern-js/server-plugin@1.2.1
54
+ - @modern-js/server-utils@1.2.1
55
+ - @modern-js/utils@1.2.2
56
+
57
+ ## 1.3.1
58
+
59
+ ### Patch Changes
60
+
61
+ - e2d3a575: fix extending core config interface
62
+ - 823809c6: fix: hot reload not working on windows
63
+ - e2d3a575: fix extending core config interface
64
+ - Updated dependencies [823809c6]
65
+ - Updated dependencies [4584cc04]
66
+ - Updated dependencies [7c19fd94]
67
+ - @modern-js/bff-utils@1.2.1
68
+ - @modern-js/utils@1.2.1
69
+ - @modern-js/core@1.3.1
70
+
3
71
  ## 1.3.0
4
72
 
5
73
  ### Minor Changes
@@ -18,6 +18,7 @@ export const enableRegister = (projectRoot, config) => {
18
18
  return require('@babel/register')(_objectSpread(_objectSpread({}, babelConfig), {}, {
19
19
  only: [function (filePath) {
20
20
  // TODO: wait params
21
+ // FIXME: 删除hardcode,根据 AppContext 中的 metaName 设置路径
21
22
  if (filePath.includes(`node_modules${path.sep}.modern-js`)) {
22
23
  return true;
23
24
  }
@@ -14,8 +14,7 @@ export default class DevServerPlugin {
14
14
  } = this;
15
15
  const host = `&host=${options.client.host || 'localhost'}`;
16
16
  const path = `&path=${options.client.path}`;
17
- const port = `&port=${options.client.port}`; // Todo @songzhenwei
18
-
17
+ const port = `&port=${options.client.port}`;
19
18
  const clientEntry = `${require.resolve('@modern-js/hmr-client')}?${host}${path}${port}`;
20
19
 
21
20
  const hotEntry = require.resolve('webpack/hot/dev-server');
@@ -5,6 +5,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
5
5
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
6
 
7
7
  import { compatRequire } from '@modern-js/utils';
8
+ import { match } from 'path-to-regexp';
8
9
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
9
10
  const VALID_METHODS = ['get', 'post', 'put', 'delete', 'patch']; // eslint-disable-next-line @typescript-eslint/no-unused-vars
10
11
 
@@ -81,4 +82,26 @@ export default (filepath => {
81
82
 
82
83
  const data = normalizeConfig(mockModule);
83
84
  return data;
84
- });
85
+ });
86
+ export const getMatched = (context, mockApiList) => {
87
+ const {
88
+ path: targetPathname,
89
+ method: targetMethod
90
+ } = context;
91
+ const matched = mockApiList.find(mockApi => {
92
+ const {
93
+ method,
94
+ path: pathname
95
+ } = mockApi;
96
+
97
+ if (method.toLowerCase() === targetMethod.toLowerCase()) {
98
+ return match(pathname, {
99
+ encode: encodeURI,
100
+ decode: decodeURIComponent
101
+ })(targetPathname);
102
+ }
103
+
104
+ return false;
105
+ });
106
+ return matched;
107
+ };
@@ -1,32 +1,7 @@
1
1
  import path from 'path';
2
2
  import { fs } from '@modern-js/utils';
3
- import { match } from 'path-to-regexp';
4
3
  import { AGGRED_DIR } from "../../constants";
5
- import getMockData from "./getMockData";
6
-
7
- const getMatched = (context, mockApiList) => {
8
- const {
9
- path: targetPathname,
10
- method: targetMethod
11
- } = context;
12
- const matched = mockApiList.find(mockApi => {
13
- const {
14
- method,
15
- path: pathname
16
- } = mockApi;
17
-
18
- if (method.toLowerCase() === targetMethod.toLowerCase()) {
19
- return match(pathname, {
20
- encode: encodeURI,
21
- decode: decodeURIComponent
22
- })(targetPathname);
23
- }
24
-
25
- return false;
26
- });
27
- return matched;
28
- };
29
-
4
+ import getMockData, { getMatched } from "./getMockData";
30
5
  export const createMockHandler = ({
31
6
  pwd
32
7
  }) => {
@@ -106,8 +106,10 @@ export default class SocketServer {
106
106
  });
107
107
  }
108
108
 
109
- close(connection) {
110
- connection.close();
109
+ close() {
110
+ this.sockets.forEach(socket => {
111
+ socket.close();
112
+ });
111
113
  } // get standard stats
112
114
 
113
115
 
@@ -1,18 +1,17 @@
1
+ import path from 'path';
1
2
  import chokidar from 'chokidar';
2
3
  import { DependencyTree } from "./dependency-tree";
3
4
  import { StatsCache } from "./stats-cache";
4
-
5
- const getWatchedFiles = watcher => {
5
+ export const getWatchedFiles = watcher => {
6
6
  const watched = watcher.getWatched();
7
7
  const files = [];
8
8
  Object.keys(watched).forEach(dir => {
9
9
  watched[dir].forEach(fileName => {
10
- files.push(`${dir}/${fileName}`);
10
+ files.push(path.join(dir, fileName));
11
11
  });
12
12
  });
13
13
  return files;
14
14
  };
15
-
16
15
  export default class Watcher {
17
16
  constructor() {
18
17
  this.dependencyTree = null;
@@ -21,9 +20,7 @@ export default class Watcher {
21
20
 
22
21
  listen(files, options, callback) {
23
22
  const watched = files.filter(Boolean);
24
- const filenames = watched.map(filename => filename.replace(/\\/g, '/')); // eslint-disable-next-line no-console
25
-
26
- console.log('watched files:', filenames);
23
+ const filenames = watched.map(filename => filename.replace(/\\/g, '/'));
27
24
  const cache = new StatsCache();
28
25
  const watcher = chokidar.watch(filenames, options);
29
26
  watcher.on('ready', () => {
@@ -1,20 +1,24 @@
1
1
  import fs from 'fs';
2
+ import crypto from 'crypto';
2
3
  export class StatsCache {
3
4
  constructor() {
4
- this.cachedStats = {};
5
+ this.cachedHash = {};
6
+ this.cachedSize = {};
5
7
  }
6
8
 
7
9
  add(files) {
8
10
  const {
9
- cachedStats
11
+ cachedHash,
12
+ cachedSize
10
13
  } = this;
11
14
 
12
15
  for (const filename of files) {
13
16
  if (fs.existsSync(filename)) {
14
- const stat = fs.statSync(filename);
17
+ const stats = fs.statSync(filename);
15
18
 
16
- if (stat.isFile() && !cachedStats[filename]) {
17
- cachedStats[filename] = this.sign(stat);
19
+ if (stats.isFile() && !cachedHash[filename]) {
20
+ cachedHash[filename] = this.hash(stats, filename);
21
+ cachedSize[filename] = stats.size;
18
22
  }
19
23
  }
20
24
  }
@@ -22,32 +26,41 @@ export class StatsCache {
22
26
 
23
27
  refresh(filename) {
24
28
  const {
25
- cachedStats
29
+ cachedHash,
30
+ cachedSize
26
31
  } = this;
27
32
 
28
33
  if (fs.existsSync(filename)) {
29
- const stat = fs.statSync(filename);
34
+ const stats = fs.statSync(filename);
30
35
 
31
- if (stat.isFile()) {
32
- cachedStats[filename] = this.sign(stat);
36
+ if (stats.isFile()) {
37
+ cachedHash[filename] = this.hash(stats, filename);
38
+ cachedSize[filename] = stats.size;
33
39
  }
34
40
  }
35
41
  }
36
42
 
37
43
  del(filename) {
38
- if (this.cachedStats[filename]) {
39
- delete this.cachedStats[filename];
44
+ if (this.cachedHash[filename]) {
45
+ delete this.cachedHash[filename];
46
+ delete this.cachedSize[filename];
40
47
  }
41
48
  }
42
49
 
43
50
  isDiff(filename) {
44
51
  const {
45
- cachedStats
52
+ cachedHash,
53
+ cachedSize
46
54
  } = this;
47
- const stat = fs.statSync(filename);
48
- const cachedStat = cachedStats[filename];
55
+ const stats = fs.statSync(filename);
56
+ const hash = cachedHash[filename];
57
+ const size = cachedSize[filename];
49
58
 
50
- if (this.sign(stat) !== cachedStat) {
59
+ if (stats.size !== size) {
60
+ return true;
61
+ }
62
+
63
+ if (this.hash(stats, filename) !== hash) {
51
64
  return true;
52
65
  }
53
66
 
@@ -55,12 +68,11 @@ export class StatsCache {
55
68
  }
56
69
 
57
70
  has(filename) {
58
- return Boolean(this.cachedStats[filename]);
59
- } // Todo size 其实有点问题,修改单个字符会导致触发不了 change
60
-
71
+ return Boolean(this.cachedHash[filename]);
72
+ }
61
73
 
62
- sign(stat) {
63
- return stat.size;
74
+ hash(stats, filename) {
75
+ return crypto.createHash('md5').update(fs.readFileSync(filename)).digest('hex');
64
76
  }
65
77
 
66
78
  }
@@ -19,10 +19,12 @@ export class ModernServerContext {
19
19
  this.params = {};
20
20
  this.logger = void 0;
21
21
  this.metrics = void 0;
22
+ this.serverData = void 0;
22
23
  this.req = req;
23
24
  this.res = res;
24
25
  this.logger = req.logger;
25
26
  this.metrics = req.metrics;
27
+ this.serverData = {};
26
28
  this.bind();
27
29
  }
28
30
 
@@ -41,6 +43,10 @@ export class ModernServerContext {
41
43
  this.params = params;
42
44
  }
43
45
 
46
+ setServerData(key, value) {
47
+ this.serverData[key] = value;
48
+ }
49
+
44
50
  getReqHeader(key) {
45
51
  const {
46
52
  req
@@ -1,13 +1,15 @@
1
1
  class RouteAPI {
2
- constructor(matched, router) {
2
+ constructor(matched, router, url) {
3
3
  this.router = void 0;
4
4
  this.current = void 0;
5
+ this.url = void 0;
5
6
  this.current = matched;
6
7
  this.router = router;
8
+ this.url = url;
7
9
  }
8
10
 
9
11
  cur() {
10
- return this.current.generate();
12
+ return this.current.generate(this.url);
11
13
  }
12
14
 
13
15
  get(entryName) {
@@ -15,7 +17,7 @@ class RouteAPI {
15
17
  router
16
18
  } = this;
17
19
  const matched = router.matchEntry(entryName);
18
- return matched ? matched.generate() : null;
20
+ return matched ? matched.generate(this.url) : null;
19
21
  }
20
22
 
21
23
  use(entryName) {
@@ -34,4 +36,4 @@ class RouteAPI {
34
36
 
35
37
  }
36
38
 
37
- export const createRouteAPI = (matched, router) => new RouteAPI(matched, router);
39
+ export const createRouteAPI = (matched, router, url) => new RouteAPI(matched, router, url);
@@ -40,6 +40,7 @@ export const createRenderHandler = ({
40
40
  const result = await ssr.render(ctx, {
41
41
  distDir,
42
42
  entryName: route.entryName,
43
+ urlPath: route.urlPath,
43
44
  bundle: route.bundle,
44
45
  template: templateHTML,
45
46
  staticGenerate
@@ -14,7 +14,7 @@ const createCacheItem = async (filepath, mtime) => {
14
14
  };
15
15
  };
16
16
 
17
- class LruReader {
17
+ export class LruReader {
18
18
  // private timer?: NodeJS.Timeout;
19
19
  constructor() {
20
20
  this.cache = void 0;
@@ -96,7 +96,6 @@ class LruReader {
96
96
 
97
97
 
98
98
  }
99
-
100
99
  const reader = new LruReader();
101
100
  export const readFile = async filepath => {
102
101
  const file = await reader.read(filepath);
@@ -1,9 +1,11 @@
1
1
  import path from 'path';
2
2
  import { SERVER_RENDER_FUNCTION_NAME } from '@modern-js/utils';
3
3
  import mime from 'mime-types';
4
+ import cookie from 'cookie';
4
5
  import cache from "./cache";
5
6
  export const render = async (ctx, renderOptions, runner) => {
6
7
  const {
8
+ urlPath,
7
9
  bundle,
8
10
  distDir,
9
11
  template,
@@ -13,11 +15,14 @@ export const render = async (ctx, renderOptions, runner) => {
13
15
  const bundleJS = path.join(distDir, bundle);
14
16
  const context = {
15
17
  request: {
18
+ baseUrl: urlPath,
16
19
  params: ctx.params,
17
20
  pathname: ctx.path,
21
+ host: ctx.host,
18
22
  query: ctx.query,
19
- headers: ctx.headers,
20
- cookie: ctx.headers.cookie
23
+ url: ctx.href,
24
+ cookieMap: cookie.parse(ctx.headers.cookie || ''),
25
+ headers: ctx.headers
21
26
  },
22
27
  redirection: {},
23
28
  template,
@@ -9,7 +9,6 @@ export class RouteMatchManager {
9
9
 
10
10
  filter(pathname) {
11
11
  return this.matchers.reduce((matches, matcher) => {
12
- // 非网关来的,或网关匹配上之后,内部再进行一次自己的匹配
13
12
  if (matcher.matchUrlPath(pathname)) {
14
13
  matches.push(matcher);
15
14
  }
@@ -1,5 +1,6 @@
1
1
  import { removeTailSlash } from '@modern-js/utils';
2
2
  import { match, pathToRegexp } from 'path-to-regexp';
3
+ import { toPath } from "../../utils";
3
4
  import { ModernRoute } from "./route"; // eslint-disable-next-line no-useless-escape
4
5
 
5
6
  const regCharsDetector = /[^a-zA-Z\-_0-9\/\.]/;
@@ -14,8 +15,16 @@ export class RouteMatcher {
14
15
  } // generate modern route object
15
16
 
16
17
 
17
- generate() {
18
- return new ModernRoute(this.spec);
18
+ generate(url) {
19
+ const route = new ModernRoute(this.spec);
20
+
21
+ if (this.urlPath) {
22
+ const params = this.parseURLParams(url);
23
+ route.urlPath = toPath(route.urlPath, params);
24
+ route.params = params;
25
+ }
26
+
27
+ return route;
19
28
  }
20
29
 
21
30
  parseURLParams(pathname) {
@@ -73,9 +82,12 @@ export class RouteMatcher {
73
82
 
74
83
  if (useReg) {
75
84
  this.urlMatcher = match(urlPath, {
85
+ end: false,
76
86
  decode: decodeURIComponent
77
87
  });
78
- this.urlReg = pathToRegexp(urlPath);
88
+ this.urlReg = pathToRegexp(urlPath, [], {
89
+ end: false
90
+ });
79
91
  }
80
92
  }
81
93
 
@@ -10,6 +10,7 @@ export class ModernRoute {
10
10
  this.isSSR = void 0;
11
11
  this.isSPA = void 0;
12
12
  this.enableModernMode = void 0;
13
+ this.params = {};
13
14
  this.entryName = routeSpec.entryName || '';
14
15
  this.urlPath = routeSpec.urlPath;
15
16
  this.entryPath = routeSpec.entryPath || '';
@@ -118,6 +118,8 @@ export class ModernDevServer extends ModernServer {
118
118
  }
119
119
 
120
120
  async close() {
121
+ var _this$socketServer2;
122
+
121
123
  super.close();
122
124
  await this.watcher.close();
123
125
  await new Promise(resolve => {
@@ -129,6 +131,7 @@ export class ModernDevServer extends ModernServer {
129
131
  resolve();
130
132
  }
131
133
  });
134
+ (_this$socketServer2 = this.socketServer) === null || _this$socketServer2 === void 0 ? void 0 : _this$socketServer2.close();
132
135
  }
133
136
 
134
137
  async createHTTPServer(handler) {
@@ -5,9 +5,9 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
5
5
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
6
 
7
7
  import path from 'path';
8
- import { serverManager } from '@modern-js/server-plugin';
9
- import { logger as defaultLogger } from '@modern-js/utils';
10
- import { AppContext, initAppContext, initAppDir, loadUserConfig, ConfigContext } from '@modern-js/core';
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';
11
11
  import { metrics as defaultMetrics } from "../libs/metrics";
12
12
  import { ModernServer } from "./modern-server";
13
13
  import { ModernAPIServer, ModernSSRServer, ModernWebServer } from "./modern-server-split";
@@ -115,8 +115,9 @@ export class Server {
115
115
  const {
116
116
  options
117
117
  } = this;
118
+ serverManager.clear();
118
119
  (_options$plugins = options.plugins) === null || _options$plugins === void 0 ? void 0 : _options$plugins.forEach(p => {
119
- serverManager.usePlugin(p);
120
+ serverManager.usePlugin(compatRequire(p.pluginPath));
120
121
  });
121
122
  const appContext = await this.initAppContext();
122
123
  serverManager.run(() => {
@@ -5,7 +5,7 @@ export class ModernSSRServer extends ModernServer {
5
5
  }
6
6
 
7
7
  verifyMatch(context, matched) {
8
- if (matched.generate().isApi) {
8
+ if (matched.generate(context.url).isApi) {
9
9
  this.render404(context);
10
10
  }
11
11
  }
@@ -21,7 +21,7 @@ import clone from 'lodash.clone';
21
21
  import { RouteMatchManager } from "../libs/route";
22
22
  import { createRenderHandler } from "../libs/render";
23
23
  import { createStaticFileHandler } from "../libs/serve-file";
24
- import { createErrorDocument, createMiddlewareCollecter, mergeExtension, noop } from "../utils";
24
+ import { createErrorDocument, createMiddlewareCollecter, getStaticReg, mergeExtension, noop } from "../utils";
25
25
  import * as reader from "../libs/render/reader";
26
26
  import { createProxyHandler } from "../libs/proxy";
27
27
  import { createContext } from "../libs/context";
@@ -126,15 +126,10 @@ export class ModernServer {
126
126
  this.warmupSSRBundle();
127
127
  }
128
128
 
129
- await this.prepareFrameHandler();
130
- const {
131
- favicon,
132
- faviconByEntries
133
- } = this.conf.output || {};
134
- const favicons = this.prepareFavicons(favicon, faviconByEntries); // Only work when without setting `assetPrefix`.
129
+ await this.prepareFrameHandler(); // Only work when without setting `assetPrefix`.
135
130
  // Setting `assetPrefix` means these resources should be uploaded to CDN.
136
131
 
137
- const staticPathRegExp = new RegExp(`^/(static/|upload/|favicon.ico|icon.png${favicons.length > 0 ? `|${favicons.join('|')}` : ''})`);
132
+ const staticPathRegExp = getStaticReg(this.conf.output || {});
138
133
  this.staticFileHandler = createStaticFileHandler([{
139
134
  path: staticPathRegExp,
140
135
  target: distDir
@@ -353,7 +348,7 @@ export class ModernServer {
353
348
  return;
354
349
  }
355
350
 
356
- const routeAPI = createRouteAPI(matched, this.router);
351
+ const routeAPI = createRouteAPI(matched, this.router, context.url);
357
352
  await this.emitRouteHook('afterMatch', {
358
353
  context,
359
354
  routeAPI
@@ -366,12 +361,15 @@ export class ModernServer {
366
361
  const {
367
362
  current
368
363
  } = routeAPI;
369
- const route = current.generate();
370
- const params = current.parseURLParams(context.url);
371
- context.setParams(params); // route is api service
364
+ const route = current.generate(context.url);
365
+ context.setParams(route.params);
366
+ context.setServerData('router', {
367
+ baseUrl: route.urlPath,
368
+ params: route.params
369
+ }); // route is api service
372
370
 
373
371
  if (route.isApi) {
374
- this.handleAPI(context);
372
+ await this.handleAPI(context);
375
373
  return;
376
374
  }
377
375
 
@@ -413,6 +411,7 @@ export class ModernServer {
413
411
  templateAPI
414
412
  });
415
413
  await this.injectMicroFE(context, templateAPI);
414
+ templateAPI.appendHead(`<script>window._SERVER_DATA=${JSON.stringify(context.serverData)}</script>`);
416
415
  response = templateAPI.get();
417
416
  }
418
417
 
@@ -555,7 +554,7 @@ export class ModernServer {
555
554
  const matched = this.router.match(statusPage) || this.router.match(customErrorPage); // if no custom status page find
556
555
 
557
556
  if (matched) {
558
- const route = matched.generate();
557
+ const route = matched.generate(context.url);
559
558
  const {
560
559
  entryName
561
560
  } = route; // check entryName, aviod matched '/' route
@@ -581,25 +580,5 @@ export class ModernServer {
581
580
  res.end(createErrorDocument(status, text));
582
581
  }
583
582
 
584
- prepareFavicons(favicon, faviconByEntries) {
585
- const faviconNames = [];
586
-
587
- if (favicon) {
588
- faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
589
- }
590
-
591
- if (faviconByEntries) {
592
- Object.keys(faviconByEntries).forEach(f => {
593
- const curFavicon = faviconByEntries[f];
594
-
595
- if (curFavicon) {
596
- faviconNames.push(curFavicon.substring(curFavicon.lastIndexOf('/') + 1));
597
- }
598
- });
599
- }
600
-
601
- return faviconNames;
602
- }
603
-
604
583
  }
605
584
  /* eslint-enable max-lines */
@@ -1,3 +1,4 @@
1
+ import { compile } from 'path-to-regexp';
1
2
  export const mergeExtension = users => {
2
3
  const output = [];
3
4
  return {
@@ -70,4 +71,42 @@ export const createMiddlewareCollecter = () => {
70
71
  addWebMiddleware,
71
72
  addAPIMiddleware
72
73
  };
74
+ };
75
+ export const toPath = (reg, params) => {
76
+ const fn = compile(reg, {
77
+ encode: encodeURIComponent
78
+ });
79
+ return fn(params);
80
+ };
81
+ export const getStaticReg = (output = {}) => {
82
+ const {
83
+ favicon,
84
+ faviconByEntries,
85
+ cssPath,
86
+ jsPath,
87
+ mediaPath
88
+ } = output;
89
+ const favicons = prepareFavicons(favicon, faviconByEntries);
90
+ const staticFiles = [cssPath, jsPath, mediaPath].filter(v => Boolean(v));
91
+ const staticPathRegExp = new RegExp(`^/(static/|upload/|favicon.ico|icon.png${favicons.length > 0 ? `|${favicons.join('|')}` : ''}|${staticFiles.join('|')})`);
92
+ return staticPathRegExp;
93
+ };
94
+ export const prepareFavicons = (favicon, faviconByEntries) => {
95
+ const faviconNames = [];
96
+
97
+ if (favicon) {
98
+ faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
99
+ }
100
+
101
+ if (faviconByEntries) {
102
+ Object.keys(faviconByEntries).forEach(f => {
103
+ const curFavicon = faviconByEntries[f];
104
+
105
+ if (curFavicon) {
106
+ faviconNames.push(curFavicon.substring(curFavicon.lastIndexOf('/') + 1));
107
+ }
108
+ });
109
+ }
110
+
111
+ return faviconNames;
73
112
  };