@modern-js/runtime 1.21.5 → 2.0.0-beta.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 (256) hide show
  1. package/CHANGELOG.md +117 -18
  2. package/dist/js/modern/cli/index.js +3 -5
  3. package/dist/js/modern/core/app-config.js +2 -1
  4. package/dist/js/modern/core/compatible.js +47 -48
  5. package/dist/js/modern/core/index.js +4 -3
  6. package/dist/js/modern/core/loader/loaderManager.js +12 -34
  7. package/dist/js/modern/core/loader/useLoader.js +8 -26
  8. package/dist/js/modern/core/plugin.js +6 -28
  9. package/dist/js/modern/document/Body.js +17 -0
  10. package/dist/js/modern/document/DocumentContext.js +6 -0
  11. package/dist/js/modern/document/DocumentStructrueContext.js +7 -0
  12. package/dist/js/modern/document/Head.js +24 -0
  13. package/dist/js/modern/document/Html.js +92 -0
  14. package/dist/js/modern/document/Root.js +31 -0
  15. package/dist/js/modern/document/Scripts.js +10 -0
  16. package/dist/js/modern/document/cli/index.js +130 -0
  17. package/dist/js/modern/document/constants.js +19 -0
  18. package/dist/js/modern/document/index.js +8 -0
  19. package/dist/js/modern/index.js +2 -1
  20. package/dist/js/modern/router/cli/index.js +20 -20
  21. package/dist/js/modern/router/runtime/index.js +1 -1
  22. package/dist/js/modern/router/runtime/plugin.js +25 -52
  23. package/dist/js/modern/router/runtime/plugin.node.js +137 -0
  24. package/dist/js/modern/router/runtime/root/index.js +19 -0
  25. package/dist/js/modern/router/runtime/root/load.js +61 -0
  26. package/dist/js/modern/router/runtime/types.js +1 -0
  27. package/dist/js/modern/router/runtime/utils.js +99 -58
  28. package/dist/js/modern/router/runtime/withRouter.js +20 -0
  29. package/dist/js/modern/runtime-context.js +2 -1
  30. package/dist/js/modern/ssr/cli/index.js +35 -17
  31. package/dist/js/modern/ssr/index.js +64 -51
  32. package/dist/js/modern/ssr/index.node.js +6 -15
  33. package/dist/js/modern/ssr/prefetch.js +0 -7
  34. package/dist/js/modern/ssr/react/prerender/index.js +2 -23
  35. package/dist/js/modern/ssr/react/prerender/util.js +2 -17
  36. package/dist/js/modern/ssr/react/withCallback/index.js +0 -1
  37. package/dist/js/modern/ssr/serverRender/helmet.js +12 -20
  38. package/dist/js/modern/ssr/serverRender/index.js +12 -27
  39. package/dist/js/modern/ssr/serverRender/renderToStream/buildTemplate.after.js +38 -0
  40. package/dist/js/modern/ssr/serverRender/renderToStream/buildTemplate.share.js +5 -0
  41. package/dist/js/modern/ssr/serverRender/renderToStream/bulidTemplate.before.js +58 -0
  42. package/dist/js/modern/ssr/serverRender/renderToStream/index.js +40 -0
  43. package/dist/js/modern/ssr/serverRender/renderToStream/loadable.js +24 -0
  44. package/dist/js/modern/ssr/serverRender/renderToStream/renderToPipe.js +72 -0
  45. package/dist/js/modern/ssr/serverRender/renderToStream/styledComponent.js +11 -0
  46. package/dist/js/modern/ssr/serverRender/renderToStream/template.js +18 -0
  47. package/dist/js/modern/ssr/serverRender/renderToStream/type.js +0 -0
  48. package/dist/js/modern/ssr/serverRender/{entry.js → renderToString/entry.js} +6 -40
  49. package/dist/js/modern/ssr/serverRender/renderToString/index.js +29 -0
  50. package/dist/js/modern/ssr/serverRender/{loadable.js → renderToString/loadable.js} +2 -24
  51. package/dist/js/modern/ssr/serverRender/{reduce.js → renderToString/reduce.js} +0 -2
  52. package/dist/js/modern/ssr/serverRender/{styledComponent.js → renderToString/styledComponent.js} +0 -0
  53. package/dist/js/modern/ssr/serverRender/{template.js → renderToString/template.js} +0 -15
  54. package/dist/js/modern/ssr/serverRender/{type.js → renderToString/type.js} +0 -2
  55. package/dist/js/modern/ssr/serverRender/types.js +2 -0
  56. package/dist/js/modern/ssr/serverRender/utils.js +20 -0
  57. package/dist/js/modern/ssr/utils.js +8 -13
  58. package/dist/js/modern/state/cli/index.js +0 -10
  59. package/dist/js/modern/state/runtime/plugin.js +1 -14
  60. package/dist/js/node/cli/index.js +3 -13
  61. package/dist/js/node/common.js +0 -2
  62. package/dist/js/node/core/app-config.js +2 -5
  63. package/dist/js/node/core/compatible.js +47 -66
  64. package/dist/js/node/core/index.js +8 -17
  65. package/dist/js/node/core/loader/index.js +0 -2
  66. package/dist/js/node/core/loader/loaderManager.js +12 -37
  67. package/dist/js/node/core/loader/useLoader.js +8 -31
  68. package/dist/js/node/core/plugin.js +5 -34
  69. package/dist/js/node/document/Body.js +26 -0
  70. package/dist/js/node/document/DocumentContext.js +14 -0
  71. package/dist/js/node/document/DocumentStructrueContext.js +15 -0
  72. package/dist/js/node/document/Head.js +33 -0
  73. package/dist/js/node/document/Html.js +98 -0
  74. package/dist/js/node/document/Root.js +41 -0
  75. package/dist/js/node/document/Scripts.js +17 -0
  76. package/dist/js/node/document/cli/index.js +140 -0
  77. package/dist/js/node/document/constants.js +36 -0
  78. package/dist/js/node/document/index.js +93 -0
  79. package/dist/js/node/exports/head.js +0 -5
  80. package/dist/js/node/exports/loadable.js +0 -5
  81. package/dist/js/node/exports/server.js +0 -2
  82. package/dist/js/node/exports/styled.js +0 -5
  83. package/dist/js/node/index.js +5 -5
  84. package/dist/js/node/router/cli/index.js +20 -24
  85. package/dist/js/node/router/index.js +0 -4
  86. package/dist/js/node/router/runtime/DefaultNotFound.js +1 -5
  87. package/dist/js/node/router/runtime/index.js +4 -9
  88. package/dist/js/node/router/runtime/plugin.js +23 -65
  89. package/dist/js/node/router/runtime/plugin.node.js +147 -0
  90. package/dist/js/node/router/runtime/root/index.js +26 -0
  91. package/dist/js/node/router/runtime/root/load.js +69 -0
  92. package/dist/js/node/router/runtime/types.js +5 -0
  93. package/dist/js/node/router/runtime/utils.js +101 -67
  94. package/dist/js/node/router/runtime/withRouter.js +26 -0
  95. package/dist/js/node/runtime-context.js +4 -4
  96. package/dist/js/node/ssr/cli/index.js +35 -21
  97. package/dist/js/node/ssr/index.js +63 -62
  98. package/dist/js/node/ssr/index.node.js +6 -25
  99. package/dist/js/node/ssr/prefetch.js +0 -11
  100. package/dist/js/node/ssr/react/index.js +0 -2
  101. package/dist/js/node/ssr/react/nossr/index.js +0 -6
  102. package/dist/js/node/ssr/react/prerender/index.js +2 -30
  103. package/dist/js/node/ssr/react/prerender/util.js +2 -25
  104. package/dist/js/node/ssr/react/withCallback/index.js +1 -4
  105. package/dist/js/node/ssr/serverRender/helmet.js +13 -20
  106. package/dist/js/node/ssr/serverRender/index.js +14 -39
  107. package/dist/js/node/ssr/serverRender/renderToStream/buildTemplate.after.js +45 -0
  108. package/dist/js/node/ssr/serverRender/renderToStream/buildTemplate.share.js +13 -0
  109. package/dist/js/node/ssr/serverRender/renderToStream/bulidTemplate.before.js +65 -0
  110. package/dist/js/node/ssr/serverRender/renderToStream/index.js +48 -0
  111. package/dist/js/node/ssr/serverRender/renderToStream/loadable.js +30 -0
  112. package/dist/js/node/ssr/serverRender/renderToStream/renderToPipe.js +79 -0
  113. package/dist/js/node/ssr/serverRender/renderToStream/styledComponent.js +17 -0
  114. package/dist/js/node/ssr/serverRender/renderToStream/template.js +25 -0
  115. package/dist/js/node/ssr/serverRender/renderToStream/type.js +0 -0
  116. package/dist/js/node/ssr/serverRender/{entry.js → renderToString/entry.js} +13 -64
  117. package/dist/js/node/ssr/serverRender/renderToString/index.js +37 -0
  118. package/dist/js/node/ssr/serverRender/{loadable.js → renderToString/loadable.js} +3 -28
  119. package/dist/js/node/ssr/serverRender/{reduce.js → renderToString/reduce.js} +0 -3
  120. package/dist/js/node/ssr/serverRender/{styledComponent.js → renderToString/styledComponent.js} +0 -3
  121. package/dist/js/node/ssr/serverRender/{template.js → renderToString/template.js} +0 -18
  122. package/dist/js/node/ssr/serverRender/{type.js → renderToString/type.js} +0 -2
  123. package/dist/js/node/ssr/serverRender/types.js +12 -0
  124. package/dist/js/node/ssr/serverRender/utils.js +28 -0
  125. package/dist/js/node/ssr/utils.js +10 -21
  126. package/dist/js/node/state/cli/index.js +0 -15
  127. package/dist/js/node/state/index.js +0 -4
  128. package/dist/js/node/state/plugins.js +0 -11
  129. package/dist/js/node/state/runtime/index.js +0 -7
  130. package/dist/js/node/state/runtime/plugin.js +1 -25
  131. package/dist/js/treeshaking/cli/index.js +3 -3
  132. package/dist/js/treeshaking/core/app-config.js +2 -1
  133. package/dist/js/treeshaking/core/compatible.js +50 -65
  134. package/dist/js/treeshaking/core/index.js +4 -3
  135. package/dist/js/treeshaking/core/loader/loaderManager.js +19 -51
  136. package/dist/js/treeshaking/core/loader/useLoader.js +11 -28
  137. package/dist/js/treeshaking/core/plugin.js +6 -51
  138. package/dist/js/treeshaking/document/Body.js +14 -0
  139. package/dist/js/treeshaking/document/DocumentContext.js +6 -0
  140. package/dist/js/treeshaking/document/DocumentStructrueContext.js +7 -0
  141. package/dist/js/treeshaking/document/Head.js +21 -0
  142. package/dist/js/treeshaking/document/Html.js +104 -0
  143. package/dist/js/treeshaking/document/Root.js +24 -0
  144. package/dist/js/treeshaking/document/Scripts.js +10 -0
  145. package/dist/js/treeshaking/document/cli/index.js +170 -0
  146. package/dist/js/treeshaking/document/constants.js +16 -0
  147. package/dist/js/treeshaking/document/index.js +8 -0
  148. package/dist/js/treeshaking/index.js +2 -1
  149. package/dist/js/treeshaking/router/cli/index.js +26 -22
  150. package/dist/js/treeshaking/router/runtime/index.js +1 -1
  151. package/dist/js/treeshaking/router/runtime/plugin.js +28 -54
  152. package/dist/js/treeshaking/router/runtime/plugin.node.js +161 -0
  153. package/dist/js/treeshaking/router/runtime/root/index.js +17 -0
  154. package/dist/js/treeshaking/router/runtime/root/load.js +102 -0
  155. package/dist/js/treeshaking/router/runtime/types.js +1 -0
  156. package/dist/js/treeshaking/router/runtime/utils.js +104 -58
  157. package/dist/js/treeshaking/router/runtime/withRouter.js +18 -0
  158. package/dist/js/treeshaking/runtime-context.js +2 -1
  159. package/dist/js/treeshaking/ssr/cli/index.js +43 -23
  160. package/dist/js/treeshaking/ssr/index.js +74 -59
  161. package/dist/js/treeshaking/ssr/index.node.js +18 -31
  162. package/dist/js/treeshaking/ssr/prefetch.js +0 -13
  163. package/dist/js/treeshaking/ssr/react/nossr/index.js +3 -4
  164. package/dist/js/treeshaking/ssr/react/prerender/index.js +2 -21
  165. package/dist/js/treeshaking/ssr/react/prerender/util.js +3 -20
  166. package/dist/js/treeshaking/ssr/react/withCallback/index.js +1 -2
  167. package/dist/js/treeshaking/ssr/serverRender/helmet.js +12 -11
  168. package/dist/js/treeshaking/ssr/serverRender/index.js +33 -55
  169. package/dist/js/treeshaking/ssr/serverRender/renderToStream/buildTemplate.after.js +32 -0
  170. package/dist/js/treeshaking/ssr/serverRender/renderToStream/buildTemplate.share.js +7 -0
  171. package/dist/js/treeshaking/ssr/serverRender/renderToStream/bulidTemplate.before.js +60 -0
  172. package/dist/js/treeshaking/ssr/serverRender/renderToStream/index.js +50 -0
  173. package/dist/js/treeshaking/ssr/serverRender/renderToStream/loadable.js +22 -0
  174. package/dist/js/treeshaking/ssr/serverRender/renderToStream/renderToPipe.js +68 -0
  175. package/dist/js/treeshaking/ssr/serverRender/renderToStream/styledComponent.js +10 -0
  176. package/dist/js/treeshaking/ssr/serverRender/renderToStream/template.js +22 -0
  177. package/dist/js/treeshaking/ssr/serverRender/renderToStream/type.js +0 -0
  178. package/dist/js/treeshaking/ssr/serverRender/{entry.js → renderToString/entry.js} +23 -76
  179. package/dist/js/treeshaking/ssr/serverRender/renderToString/index.js +44 -0
  180. package/dist/js/treeshaking/ssr/serverRender/{loadable.js → renderToString/loadable.js} +7 -34
  181. package/dist/js/treeshaking/ssr/serverRender/{reduce.js → renderToString/reduce.js} +0 -2
  182. package/dist/js/treeshaking/ssr/serverRender/{styledComponent.js → renderToString/styledComponent.js} +0 -0
  183. package/dist/js/treeshaking/ssr/serverRender/{template.js → renderToString/template.js} +2 -18
  184. package/dist/js/treeshaking/ssr/serverRender/{type.js → renderToString/type.js} +0 -2
  185. package/dist/js/treeshaking/ssr/serverRender/types.js +2 -0
  186. package/dist/js/treeshaking/ssr/serverRender/utils.js +28 -0
  187. package/dist/js/treeshaking/ssr/utils.js +20 -17
  188. package/dist/js/treeshaking/state/cli/index.js +3 -10
  189. package/dist/js/treeshaking/state/runtime/plugin.js +2 -10
  190. package/dist/types/cli/index.d.ts +0 -2
  191. package/dist/types/common.d.ts +0 -2
  192. package/dist/types/core/compatible.d.ts +2 -2
  193. package/dist/types/core/index.d.ts +2 -2
  194. package/dist/types/core/loader/loaderManager.d.ts +0 -1
  195. package/dist/types/core/loader/useLoader.d.ts +0 -5
  196. package/dist/types/core/plugin.d.ts +2 -14
  197. package/dist/types/document/Body.d.ts +4 -0
  198. package/dist/types/document/DocumentContext.d.ts +13 -0
  199. package/dist/types/document/DocumentStructrueContext.d.ts +10 -0
  200. package/dist/types/document/Head.d.ts +5 -0
  201. package/dist/types/document/Html.d.ts +4 -0
  202. package/dist/types/document/Root.d.ts +8 -0
  203. package/dist/types/document/Scripts.d.ts +2 -0
  204. package/dist/types/document/cli/index.d.ts +3 -0
  205. package/dist/types/document/constants.d.ts +14 -0
  206. package/dist/types/document/index.d.ts +8 -0
  207. package/dist/types/exports/server.d.ts +21 -1
  208. package/dist/types/index.d.ts +2 -1
  209. package/dist/types/router/cli/index.d.ts +0 -2
  210. package/dist/types/router/runtime/DefaultNotFound.d.ts +1 -0
  211. package/dist/types/router/runtime/index.d.ts +3 -3
  212. package/dist/types/router/runtime/plugin.d.ts +2 -45
  213. package/dist/types/router/runtime/plugin.node.d.ts +8 -0
  214. package/dist/types/router/runtime/root/index.d.ts +8 -0
  215. package/dist/types/router/runtime/root/load.d.ts +22 -0
  216. package/dist/types/router/runtime/types.d.ts +36 -0
  217. package/dist/types/router/runtime/utils.d.ts +5 -2
  218. package/dist/types/router/runtime/withRouter.d.ts +8 -0
  219. package/dist/types/runtime-context.d.ts +3 -1
  220. package/dist/types/ssr/cli/index.d.ts +0 -2
  221. package/dist/types/ssr/index.d.ts +2 -2
  222. package/dist/types/ssr/index.node.d.ts +1 -1
  223. package/dist/types/ssr/prefetch.d.ts +2 -2
  224. package/dist/types/ssr/react/nossr/index.d.ts +3 -1
  225. package/dist/types/ssr/serverRender/index.d.ts +2 -3
  226. package/dist/types/ssr/serverRender/renderToStream/buildTemplate.after.d.ts +7 -0
  227. package/dist/types/ssr/serverRender/renderToStream/buildTemplate.share.d.ts +3 -0
  228. package/dist/types/ssr/serverRender/renderToStream/bulidTemplate.before.d.ts +2 -0
  229. package/dist/types/ssr/serverRender/renderToStream/index.d.ts +6 -0
  230. package/dist/types/ssr/serverRender/renderToStream/loadable.d.ts +16 -0
  231. package/dist/types/ssr/serverRender/renderToStream/renderToPipe.d.ts +8 -0
  232. package/dist/types/ssr/serverRender/renderToStream/styledComponent.d.ts +12 -0
  233. package/dist/types/ssr/serverRender/renderToStream/template.d.ts +3 -0
  234. package/dist/types/ssr/serverRender/renderToStream/type.d.ts +4 -0
  235. package/dist/types/ssr/serverRender/{entry.d.ts → renderToString/entry.d.ts} +2 -2
  236. package/dist/types/ssr/serverRender/renderToString/index.d.ts +6 -0
  237. package/dist/types/ssr/serverRender/{loadable.d.ts → renderToString/loadable.d.ts} +0 -0
  238. package/dist/types/ssr/serverRender/{reduce.d.ts → renderToString/reduce.d.ts} +0 -0
  239. package/dist/types/ssr/serverRender/{styledComponent.d.ts → renderToString/styledComponent.d.ts} +0 -0
  240. package/dist/types/ssr/serverRender/{template.d.ts → renderToString/template.d.ts} +0 -0
  241. package/dist/types/ssr/serverRender/{type.d.ts → renderToString/type.d.ts} +1 -8
  242. package/dist/types/ssr/serverRender/types.d.ts +15 -0
  243. package/dist/types/ssr/serverRender/utils.d.ts +3 -0
  244. package/dist/types/ssr/utils.d.ts +4 -2
  245. package/dist/types/state/cli/index.d.ts +0 -2
  246. package/dist/types/state/runtime/plugin.d.ts +1 -1
  247. package/dist/types/state/types.d.ts +0 -1
  248. package/package.json +63 -71
  249. package/types/index.d.ts +13 -0
  250. package/types/router.d.ts +14 -0
  251. package/dist/js/modern/ssr/serverRender/measure.js +0 -11
  252. package/dist/js/node/ssr/serverRender/measure.js +0 -20
  253. package/dist/js/treeshaking/ssr/serverRender/measure.js +0 -17
  254. package/dist/types/ssr/serverRender/measure.d.ts +0 -1
  255. package/lib/types.d.ts +0 -10
  256. package/type.d.ts +0 -5
@@ -1,5 +1,22 @@
1
1
  import { getEntryOptions, SERVER_RENDER_FUNCTION_NAME, LOADABLE_STATS_FILE, isUseSSRBundle, createRuntimeExportsUtils, isSingleEntry } from '@modern-js/utils';
2
2
  const PLUGIN_IDENTIFIER = 'ssr';
3
+ const hasStringSSREntry = userConfig => {
4
+ const isStreaming = ssr => ssr && typeof ssr === 'object' && ssr.mode === 'stream';
5
+ const {
6
+ server
7
+ } = userConfig;
8
+ if (server !== null && server !== void 0 && server.ssr && !isStreaming(server.ssr)) {
9
+ return true;
10
+ }
11
+ if (server !== null && server !== void 0 && server.ssrByEntries && typeof server.ssrByEntries === 'object') {
12
+ for (const name of Object.keys(server.ssrByEntries)) {
13
+ if (!isStreaming(server.ssrByEntries[name])) {
14
+ return true;
15
+ }
16
+ }
17
+ }
18
+ return false;
19
+ };
3
20
  export default (() => ({
4
21
  name: '@modern-js/plugin-ssr',
5
22
  required: ['@modern-js/runtime'],
@@ -22,11 +39,9 @@ export default (() => ({
22
39
  CHAIN_ID
23
40
  }) => {
24
41
  const userConfig = api.useResolvedConfigContext();
25
-
26
- if (isUseSSRBundle(userConfig) && name !== 'server') {
42
+ if (isUseSSRBundle(userConfig) && name !== 'server' && hasStringSSREntry(userConfig)) {
27
43
  // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
28
- const LoadableWebpackPlugin = require('@modern-js/webpack/@loadable/webpack-plugin');
29
-
44
+ const LoadableWebpackPlugin = require('@loadable/webpack-plugin');
30
45
  chain.plugin(CHAIN_ID.PLUGIN.LOADABLE).use(LoadableWebpackPlugin, [{
31
46
  filename: LOADABLE_STATS_FILE
32
47
  }]);
@@ -34,34 +49,43 @@ export default (() => ({
34
49
  },
35
50
  babel: config => {
36
51
  const userConfig = api.useResolvedConfigContext();
37
-
38
- if (isUseSSRBundle(userConfig)) {
52
+ if (isUseSSRBundle(userConfig) && hasStringSSREntry(userConfig)) {
39
53
  config.plugins.push(require.resolve('@loadable/babel-plugin'));
40
54
  }
41
55
  }
42
56
  }
43
57
  };
44
58
  },
45
-
46
59
  modifyEntryImports({
47
60
  entrypoint,
48
61
  imports
49
62
  }) {
50
63
  const {
51
- entryName
64
+ entryName,
65
+ fileSystemRoutes
52
66
  } = entrypoint;
53
67
  const userConfig = api.useResolvedConfigContext();
54
68
  const {
55
69
  packageName,
56
70
  entrypoints
57
71
  } = api.useAppContext();
58
- pluginsExportsUtils.addExport(`export { default as ssr } from '@modern-js/runtime/ssr'`); // if use ssg then set ssr config to true
72
+ pluginsExportsUtils.addExport(`export { default as ssr } from '@modern-js/runtime/ssr'`);
59
73
 
74
+ // if use ssg then set ssr config to true
60
75
  const ssrConfig = getEntryOptions(entryName, userConfig.server.ssr, userConfig.server.ssrByEntries, packageName);
76
+ if (typeof ssrConfig === 'object' && ssrConfig.mode === 'stream') {
77
+ var _runtimeConfig$router;
78
+ const runtimeConfig = getEntryOptions(entryName, userConfig.runtime, userConfig.runtimeByEntries, packageName);
79
+ if (runtimeConfig !== null && runtimeConfig !== void 0 && (_runtimeConfig$router = runtimeConfig.router) !== null && _runtimeConfig$router !== void 0 && _runtimeConfig$router.legacy) {
80
+ throw new Error(`Legacy router plugin doesn't support streaming SSR, check your config 'runtime.router'`);
81
+ }
82
+ if (fileSystemRoutes && !entrypoint.nestedRoutesEntry) {
83
+ throw new Error(`You should switch to file-system based router to support streaming SSR.`);
84
+ }
85
+ }
61
86
  const ssgConfig = userConfig.output.ssg;
62
87
  const useSSG = isSingleEntry(entrypoints) ? Boolean(ssgConfig) : ssgConfig === true || typeof (ssgConfig === null || ssgConfig === void 0 ? void 0 : ssgConfig[0]) === 'function' || Boolean(ssgConfig === null || ssgConfig === void 0 ? void 0 : ssgConfig[entryName]);
63
88
  ssrConfigMap.set(entryName, ssrConfig || useSSG);
64
-
65
89
  if (ssrConfig || useSSG) {
66
90
  imports.push({
67
91
  value: '@modern-js/runtime/plugins',
@@ -70,13 +94,11 @@ export default (() => ({
70
94
  }]
71
95
  });
72
96
  }
73
-
74
97
  return {
75
98
  entrypoint,
76
99
  imports
77
100
  };
78
101
  },
79
-
80
102
  modifyEntryRuntimePlugins({
81
103
  entrypoint,
82
104
  plugins
@@ -84,16 +106,14 @@ export default (() => ({
84
106
  if (ssrConfigMap.get(entrypoint.entryName)) {
85
107
  plugins.push({
86
108
  name: PLUGIN_IDENTIFIER,
87
- options: ssrConfigMap.get(entrypoint.entryName)
109
+ options: JSON.stringify(ssrConfigMap.get(entrypoint.entryName))
88
110
  });
89
111
  }
90
-
91
112
  return {
92
113
  entrypoint,
93
114
  plugins
94
115
  };
95
116
  },
96
-
97
117
  modifyEntryExport({
98
118
  entrypoint,
99
119
  exportStatement
@@ -106,13 +126,11 @@ export default (() => ({
106
126
  }`, exportStatement].join('\n')
107
127
  };
108
128
  }
109
-
110
129
  return {
111
130
  entrypoint,
112
131
  exportStatement
113
132
  };
114
133
  }
115
-
116
134
  };
117
135
  }
118
136
  }));
@@ -1,17 +1,13 @@
1
1
  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; }
2
-
3
2
  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; }
4
-
5
3
  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
-
7
4
  import { loadableReady } from '@loadable/component';
8
5
  import hoistNonReactStatics from 'hoist-non-react-statics';
9
- import { RenderLevel } from "./serverRender/type";
6
+ import { RenderLevel } from "./serverRender/types";
10
7
  import { WithCallback } from "./react/withCallback";
11
- import { formatClient, mockResponse } from "./utils";
8
+ import { formatClient, mockResponse, isReact18 } from "./utils";
12
9
  import { jsx as _jsx } from "react/jsx-runtime";
13
- const IS_REACT18 = process.env.IS_REACT18 === 'true';
14
- export const ssr = _ => ({
10
+ export const ssr = config => ({
15
11
  name: '@modern-js/plugin-ssr',
16
12
  setup: () => {
17
13
  const mockResp = mockResponse();
@@ -23,58 +19,80 @@ export const ssr = _ => ({
23
19
  ModernHydrate
24
20
  }) => {
25
21
  var _window, _window$_SSR_DATA;
22
+ const hydrateContext = _objectSpread(_objectSpread({}, context), {}, {
23
+ _hydration: true
24
+ });
25
+ const callback = () => {
26
+ // won't cause component re-render because context's reference identity doesn't change
27
+ delete hydrateContext._hydration;
28
+ };
26
29
 
27
30
  // if render level not exist, use client render
28
- const renderLevel = ((_window = window) === null || _window === void 0 ? void 0 : (_window$_SSR_DATA = _window._SSR_DATA) === null || _window$_SSR_DATA === void 0 ? void 0 : _window$_SSR_DATA.renderLevel) || RenderLevel.CLIENT_RENDER; // client render and server prefetch use same logic
29
-
30
- if (renderLevel === RenderLevel.CLIENT_RENDER || renderLevel === RenderLevel.SERVER_PREFETCH) {
31
- ModernRender( /*#__PURE__*/_jsx(App, {
32
- context: context
33
- }));
34
- } else if (renderLevel === RenderLevel.SERVER_RENDER) {
35
- loadableReady(() => {
36
- const hydrateContext = _objectSpread(_objectSpread({}, context), {}, {
37
- _hydration: true
38
- });
39
-
40
- const callback = () => {
41
- // won't cause component re-render because context's reference identity doesn't change
42
- delete hydrateContext._hydration;
43
- }; // callback: https://github.com/reactwg/react-18/discussions/5
31
+ const renderLevel = ((_window = window) === null || _window === void 0 ? void 0 : (_window$_SSR_DATA = _window._SSR_DATA) === null || _window$_SSR_DATA === void 0 ? void 0 : _window$_SSR_DATA.renderLevel) || RenderLevel.CLIENT_RENDER;
44
32
 
45
-
46
- if (IS_REACT18) {
47
- let SSRApp = () => /*#__PURE__*/_jsx(WithCallback, {
48
- callback: callback,
49
- children: /*#__PURE__*/_jsx(App, {
50
- context: hydrateContext
51
- })
33
+ // react streamSSR hydrate
34
+ if (isReact18() && config.mode === 'stream') {
35
+ return streamSSRHydrate();
36
+ }
37
+ // react stringSSR hydrate
38
+ return stringSSRHydrate();
39
+ function stringSSRHydrate() {
40
+ // client render and server prefetch use same logic
41
+ if (renderLevel === RenderLevel.CLIENT_RENDER || renderLevel === RenderLevel.SERVER_PREFETCH) {
42
+ ModernRender( /*#__PURE__*/_jsx(App, {
43
+ context: context
44
+ }));
45
+ } else if (renderLevel === RenderLevel.SERVER_RENDER) {
46
+ if (isReact18()) {
47
+ loadableReady(() => {
48
+ // callback: https://github.com/reactwg/react-18/discussions/5
49
+ let SSRApp = () => /*#__PURE__*/_jsx(WithCallback, {
50
+ callback: callback,
51
+ children: /*#__PURE__*/_jsx(App, {
52
+ context: hydrateContext
53
+ })
54
+ });
55
+ SSRApp = hoistNonReactStatics(SSRApp, App);
56
+ ModernHydrate( /*#__PURE__*/_jsx(SSRApp, {}));
52
57
  });
53
-
54
- SSRApp = hoistNonReactStatics(SSRApp, App);
55
- ModernHydrate( /*#__PURE__*/_jsx(SSRApp, {}));
56
58
  } else {
57
- ModernHydrate( /*#__PURE__*/_jsx(App, {
58
- context: hydrateContext
59
- }), callback);
59
+ loadableReady(() => {
60
+ ModernHydrate( /*#__PURE__*/_jsx(App, {
61
+ context: hydrateContext
62
+ }), callback);
63
+ });
60
64
  }
61
- });
62
- } else {
63
- // unknown renderlevel or renderlevel is server prefetch.
64
- console.warn(`unknow render level: ${renderLevel}, execute render()`);
65
- ModernRender( /*#__PURE__*/_jsx(App, {
66
- context: context
67
- }));
65
+ } else {
66
+ // unknown renderlevel or renderlevel is server prefetch.
67
+ console.warn(`unknow render level: ${renderLevel}, execute render()`);
68
+ ModernRender( /*#__PURE__*/_jsx(App, {
69
+ context: context
70
+ }));
71
+ }
72
+ }
73
+ function streamSSRHydrate() {
74
+ if (renderLevel === RenderLevel.SERVER_RENDER) {
75
+ // callback: https://github.com/reactwg/react-18/discussions/5
76
+ let SSRApp = () => /*#__PURE__*/_jsx(WithCallback, {
77
+ callback: callback,
78
+ children: /*#__PURE__*/_jsx(App, {
79
+ context: hydrateContext
80
+ })
81
+ });
82
+ SSRApp = hoistNonReactStatics(SSRApp, App);
83
+ ModernHydrate( /*#__PURE__*/_jsx(SSRApp, {}));
84
+ } else {
85
+ ModernRender( /*#__PURE__*/_jsx(App, {
86
+ context: context
87
+ }));
88
+ }
68
89
  }
69
90
  },
70
-
71
91
  init({
72
92
  context
73
93
  }, next) {
74
94
  var _window2, _window2$_SSR_DATA, _window2$_SSR_DATA$co;
75
-
76
95
  const request = (_window2 = window) === null || _window2 === void 0 ? void 0 : (_window2$_SSR_DATA = _window2._SSR_DATA) === null || _window2$_SSR_DATA === void 0 ? void 0 : (_window2$_SSR_DATA$co = _window2$_SSR_DATA.context) === null || _window2$_SSR_DATA$co === void 0 ? void 0 : _window2$_SSR_DATA$co.request;
77
-
78
96
  if (!request) {
79
97
  context.ssrContext = _objectSpread(_objectSpread({}, context.ssrContext), {}, {
80
98
  response: mockResp,
@@ -84,25 +102,21 @@ export const ssr = _ => ({
84
102
  context
85
103
  });
86
104
  }
87
-
88
105
  context.ssrContext.response = mockResp;
89
106
  context.ssrContext.request = formatClient(request);
90
107
  return next({
91
108
  context
92
109
  });
93
110
  },
94
-
95
111
  pickContext: ({
96
112
  context,
97
113
  pickedContext
98
114
  }, next) => {
99
115
  var _window3, _window3$_SSR_DATA, _window3$_SSR_DATA$co;
100
-
101
116
  const request = (_window3 = window) === null || _window3 === void 0 ? void 0 : (_window3$_SSR_DATA = _window3._SSR_DATA) === null || _window3$_SSR_DATA === void 0 ? void 0 : (_window3$_SSR_DATA$co = _window3$_SSR_DATA.context) === null || _window3$_SSR_DATA$co === void 0 ? void 0 : _window3$_SSR_DATA$co.request;
102
117
  const {
103
118
  initialData
104
119
  } = context;
105
-
106
120
  if (!request) {
107
121
  return next({
108
122
  context,
@@ -111,7 +125,6 @@ export const ssr = _ => ({
111
125
  })
112
126
  });
113
127
  }
114
-
115
128
  return next({
116
129
  context,
117
130
  pickedContext: _objectSpread(_objectSpread({}, pickedContext), {}, {
@@ -1,14 +1,8 @@
1
1
  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; }
2
-
3
2
  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; }
4
-
5
3
  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
-
7
- import { registerPrefetch } from "../core";
8
- import { render } from "./serverRender";
9
- import prefetch from "./prefetch";
10
4
  import { formatServer } from "./utils";
11
- const registeredApps = new WeakSet();
5
+ import render from "./serverRender";
12
6
  export const ssr = (config = {}) => ({
13
7
  name: '@modern-js/plugin-ssr',
14
8
  setup: () => {
@@ -17,15 +11,13 @@ export const ssr = (config = {}) => ({
17
11
  App,
18
12
  context
19
13
  }) => {
20
- if (!registeredApps.has(App)) {
21
- registerPrefetch(App, _context => prefetch(App, _context));
22
- registeredApps.add(App);
23
- }
24
-
25
- const html = await render(context, config, App);
14
+ const html = await render({
15
+ context: context,
16
+ App: App,
17
+ config
18
+ });
26
19
  return html;
27
20
  },
28
-
29
21
  init({
30
22
  context
31
23
  }, next) {
@@ -37,7 +29,6 @@ export const ssr = (config = {}) => ({
37
29
  context
38
30
  });
39
31
  },
40
-
41
32
  pickContext: ({
42
33
  context,
43
34
  pickedContext
@@ -2,18 +2,15 @@ import { renderToStaticMarkup } from 'react-dom/server';
2
2
  import { run } from '@modern-js/utils/ssr';
3
3
  import { ChunkExtractor } from '@loadable/server';
4
4
  import { jsx as _jsx } from "react/jsx-runtime";
5
-
6
5
  // todo: SSRContext
7
6
  const prefetch = async (App, context) => run(context.ssrContext.request.headers, async () => {
8
7
  var _context$store;
9
-
10
8
  const {
11
9
  ssrContext
12
10
  } = context;
13
11
  const {
14
12
  loadableStats
15
13
  } = ssrContext;
16
-
17
14
  if (loadableStats) {
18
15
  const extractor = new ChunkExtractor({
19
16
  stats: loadableStats,
@@ -27,18 +24,15 @@ const prefetch = async (App, context) => run(context.ssrContext.request.headers,
27
24
  context: context
28
25
  }));
29
26
  }
30
-
31
27
  if (!context.loaderManager.hasPendingLoaders()) {
32
28
  return {
33
29
  initialData: context.initialData,
34
30
  i18nData: context.__i18nData__
35
31
  };
36
32
  }
37
-
38
33
  const loadersData = await context.loaderManager.awaitPendingLoaders();
39
34
  Object.keys(loadersData).forEach(id => {
40
35
  const data = loadersData[id];
41
-
42
36
  if (data._error) {
43
37
  ssrContext.logger.error('App Prefetch Loader', data._error);
44
38
  ssrContext.metrics.emitCounter('app.prefetch.loader.error', 1);
@@ -53,5 +47,4 @@ const prefetch = async (App, context) => run(context.ssrContext.request.headers,
53
47
  storeState: context === null || context === void 0 ? void 0 : (_context$store = context.store) === null || _context$store === void 0 ? void 0 : _context$store.getState()
54
48
  };
55
49
  });
56
-
57
50
  export default prefetch;
@@ -1,9 +1,6 @@
1
1
  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; }
2
-
3
2
  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; }
4
-
5
3
  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
-
7
4
  import withSideEffect from 'react-side-effect';
8
5
  import React, { createElement } from 'react';
9
6
  import { getOutermostProperty, aggKeysFromPropsList, exist, aggMatchesFromPropsList } from "./util";
@@ -16,10 +13,9 @@ const PROP_NAMES = {
16
13
  FALLBACK: 'fallback',
17
14
  MATCHES: 'matches'
18
15
  };
19
-
20
- const handleClientStateChange = () => {// not used
16
+ const handleClientStateChange = () => {
17
+ // not used
21
18
  };
22
-
23
19
  const mapStateOnServer = reduceProps => {
24
20
  const defaultProps = {
25
21
  interval: 10,
@@ -34,17 +30,14 @@ const mapStateOnServer = reduceProps => {
34
30
  const propKey = key;
35
31
  const reduceProp = reduceProps[propKey];
36
32
  let nextProps = props;
37
-
38
33
  if (exist(reduceProp)) {
39
34
  nextProps = _objectSpread(_objectSpread({}, props), {}, {
40
35
  [propKey]: reduceProp
41
36
  });
42
37
  }
43
-
44
38
  return nextProps;
45
39
  }, defaultProps);
46
40
  };
47
-
48
41
  const reducePropsToState = propsList => {
49
42
  const reduceProps = {
50
43
  interval: getOutermostProperty(propsList, PROP_NAMES.INTERVAL),
@@ -57,48 +50,34 @@ const reducePropsToState = propsList => {
57
50
  };
58
51
  return reduceProps;
59
52
  };
60
-
61
53
  function factory(Component) {
62
54
  class Spr extends React.Component {
63
55
  static set canUseDOM(canUseDOM) {
64
56
  Component.canUseDOM = canUseDOM;
65
57
  }
66
-
67
58
  static get canUseDOM() {
68
59
  return Component.canUseDOM;
69
60
  }
70
-
71
61
  verify() {
72
62
  return true;
73
63
  }
74
-
75
64
  render() {
76
65
  const newProps = _objectSpread({}, this.props);
77
-
78
66
  const validate = this.verify();
79
-
80
67
  if (!validate) {
81
68
  throw new Error('invalid props, check usage');
82
69
  }
83
-
84
70
  return /*#__PURE__*/createElement(Component, _objectSpread({}, newProps));
85
71
  }
86
-
87
72
  }
88
-
89
73
  _defineProperty(Spr, "peek", Component.peek);
90
-
91
74
  _defineProperty(Spr, "rewind", Component.rewind);
92
-
93
75
  _defineProperty(Spr, "config", () => {
94
76
  const mappedState = Component.rewind();
95
77
  return mappedState;
96
78
  });
97
-
98
79
  return Spr;
99
80
  }
100
-
101
81
  const NullComponent = () => null;
102
-
103
82
  const SprSideEffects = withSideEffect(reducePropsToState, handleClientStateChange, mapStateOnServer)(NullComponent);
104
83
  export const PreRender = factory(SprSideEffects);
@@ -2,12 +2,10 @@ const REQUEST_META = ['header', 'query'];
2
2
  export const getInnermostProperty = function getInnermostProperty(propsList, propName) {
3
3
  for (let i = propsList.length - 1; i >= 0; i--) {
4
4
  const props = propsList[i];
5
-
6
5
  if (props.hasOwnProperty(propName)) {
7
6
  return props[propName];
8
7
  }
9
8
  }
10
-
11
9
  return null;
12
10
  };
13
11
  export const getOutermostProperty = function getOutermostProperty(propsList, propName) {
@@ -16,7 +14,6 @@ export const getOutermostProperty = function getOutermostProperty(propsList, pro
16
14
  return props[propName];
17
15
  }
18
16
  }
19
-
20
17
  return null;
21
18
  };
22
19
  export const aggKeysFromPropsList = function aggKeysFromPropsList(propsList, propName) {
@@ -28,7 +25,6 @@ export const aggKeysFromPropsList = function aggKeysFromPropsList(propsList, pro
28
25
  const res = propsList.filter(props => usefulObject(props[propName])).reduce((result, next) => {
29
26
  REQUEST_META.forEach(key => {
30
27
  const prop = next[propName];
31
-
32
28
  if (prop !== null && prop !== void 0 && prop.hasOwnProperty(key) && usefulArray(prop[key])) {
33
29
  result[key] = unique(result[key].concat(prop[key]));
34
30
  }
@@ -37,13 +33,10 @@ export const aggKeysFromPropsList = function aggKeysFromPropsList(propsList, pro
37
33
  }, initResult);
38
34
  return REQUEST_META.reduce((result, next) => {
39
35
  var _result$key;
40
-
41
36
  const key = next;
42
-
43
37
  if (result[key] && ((_result$key = result[key]) === null || _result$key === void 0 ? void 0 : _result$key.length) === 0) {
44
38
  delete result[key];
45
39
  }
46
-
47
40
  return result;
48
41
  }, res);
49
42
  };
@@ -55,8 +48,8 @@ export const aggMatchesFromPropsList = function aggMatchesFromPropsList(propsLis
55
48
  }, {});
56
49
  const res = propsList.filter(props => usefulObject(props[propName])).reduce((result, next) => {
57
50
  REQUEST_META.forEach(key => {
58
- const prop = next[propName]; // 这边目前是浅拷贝,越后渲染优先级越高
59
-
51
+ const prop = next[propName];
52
+ // 这边目前是浅拷贝,越后渲染优先级越高
60
53
  if (prop !== null && prop !== void 0 && prop.hasOwnProperty(key) && usefulObject(prop[key])) {
61
54
  result[key] = Object.assign(result[key], prop[key]);
62
55
  }
@@ -65,35 +58,27 @@ export const aggMatchesFromPropsList = function aggMatchesFromPropsList(propsLis
65
58
  }, initResult);
66
59
  return REQUEST_META.reduce((result, next) => {
67
60
  const key = next;
68
-
69
61
  if (result[key] && Object.keys(result[key]).length === 0) {
70
62
  delete result[key];
71
63
  }
72
-
73
64
  return result;
74
65
  }, res);
75
66
  };
76
-
77
67
  function unique(arr) {
78
68
  return Array.from(new Set(arr));
79
69
  }
80
-
81
70
  function usefulObject(target) {
82
71
  if (!exist(target)) {
83
72
  return false;
84
73
  }
85
-
86
74
  return target.constructor === Object && Object.keys(target).length > 0;
87
75
  }
88
-
89
76
  function usefulArray(target) {
90
77
  if (!exist(target)) {
91
78
  return false;
92
79
  }
93
-
94
80
  return Array.isArray(target) && target.length > 0;
95
81
  }
96
-
97
82
  export function exist(target) {
98
83
  return target != null;
99
84
  }
@@ -9,7 +9,6 @@ export const WithCallback = ({
9
9
  if (once.current) {
10
10
  return;
11
11
  }
12
-
13
12
  once.current = true;
14
13
  callback();
15
14
  }, [callback]);
@@ -1,46 +1,38 @@
1
1
  // 用于 react-helmet 正则替换
2
+ import { EOL } from 'os';
2
3
  const RE_HTML_ATTR = /<html[^>]*>/;
3
4
  const RE_BODY_ATTR = /<body[^>]*>/;
4
5
  const RE_LAST_IN_HEAD = /<\/head>/;
5
6
  const RE_TITLE = /<title[^>]*>([\s\S\n\r]*?)<\/title>/;
6
- const TEST_TITLE_CONTENT = /(?<=<title[^>]*>)([\s\S\n\r]*?)([.|\S])([\s\S\n\r]*?)(?=<\/title>)/; // 通过 react-helmet 修改模板
7
+ const TEST_TITLE_CONTENT = /(?<=<title[^>]*>)([\s\S\n\r]*?)([.|\S])([\s\S\n\r]*?)(?=<\/title>)/;
7
8
 
9
+ // 通过 react-helmet 修改模板
8
10
  export default function helmet(content, helmetData) {
9
11
  let result = content;
10
12
  const bodyAttributes = helmetData.bodyAttributes.toString();
11
-
12
13
  if (bodyAttributes) {
13
14
  result = result.replace(RE_BODY_ATTR, `<body ${bodyAttributes}>`);
14
15
  }
15
-
16
16
  const htmlAttributes = helmetData.htmlAttributes.toString();
17
-
18
17
  if (htmlAttributes) {
19
18
  result = result.replace(RE_HTML_ATTR, `<html ${htmlAttributes}>`);
20
19
  }
21
-
22
20
  const base = helmetData.base.toString();
23
21
  const link = helmetData.link.toString();
24
22
  const meta = helmetData.meta.toString();
25
23
  const noscript = helmetData.noscript.toString();
26
24
  const script = helmetData.script.toString();
27
25
  const style = helmetData.style.toString();
28
- const title = helmetData.title.toString(); // 如果模板中存在 title,且 helmetData title 有内容则做替换
29
-
30
- const existTitle = RE_TITLE.test(content);
26
+ const title = helmetData.title.toString();
31
27
 
32
- if (TEST_TITLE_CONTENT.test(title.trim()) && existTitle) {
28
+ // 如果模板中存在 title,且 helmetData title 有内容则做替换
29
+ const existTitleTag = RE_TITLE.test(content);
30
+ const shouldReplaceTitle = existTitleTag && TEST_TITLE_CONTENT.test(title.trim());
31
+ if (shouldReplaceTitle) {
33
32
  result = result.replace(RE_TITLE, title);
34
33
  }
35
-
36
- return result.replace(RE_LAST_IN_HEAD, `
37
- ${base}
38
- ${link}
39
- ${meta}
40
- ${noscript}
41
- ${script}
42
- ${style}
43
- ${existTitle ? '' : title}
44
- </head>
45
- `);
34
+ const helmetStr = [base, link, meta, noscript, script, style, !existTitleTag ? title : ''].reduce((pre, cur) => {
35
+ return pre + (cur.length > 0 ? ` ${cur}${EOL}` : '');
36
+ }, '');
37
+ return result.replace(RE_LAST_IN_HEAD, `${helmetStr}</head>`);
46
38
  }