@bleedingdev/modern-js-runtime 3.8.3-ultramodern.1 → 3.8.3-ultramodern.2

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 (81) hide show
  1. package/dist/cjs/cli/ssr/loadable-bundler-plugin.js +1 -1
  2. package/dist/cjs/core/browser/hydrate.js +1 -11
  3. package/dist/cjs/core/context/extensions.js +7 -2
  4. package/dist/cjs/core/context/runtime.js +13 -2
  5. package/dist/cjs/core/react/wrapper.js +10 -8
  6. package/dist/cjs/core/server/federatedCss.js +7 -4
  7. package/dist/cjs/core/server/helmet.js +2 -0
  8. package/dist/cjs/core/server/requestResponse.js +35 -11
  9. package/dist/cjs/core/server/routerCleanup.js +10 -1
  10. package/dist/cjs/core/server/scriptOrder.js +5 -2
  11. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +1 -1
  12. package/dist/cjs/core/server/stream/createReadableStream.js +18 -5
  13. package/dist/cjs/core/server/stream/createReadableStream.worker.js +10 -2
  14. package/dist/cjs/core/server/stream/deferredScript.js +2 -1
  15. package/dist/cjs/core/server/string/index.js +4 -0
  16. package/dist/cjs/core/server/string/loadable.js +11 -2
  17. package/dist/cjs/core/server/utils.js +12 -5
  18. package/dist/cjs/exports/head.js +7 -242
  19. package/dist/cjs/module-federation/last-known-good.js +35 -2
  20. package/dist/cjs/router/cli/nestedRoutesSpec.js +7 -38
  21. package/dist/cjs/router/runtime/PrefetchLink.js +55 -8
  22. package/dist/cjs/router/runtime/redirect.js +11 -1
  23. package/dist/cjs/router/runtime/utils.js +2 -0
  24. package/dist/esm/cli/ssr/loadable-bundler-plugin.mjs +1 -1
  25. package/dist/esm/core/browser/hydrate.mjs +1 -11
  26. package/dist/esm/core/context/extensions.mjs +7 -2
  27. package/dist/esm/core/context/runtime.mjs +13 -2
  28. package/dist/esm/core/react/wrapper.mjs +11 -9
  29. package/dist/esm/core/server/federatedCss.mjs +7 -4
  30. package/dist/esm/core/server/helmet.mjs +2 -0
  31. package/dist/esm/core/server/requestResponse.mjs +35 -11
  32. package/dist/esm/core/server/routerCleanup.mjs +10 -1
  33. package/dist/esm/core/server/scriptOrder.mjs +6 -3
  34. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +2 -2
  35. package/dist/esm/core/server/stream/createReadableStream.mjs +16 -3
  36. package/dist/esm/core/server/stream/createReadableStream.worker.mjs +10 -2
  37. package/dist/esm/core/server/stream/deferredScript.mjs +2 -1
  38. package/dist/esm/core/server/string/index.mjs +4 -0
  39. package/dist/esm/core/server/string/loadable.mjs +11 -2
  40. package/dist/esm/core/server/utils.mjs +8 -4
  41. package/dist/esm/exports/head.mjs +8 -237
  42. package/dist/esm/module-federation/last-known-good.mjs +35 -2
  43. package/dist/esm/router/cli/nestedRoutesSpec.mjs +7 -38
  44. package/dist/esm/router/runtime/PrefetchLink.mjs +28 -8
  45. package/dist/esm/router/runtime/redirect.mjs +11 -1
  46. package/dist/esm/router/runtime/utils.mjs +2 -0
  47. package/dist/esm/rslib-runtime.mjs +9 -0
  48. package/dist/esm-node/cli/ssr/loadable-bundler-plugin.mjs +1 -1
  49. package/dist/esm-node/core/browser/hydrate.mjs +1 -11
  50. package/dist/esm-node/core/context/extensions.mjs +7 -2
  51. package/dist/esm-node/core/context/runtime.mjs +13 -2
  52. package/dist/esm-node/core/react/wrapper.mjs +11 -9
  53. package/dist/esm-node/core/server/federatedCss.mjs +7 -4
  54. package/dist/esm-node/core/server/helmet.mjs +2 -0
  55. package/dist/esm-node/core/server/requestResponse.mjs +35 -11
  56. package/dist/esm-node/core/server/routerCleanup.mjs +10 -1
  57. package/dist/esm-node/core/server/scriptOrder.mjs +6 -3
  58. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +2 -2
  59. package/dist/esm-node/core/server/stream/createReadableStream.mjs +16 -3
  60. package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +10 -2
  61. package/dist/esm-node/core/server/stream/deferredScript.mjs +2 -1
  62. package/dist/esm-node/core/server/string/index.mjs +4 -0
  63. package/dist/esm-node/core/server/string/loadable.mjs +11 -2
  64. package/dist/esm-node/core/server/utils.mjs +8 -4
  65. package/dist/esm-node/exports/head.mjs +8 -237
  66. package/dist/esm-node/module-federation/last-known-good.mjs +35 -2
  67. package/dist/esm-node/router/cli/nestedRoutesSpec.mjs +7 -38
  68. package/dist/esm-node/router/runtime/PrefetchLink.mjs +28 -8
  69. package/dist/esm-node/router/runtime/redirect.mjs +11 -1
  70. package/dist/esm-node/router/runtime/utils.mjs +2 -0
  71. package/dist/esm-node/rslib-runtime.mjs +10 -0
  72. package/dist/types/core/context/extensions.d.ts +2 -4
  73. package/dist/types/core/context/public.d.ts +4 -8
  74. package/dist/types/core/server/requestResponse.d.ts +1 -1
  75. package/dist/types/core/server/routerCleanup.d.ts +2 -0
  76. package/dist/types/core/server/string/loadable.d.ts +1 -0
  77. package/dist/types/core/server/utils.d.ts +1 -0
  78. package/dist/types/exports/head.d.ts +1 -2
  79. package/dist/types/module-federation/last-known-good.d.ts +0 -20
  80. package/package.json +10 -9
  81. package/rstest.config.mts +11 -4
@@ -54,7 +54,7 @@ class LoadablePlugin {
54
54
  const chunkLoadingGlobal = this.opts.chunkLoadingGlobal ?? compiler.options.output.chunkLoadingGlobal ?? DEFAULT_CHUNK_LOADING_GLOBAL;
55
55
  compiler.options.output.chunkLoadingGlobal = chunkLoadingGlobal;
56
56
  new compiler.webpack.DefinePlugin({
57
- 'process.env.MODERN_CHUNK_LOADING_GLOBAL': JSON.stringify(chunkLoadingGlobal)
57
+ __MODERN_CHUNK_LOADING_GLOBAL__: JSON.stringify(chunkLoadingGlobal)
58
58
  }).apply(compiler);
59
59
  if (this.opts.outputAsset || this.opts.writeToDisk) compiler.hooks.make.tap(LoadablePlugin.name, (compilation)=>{
60
60
  compilation.hooks.processAssets.tap({
@@ -38,18 +38,8 @@ const client_namespaceObject = require("react-dom/client");
38
38
  const external_constants_js_namespaceObject = require("../constants.js");
39
39
  const wrapper_js_namespaceObject = require("../react/wrapper.js");
40
40
  const external_withCallback_js_namespaceObject = require("./withCallback.js");
41
- const runtimeProcess = Reflect.get(globalThis, 'process');
42
- const runtimeEnvironment = null !== runtimeProcess && 'object' == typeof runtimeProcess ? Reflect.get(runtimeProcess, 'env') : void 0;
43
- const readRuntimeEnvironment = (name)=>{
44
- if (null === runtimeEnvironment || 'object' != typeof runtimeEnvironment) return;
45
- const value = Reflect.get(runtimeEnvironment, name);
46
- return 'string' == typeof value ? value : void 0;
47
- };
48
41
  const loadableReadyOptions = {
49
- chunkLoadingGlobal: (()=>{
50
- const configured = readRuntimeEnvironment('MODERN_CHUNK_LOADING_GLOBAL');
51
- return void 0 === configured || '' === configured ? '__LOADABLE_LOADED_CHUNKS__' : configured;
52
- })()
42
+ chunkLoadingGlobal: 'string' == typeof __MODERN_CHUNK_LOADING_GLOBAL__ && '' !== __MODERN_CHUNK_LOADING_GLOBAL__ ? __MODERN_CHUNK_LOADING_GLOBAL__ : '__LOADABLE_LOADED_CHUNKS__'
53
43
  };
54
44
  function hydrateWithReact(App, rootElement) {
55
45
  return Promise.resolve((0, client_namespaceObject.hydrateRoot)(rootElement, App, {
@@ -33,8 +33,13 @@ function getStore(context) {
33
33
  }
34
34
  function ensureStore(context) {
35
35
  const target = context;
36
- target[EXTENSIONS_SLOT] ??= new Map();
37
- return target[EXTENSIONS_SLOT];
36
+ const store = target[EXTENSIONS_SLOT] ?? new Map();
37
+ Object.defineProperty(target, EXTENSIONS_SLOT, {
38
+ configurable: true,
39
+ enumerable: true,
40
+ value: store
41
+ });
42
+ return store;
38
43
  }
39
44
  function stripRuntimeContextExtensions(context) {
40
45
  delete context[EXTENSIONS_SLOT];
@@ -40,8 +40,19 @@ const ROUTE_MANIFEST = '_MODERNJS_ROUTE_MANIFEST';
40
40
  const InternalRuntimeContext = (0, external_react_namespaceObject.createContext)({});
41
41
  const getInitialContext = (isBrowser = true, routeManifest)=>{
42
42
  const requestContext = {
43
- request: {},
44
- response: {}
43
+ request: {
44
+ params: {},
45
+ pathname: '',
46
+ query: {},
47
+ headers: {},
48
+ host: '',
49
+ url: ''
50
+ },
51
+ response: {
52
+ setHeader () {},
53
+ status () {},
54
+ locals: {}
55
+ }
45
56
  };
46
57
  return {
47
58
  isBrowser,
@@ -36,12 +36,14 @@ const index_js_namespaceObject = require("../context/index.js");
36
36
  const extensions_js_namespaceObject = require("../context/extensions.js");
37
37
  const helmetContext_js_namespaceObject = require("../context/helmetContext.js");
38
38
  function createRscSafeRequestContext(ssrContext) {
39
- if (void 0 === ssrContext) return {
40
- request: {},
41
- response: {
42
- locals: {}
43
- }
44
- };
39
+ const requestContext = (0, index_js_namespaceObject.getInitialContext)().requestContext;
40
+ Object.defineProperty(requestContext.response, 'setHeader', {
41
+ enumerable: false
42
+ });
43
+ Object.defineProperty(requestContext.response, 'status', {
44
+ enumerable: false
45
+ });
46
+ if (void 0 === ssrContext) return requestContext;
45
47
  const { request, response } = ssrContext;
46
48
  return {
47
49
  request: {
@@ -61,9 +63,9 @@ function createRscSafeRequestContext(ssrContext) {
61
63
  host: request.host,
62
64
  referer: request.referer
63
65
  },
64
- response: {
66
+ response: Object.assign(requestContext.response, {
65
67
  locals: response.locals ?? {}
66
- }
68
+ })
67
69
  };
68
70
  }
69
71
  function wrapRuntimeContextProvider(App, contextValue) {
@@ -30,16 +30,19 @@ __webpack_require__.r(__webpack_exports__);
30
30
  __webpack_require__.d(__webpack_exports__, {
31
31
  createFederatedCssLinks: ()=>createFederatedCssLinks
32
32
  });
33
+ const runtime_extensions_namespaceObject = require("@modern-js/runtime-extensions");
33
34
  const external_utils_js_namespaceObject = require("./utils.js");
34
- const escapeHtmlAttribute = (value)=>value.replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
35
35
  const createFederatedCssLinks = (assets, options)=>{
36
36
  if (void 0 === assets || 0 === assets.length) return '';
37
37
  const seen = new Set(options.existingAssets || []);
38
- const attributes = (0, external_utils_js_namespaceObject.attributesToString)(options.attributes || {});
38
+ const attributes = (0, external_utils_js_namespaceObject.attributesToString)(Object.fromEntries(Object.entries(options.attributes || {}).filter(([name])=>![
39
+ 'href',
40
+ 'rel'
41
+ ].includes(name.toLowerCase()))));
39
42
  const links = [];
40
43
  for (const asset of assets){
41
- const href = escapeHtmlAttribute(asset);
42
- if (!('' === asset || seen.has(asset) || options.template.includes(asset) || options.template.includes(href))) {
44
+ const href = (0, runtime_extensions_namespaceObject.escapeHtmlAttribute)(asset);
45
+ if (!('' === asset || seen.has(asset) || (0, external_utils_js_namespaceObject.hasStylesheetLink)(options.template, asset) || (0, external_utils_js_namespaceObject.hasStylesheetLink)(options.template, href))) {
43
46
  seen.add(asset);
44
47
  links.push(`<link${attributes} href="${href}" rel="stylesheet" />`);
45
48
  }
@@ -53,6 +53,7 @@ function helmetReplace(content, helmetData) {
53
53
  const htmlAttributes = helmetData.htmlAttributes.toString();
54
54
  if (htmlAttributes) result = (0, external_utils_js_namespaceObject.safeReplace)(result, RE_HTML_ATTR, `<html ${htmlAttributes}>`);
55
55
  const base = helmetData.base.toString();
56
+ const priority = helmetData.priority.toString();
56
57
  const link = helmetData.link.toString();
57
58
  const meta = helmetData.meta.toString();
58
59
  const noscript = helmetData.noscript.toString();
@@ -64,6 +65,7 @@ function helmetReplace(content, helmetData) {
64
65
  if (shouldReplaceTitle) result = (0, external_utils_js_namespaceObject.safeReplace)(result, RE_TITLE, title);
65
66
  const helmetStr = [
66
67
  base,
68
+ priority,
67
69
  link,
68
70
  meta,
69
71
  noscript,
@@ -35,9 +35,15 @@ __webpack_require__.d(__webpack_exports__, {
35
35
  const lifecycle_js_namespaceObject = require("../../router/runtime/lifecycle.js");
36
36
  const redirect_js_namespaceObject = require("../../router/runtime/redirect.js");
37
37
  const external_tracer_js_namespaceObject = require("./tracer.js");
38
- const isRedirectStatus = (status)=>status >= 300 && status <= 399;
38
+ const isRedirectStatus = (status)=>301 === status || 302 === status || 303 === status || 307 === status || 308 === status;
39
39
  const isNullBodyStatus = (status)=>204 === status || 205 === status || 304 === status;
40
+ const getRedirectLocation = (headers)=>{
41
+ const location = headers.get('Location');
42
+ return location && URL.canParse(location, 'http://localhost') ? location : void 0;
43
+ };
40
44
  const processRedirect = (headers, status, ctx)=>{
45
+ headers.delete('content-length');
46
+ headers.delete('transfer-encoding');
41
47
  if (ctx.enableRsc && ctx.isRSCNavigation) return (0, redirect_js_namespaceObject.handleRSCRedirect)(headers, ctx.basename, status);
42
48
  return new Response(null, {
43
49
  status,
@@ -54,20 +60,38 @@ const applyRouterSnapshotResult = (context, onError)=>{
54
60
  const createLoaderRedirectResponse = (beforeRenderResult, redirectCtx)=>{
55
61
  if (void 0 === beforeRenderResult || !isRedirectStatus(beforeRenderResult.status)) return;
56
62
  if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
57
- const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
58
- return processRedirect(new Headers({
59
- Location: redirectUrl
60
- }), beforeRenderResult.status, redirectCtx);
63
+ const redirectUrl = getRedirectLocation(beforeRenderResult.headers);
64
+ if (!redirectUrl) return;
65
+ return processRedirect(new Headers(beforeRenderResult.headers), beforeRenderResult.status, redirectCtx);
61
66
  };
62
- const finalizeRenderResponse = (response, responseProxy, redirectCtx, routerCleanup)=>{
63
- if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && void 0 !== responseProxy.headers.Location && '' !== responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
67
+ const finalizeRenderResponse = async (response, responseProxy, redirectCtx, routerCleanup)=>{
68
+ const proxyHeaders = new Headers(responseProxy.headers);
69
+ if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && void 0 !== getRedirectLocation(proxyHeaders)) {
70
+ await routerCleanup.discardBody(response);
71
+ return processRedirect(proxyHeaders, responseProxy.status, redirectCtx);
72
+ }
73
+ const headers = new Headers(response.headers);
74
+ Object.entries(responseProxy.headers).forEach(([key, value])=>{
75
+ headers.set(key, value);
76
+ });
77
+ if (-1 !== responseProxy.status) {
78
+ if (isNullBodyStatus(responseProxy.status)) {
79
+ await routerCleanup.discardBody(response);
80
+ headers.delete('content-length');
81
+ headers.delete('transfer-encoding');
82
+ return new Response(null, {
83
+ status: responseProxy.status,
84
+ headers
85
+ });
86
+ }
87
+ return routerCleanup.deferUntilBodyDone(new Response(response.body, {
88
+ status: responseProxy.status,
89
+ headers
90
+ }));
91
+ }
64
92
  Object.entries(responseProxy.headers).forEach(([key, value])=>{
65
93
  response.headers.set(key, value);
66
94
  });
67
- if (-1 !== responseProxy.status) return routerCleanup.deferUntilBodyDone(new Response(isNullBodyStatus(responseProxy.status) ? null : response.body, {
68
- status: responseProxy.status,
69
- headers: response.headers
70
- }));
71
95
  return routerCleanup.deferUntilBodyDone(response);
72
96
  };
73
97
  exports.applyRouterSnapshotResult = __webpack_exports__.applyRouterSnapshotResult;
@@ -97,12 +97,21 @@ function createRouterCleanup(runtimeContext, onError) {
97
97
  headers: response.headers
98
98
  });
99
99
  };
100
+ const discardBody = async (response)=>{
101
+ const { body } = response;
102
+ if (!body) return void await run();
103
+ deferred = true;
104
+ if (body.locked) throw new TypeError('Cannot discard a locked response body before router cleanup');
105
+ await body.cancel('Response body discarded during finalization');
106
+ await run();
107
+ };
100
108
  return {
101
109
  get deferred () {
102
110
  return deferred;
103
111
  },
104
112
  run,
105
- deferUntilBodyDone
113
+ deferUntilBodyDone,
114
+ discardBody
106
115
  };
107
116
  }
108
117
  exports.ROUTER_CLEANUP_ERROR = __webpack_exports__.ROUTER_CLEANUP_ERROR;
@@ -102,6 +102,7 @@ function injectBeforeHydrationEntryScript(template, scripts, entryName = 'index'
102
102
  return `${template.slice(0, target.index)}${scripts}${template.slice(target.index)}`;
103
103
  }
104
104
  function replaceChunkJsPlaceholder(template, scripts, entryName, placeholder = external_constants_js_namespaceObject.CHUNK_JS_PLACEHOLDER) {
105
+ if (!template.includes(placeholder)) return template;
105
106
  if ('' === scripts) return (0, external_utils_js_namespaceObject.safeReplace)(template, placeholder, '');
106
107
  const withoutPlaceholder = (0, external_utils_js_namespaceObject.safeReplace)(template, placeholder, '');
107
108
  const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, scripts, entryName);
@@ -117,8 +118,10 @@ function createRouteHydrationScriptTags(runtimeContext, entryName, options = {})
117
118
  ...getMatchedRouteAssets(runtimeContext),
118
119
  ...routeAssets[`async-${entryName}`]?.assets ?? []
119
120
  ].filter((asset)=>asset.endsWith('.js'))));
120
- const nonceAttr = void 0 === nonce || '' === nonce ? '' : ` nonce="${nonce}"`;
121
- return jsAssets.filter((asset)=>!existingScriptSrcs.has(asset)).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
121
+ return jsAssets.filter((asset)=>!existingScriptSrcs.has(asset)).map((asset)=>`<script${(0, external_utils_js_namespaceObject.attributesToString)({
122
+ src: asset,
123
+ nonce: nonce || void 0
124
+ })}></script>`).join(' ');
122
125
  }
123
126
  exports.createRouteHydrationScriptTags = __webpack_exports__.createRouteHydrationScriptTags;
124
127
  exports.getMatchedRouteChunks = __webpack_exports__.getMatchedRouteChunks;
@@ -68,7 +68,7 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
68
68
  if (asyncEntry) matchedRouteManifests.push(asyncEntry);
69
69
  const cssChunks = matchedRouteManifests.reduce((chunks, routeManifest)=>{
70
70
  const { referenceCssAssets = [] } = routeManifest;
71
- const _cssChunks = referenceCssAssets.filter((asset)=>asset?.endsWith('.css') && !template.includes(asset));
71
+ const _cssChunks = referenceCssAssets.filter((asset)=>asset?.endsWith('.css') && !(0, external_utils_js_namespaceObject.hasStylesheetLink)(template, asset));
72
72
  return [
73
73
  ...chunks,
74
74
  ..._cssChunks
@@ -30,13 +30,15 @@ __webpack_require__.r(__webpack_exports__);
30
30
  __webpack_require__.d(__webpack_exports__, {
31
31
  createReadableStreamFromElement: ()=>createReadableStreamFromElement
32
32
  });
33
- const node_namespaceObject = require("@modern-js/runtime-utils/node");
33
+ const node_namespaceObject = require("@modern-js/runtime-extensions/node");
34
+ const runtime_utils_node_namespaceObject = require("@modern-js/runtime-utils/node");
34
35
  const constants_namespaceObject = require("@modern-js/utils/universal/constants");
35
36
  const external_stream_namespaceObject = require("stream");
36
37
  const external_common_js_namespaceObject = require("../../../common.js");
37
38
  const external_constants_js_namespaceObject = require("../../constants.js");
38
39
  const index_js_namespaceObject = require("../../context/index.js");
39
40
  const monitors_index_js_namespaceObject = require("../../context/monitors/index.js");
41
+ const external_helmet_js_namespaceObject = require("../helmet.js");
40
42
  const external_deferredScript_js_namespaceObject = require("./deferredScript.js");
41
43
  const external_shared_js_namespaceObject = require("./shared.js");
42
44
  const external_template_js_namespaceObject = require("./template.js");
@@ -68,6 +70,8 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
68
70
  });
69
71
  const chunkVec = [];
70
72
  let hasStartedPipe = false;
73
+ node_namespaceObject.beginHeadRender(runtimeContext);
74
+ const reportError = node_namespaceObject.createOnceErrorReporter(options.onError);
71
75
  return new Promise((resolve)=>{
72
76
  const { pipe: reactStreamingPipe } = renderToPipeableStream(processedRootElement, {
73
77
  nonce: config.nonce,
@@ -101,8 +105,10 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
101
105
  if (-1 !== markerIndex) {
102
106
  const beforeMark = concatedChunk.slice(0, markerIndex);
103
107
  const afterMark = concatedChunk.slice(markerIndex + external_common_js_namespaceObject.ESCAPED_SHELL_STREAM_END_MARK.length);
108
+ node_namespaceObject.publishHeadRender(runtimeContext);
109
+ const completedShellBefore = (0, external_helmet_js_namespaceObject.createReplaceHelemt)((0, external_helmet_js_namespaceObject.getHelmetData)(runtimeContext))(shellBefore);
104
110
  shellChunkStatus = external_shared_js_namespaceObject.ShellChunkStatus.FINISH;
105
- this.push(`${shellBefore}${beforeMark}${shellAfter}`);
111
+ this.push(`${completedShellBefore}${beforeMark}${shellAfter}`);
106
112
  if (afterMark) this.push(afterMark);
107
113
  if (pendingScripts.length > 0) for (const s of pendingScripts)this.push(s);
108
114
  }
@@ -120,10 +126,16 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
120
126
  extenders.forEach((extender)=>{
121
127
  if (extender.processStream) processedStream = extender.processStream(processedStream);
122
128
  });
129
+ node_namespaceObject.pipeNodeHeadStream({
130
+ source: processedStream,
131
+ destination: body,
132
+ context: runtimeContext,
133
+ terminalMarker: external_common_js_namespaceObject.ESCAPED_SHELL_STREAM_END_MARK,
134
+ onError: reportError
135
+ });
123
136
  reactStreamingPipe(passThrough);
124
- processedStream.pipe(body);
125
137
  try {
126
- const storageContext = node_namespaceObject.storage.useContext?.();
138
+ const storageContext = runtime_utils_node_namespaceObject.storage.useContext?.();
127
139
  const activeDeferreds = storageContext?.activeDeferreds;
128
140
  const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
129
141
  if (entries.length > 0) {
@@ -140,6 +152,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
140
152
  });
141
153
  },
142
154
  onShellError (error) {
155
+ node_namespaceObject.abortHeadRender(runtimeContext);
143
156
  renderLevel = external_constants_js_namespaceObject.RenderLevel.CLIENT_RENDER;
144
157
  (0, external_template_js_namespaceObject.getTemplates)(htmlTemplate, {
145
158
  request,
@@ -158,7 +171,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
158
171
  },
159
172
  onError (error) {
160
173
  renderLevel = external_constants_js_namespaceObject.RenderLevel.CLIENT_RENDER;
161
- options?.onError?.(error);
174
+ reportError(error);
162
175
  }
163
176
  });
164
177
  });
@@ -31,9 +31,11 @@ __webpack_require__.d(__webpack_exports__, {
31
31
  createReadableStreamFromElement: ()=>createReadableStreamFromElement
32
32
  });
33
33
  const ssr_namespaceObject = require("@modern-js/render/ssr");
34
+ const runtime_extensions_namespaceObject = require("@modern-js/runtime-extensions");
34
35
  const node_namespaceObject = require("@modern-js/runtime-utils/node");
35
36
  const external_common_js_namespaceObject = require("../../../common.js");
36
37
  const external_constants_js_namespaceObject = require("../../constants.js");
38
+ const external_helmet_js_namespaceObject = require("../helmet.js");
37
39
  const external_deferredScript_js_namespaceObject = require("./deferredScript.js");
38
40
  const external_shared_js_namespaceObject = require("./shared.js");
39
41
  const external_template_js_namespaceObject = require("./template.js");
@@ -41,6 +43,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
41
43
  let shellChunkStatus = external_shared_js_namespaceObject.ShellChunkStatus.START;
42
44
  const chunkVec = [];
43
45
  const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, moduleFederationCssAssets, rscManifest, rscRoot } = options;
46
+ runtime_extensions_namespaceObject.beginHeadRender(runtimeContext);
44
47
  const { shellBefore, shellAfter } = await (0, external_template_js_namespaceObject.getTemplates)(htmlTemplate, {
45
48
  renderLevel: external_constants_js_namespaceObject.RenderLevel.SERVER_RENDER,
46
49
  runtimeContext,
@@ -68,7 +71,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
68
71
  const forceStreamToString = Boolean("u" > typeof process && process.env?.MODERN_JS_STREAM_TO_STRING);
69
72
  const { waitForAllReady } = (0, external_shared_js_namespaceObject.resolveStreamingMode)(request, forceStreamToString);
70
73
  if (waitForAllReady) await readableOriginal.allReady;
71
- const reader = readableOriginal.getReader();
74
+ const reader = runtime_extensions_namespaceObject.createConservingWebShellStream(readableOriginal, runtimeContext, external_common_js_namespaceObject.ESCAPED_SHELL_STREAM_END_MARK, options.onError).getReader();
72
75
  const stream = new ReadableStream({
73
76
  start (controller) {
74
77
  const pendingScripts = [];
@@ -113,14 +116,17 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
113
116
  if (-1 !== markerIndex) {
114
117
  const beforeMark = concatedChunk.slice(0, markerIndex);
115
118
  const afterMark = concatedChunk.slice(markerIndex + external_common_js_namespaceObject.ESCAPED_SHELL_STREAM_END_MARK.length);
119
+ runtime_extensions_namespaceObject.publishHeadRender(runtimeContext);
120
+ const completedShellBefore = (0, external_helmet_js_namespaceObject.createReplaceHelemt)((0, external_helmet_js_namespaceObject.getHelmetData)(runtimeContext))(shellBefore);
116
121
  shellChunkStatus = external_shared_js_namespaceObject.ShellChunkStatus.FINISH;
117
- safeEnqueue((0, external_shared_js_namespaceObject.encodeForWebStream)(`${shellBefore}${beforeMark}${shellAfter}`));
122
+ safeEnqueue((0, external_shared_js_namespaceObject.encodeForWebStream)(`${completedShellBefore}${beforeMark}${shellAfter}`));
118
123
  if (afterMark.length > 0) safeEnqueue((0, external_shared_js_namespaceObject.encodeForWebStream)(afterMark));
119
124
  flushPendingScripts();
120
125
  }
121
126
  } else safeEnqueue(value);
122
127
  if (!isClosed) push();
123
128
  } catch (error) {
129
+ runtime_extensions_namespaceObject.abortHeadRender(runtimeContext);
124
130
  if (!isClosed) {
125
131
  isClosed = true;
126
132
  try {
@@ -132,11 +138,13 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
132
138
  push();
133
139
  },
134
140
  cancel (reason) {
141
+ runtime_extensions_namespaceObject.abortHeadRender(runtimeContext);
135
142
  reader.cancel(reason).catch(()=>{});
136
143
  }
137
144
  });
138
145
  return stream;
139
146
  } catch (e) {
147
+ runtime_extensions_namespaceObject.abortHeadRender(runtimeContext);
140
148
  const fallbackHtml = `${shellBefore}${shellAfter}`;
141
149
  const stream = (0, external_shared_js_namespaceObject.getReadableStreamFromString)(fallbackHtml);
142
150
  return stream;
@@ -37,6 +37,7 @@ __webpack_require__.d(__webpack_exports__, {
37
37
  toErrorInfo: ()=>toErrorInfo
38
38
  });
39
39
  const constants_js_namespaceObject = require("../../../router/runtime/constants.js");
40
+ const external_utils_js_namespaceObject = require("../utils.js");
40
41
  const HTML_ESCAPE_MAP = {
41
42
  '&': '&amp;',
42
43
  '<': '&lt;',
@@ -60,7 +61,7 @@ function isPromiseLike(value) {
60
61
  return !!value && 'function' == typeof value.then;
61
62
  }
62
63
  function toErrorInfo(error) {
63
- if ('production' === process.env.NODE_ENV) return {
64
+ if ((0, external_utils_js_namespaceObject.shouldRedactServerError)()) return {
64
65
  message: 'Unexpected Server Error'
65
66
  };
66
67
  if (error && 'object' == typeof error) {
@@ -39,6 +39,7 @@ __webpack_require__.r(__webpack_exports__);
39
39
  __webpack_require__.d(__webpack_exports__, {
40
40
  renderString: ()=>renderString
41
41
  });
42
+ const runtime_extensions_namespaceObject = require("@modern-js/runtime-extensions");
42
43
  const time_namespaceObject = require("@modern-js/runtime-utils/time");
43
44
  const constants_namespaceObject = require("@modern-js/utils/universal/constants");
44
45
  const server_namespaceObject = require("react-dom/server");
@@ -108,16 +109,19 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
108
109
  let html = '';
109
110
  let helmetData;
110
111
  const finalApp = collectors.reduce((pre, creator)=>creator.collect?.(pre) || pre, App);
112
+ runtime_extensions_namespaceObject.beginHeadRender(runtimeContext);
111
113
  try {
112
114
  const end = (0, time_namespaceObject.time)();
113
115
  html = server_default().renderToString(finalApp, {
114
116
  identifierPrefix: constants_namespaceObject.SSR_HYDRATION_ID_PREFIX
115
117
  });
118
+ html = runtime_extensions_namespaceObject.completeHeadRender(runtimeContext, html);
116
119
  chunkSet.renderLevel = external_constants_js_namespaceObject.RenderLevel.SERVER_RENDER;
117
120
  helmetData = (0, external_helmet_js_namespaceObject.getHelmetData)(runtimeContext);
118
121
  const cost = end();
119
122
  onTiming(external_tracer_js_namespaceObject.SSRTimings.RENDER_HTML, cost);
120
123
  } catch (e) {
124
+ runtime_extensions_namespaceObject.abortHeadRender(runtimeContext);
121
125
  chunkSet.renderLevel = external_constants_js_namespaceObject.RenderLevel.CLIENT_RENDER;
122
126
  onError(e, external_tracer_js_namespaceObject.SSRErrors.RENDER_HTML);
123
127
  }
@@ -60,6 +60,10 @@ const readAsset = async (chunk)=>{
60
60
  return fs.readFile(filepath, 'utf-8');
61
61
  };
62
62
  class LoadableCollector {
63
+ get existsAssets() {
64
+ const { routeManifest, entryName } = this.options;
65
+ return routeManifest?.routeAssets?.[entryName]?.assets;
66
+ }
63
67
  collect(comopnent) {
64
68
  const { stats, entryName } = this.options;
65
69
  if (!stats) return comopnent;
@@ -121,7 +125,7 @@ class LoadableCollector {
121
125
  const matchs = template.matchAll(jsScriptRegExp);
122
126
  const existedScript = [];
123
127
  for (const match of matchs)existedScript.push(match[1]);
124
- const scripts = await Promise.all(chunks.filter((chunk)=>!existedScript.includes(chunk.url)).map(async (chunk)=>{
128
+ const scripts = await Promise.all(chunks.filter((chunk)=>!existedScript.includes(chunk.url) && !this.existsAssets?.includes(chunk.path)).map(async (chunk)=>{
125
129
  const script = `<script${attributes} src="${chunk.url}"></script>`;
126
130
  if ((0, external_utils_js_namespaceObject.checkIsNode)() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<script>${content}</script>`).catch((_)=>script);
127
131
  return script;
@@ -132,7 +136,12 @@ class LoadableCollector {
132
136
  const { template, chunkSet, config, moduleFederationCssAssets } = this.options;
133
137
  const { inlineStyles } = config;
134
138
  const atrributes = (0, external_utils_js_namespaceObject.attributesToString)(this.generateAttributes());
135
- const emittedChunks = chunks.filter((chunk)=>!(0, external_utils_js_namespaceObject.hasStylesheetLink)(template, chunk.url));
139
+ const emittedAssetUrls = new Set();
140
+ const emittedChunks = chunks.filter((chunk)=>{
141
+ const shouldEmit = !(0, external_utils_js_namespaceObject.hasStylesheetLink)(template, chunk.url) && !this.existsAssets?.includes(chunk.path) && !emittedAssetUrls.has(chunk.url);
142
+ if (shouldEmit) emittedAssetUrls.add(chunk.url);
143
+ return shouldEmit;
144
+ });
136
145
  const css = await Promise.all(emittedChunks.map(async (chunk)=>{
137
146
  const link = `<link${atrributes} href="${chunk.url}" rel="stylesheet" />`;
138
147
  if ((0, external_utils_js_namespaceObject.checkIsNode)() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<style>${content}</style>`).catch((_)=>link);
@@ -34,11 +34,13 @@ __webpack_require__.d(__webpack_exports__, {
34
34
  getSSRMode: ()=>getSSRMode,
35
35
  hasStylesheetLink: ()=>hasStylesheetLink,
36
36
  safeReplace: ()=>safeReplace,
37
- serializeErrors: ()=>serializeErrors
37
+ serializeErrors: ()=>serializeErrors,
38
+ shouldRedactServerError: ()=>shouldRedactServerError
38
39
  });
40
+ const runtime_extensions_namespaceObject = require("@modern-js/runtime-extensions");
39
41
  const routerHelper_js_namespaceObject = require("../../router/runtime/routerHelper.js");
40
42
  function attributesToString(attributes) {
41
- return Object.entries(attributes).reduce((str, [key, value])=>void 0 === value ? str : `${str} ${key}="${value}"`, '');
43
+ return Object.entries(attributes).reduce((str, [key, value])=>void 0 !== value && (0, runtime_extensions_namespaceObject.isSafeHtmlAttributeName)(key) ? `${str} ${key}="${(0, runtime_extensions_namespaceObject.escapeHtmlAttribute)(value)}"` : str, '');
42
44
  }
43
45
  function safeReplace(source, searchValue, replaceValue) {
44
46
  return source.replace(searchValue, ()=>replaceValue);
@@ -76,12 +78,14 @@ function serializeRouteErrorResponse(error) {
76
78
  status: error.status,
77
79
  statusText: 'Internal Server Error',
78
80
  data: 'Unexpected Server Error',
81
+ internal: error.internal,
79
82
  __type: 'RouteErrorResponse'
80
83
  };
81
84
  return {
82
85
  status: error.status,
83
86
  statusText: error.statusText,
84
87
  data: error.data,
88
+ internal: error.internal,
85
89
  __type: 'RouteErrorResponse'
86
90
  };
87
91
  }
@@ -103,8 +107,9 @@ const getLinkAttributes = (linkTag)=>{
103
107
  let match;
104
108
  while(match = attributeRegExp.exec(linkTag)){
105
109
  const [, name, doubleQuotedValue, singleQuotedValue, unquotedValue] = match;
106
- if ('link' === name.toLowerCase()) continue;
107
- attributes.set(name.toLowerCase(), doubleQuotedValue ?? singleQuotedValue ?? unquotedValue ?? '');
110
+ const normalizedName = name.toLowerCase();
111
+ if ('link' === normalizedName || attributes.has(normalizedName)) continue;
112
+ attributes.set(normalizedName, doubleQuotedValue ?? singleQuotedValue ?? unquotedValue ?? '');
108
113
  }
109
114
  return attributes;
110
115
  };
@@ -124,6 +129,7 @@ exports.getSSRMode = __webpack_exports__.getSSRMode;
124
129
  exports.hasStylesheetLink = __webpack_exports__.hasStylesheetLink;
125
130
  exports.safeReplace = __webpack_exports__.safeReplace;
126
131
  exports.serializeErrors = __webpack_exports__.serializeErrors;
132
+ exports.shouldRedactServerError = __webpack_exports__.shouldRedactServerError;
127
133
  for(var __rspack_i in __webpack_exports__)if (-1 === [
128
134
  "attributesToString",
129
135
  "checkIsNode",
@@ -131,7 +137,8 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
131
137
  "getSSRMode",
132
138
  "hasStylesheetLink",
133
139
  "safeReplace",
134
- "serializeErrors"
140
+ "serializeErrors",
141
+ "shouldRedactServerError"
135
142
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
136
143
  Object.defineProperty(exports, '__esModule', {
137
144
  value: true