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

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
@@ -39,256 +39,25 @@ var __webpack_exports__ = {};
39
39
  __webpack_require__.r(__webpack_exports__);
40
40
  __webpack_require__.d(__webpack_exports__, {
41
41
  Helmet: ()=>Helmet,
42
- HelmetData: ()=>external_react_helmet_async_namespaceObject.HelmetData,
43
- HelmetProvider: ()=>external_react_helmet_async_namespaceObject.HelmetProvider,
44
42
  default: ()=>exports_head
45
43
  });
44
+ const runtime_extensions_namespaceObject = require("@modern-js/runtime-extensions");
46
45
  const external_react_namespaceObject = require("react");
47
46
  var external_react_default = /*#__PURE__*/ __webpack_require__.n(external_react_namespaceObject);
48
47
  const external_react_helmet_async_namespaceObject = require("react-helmet-async");
49
48
  const index_js_namespaceObject = require("../core/context/index.js");
50
49
  const helmetContext_js_namespaceObject = require("../core/context/helmetContext.js");
51
- const ATTRIBUTE_NAME_MAP = {
52
- charSet: 'charset',
53
- className: 'class',
54
- contentEditable: 'contenteditable',
55
- httpEquiv: 'http-equiv',
56
- hrefLang: 'hreflang',
57
- itemProp: 'itemprop',
58
- tabIndex: 'tabindex'
59
- };
60
- const CONTENT_PROPERTIES = new Set([
61
- 'innerHTML',
62
- 'cssText'
63
- ]);
64
- const escapeHtml = (value)=>String(value).replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
65
- const toHtmlAttributeName = (name)=>ATTRIBUTE_NAME_MAP[name] ?? name;
66
- const attributesToString = (attributes, includeHelmetAttribute = false)=>{
67
- const pairs = [];
68
- if (includeHelmetAttribute) pairs.push('data-rh="true"');
69
- for (const [name, value] of Object.entries(attributes ?? {})){
70
- if (false === value || null == value) continue;
71
- if (CONTENT_PROPERTIES.has(name)) continue;
72
- const htmlName = toHtmlAttributeName(name);
73
- if (true === value) pairs.push(htmlName);
74
- else pairs.push(`${htmlName}="${escapeHtml(value)}"`);
75
- }
76
- return pairs.join(' ');
77
- };
78
- const createDatum = (tagName, tags)=>({
79
- toComponent: ()=>[],
80
- toString: ()=>tags.map((tag)=>{
81
- const attrs = attributesToString(tag, true);
82
- if ("script" === tagName && 'string' == typeof tag.innerHTML) return `<script ${attrs}>${tag.innerHTML}</script>`;
83
- if ('style' === tagName && 'string' == typeof tag.cssText) return `<style ${attrs}>${tag.cssText}</style>`;
84
- if ("noscript" === tagName && 'string' == typeof tag.innerHTML) return `<noscript ${attrs}>${tag.innerHTML}</noscript>`;
85
- return `<${tagName} ${attrs}>`;
86
- }).join('')
87
- });
88
- const createAttributeDatum = (attributes)=>({
89
- toComponent: ()=>attributes,
90
- toString: ()=>attributesToString(attributes)
91
- });
92
- const createTitleDatum = (title, attributes)=>({
93
- toComponent: ()=>[],
94
- toString: ()=>{
95
- if (void 0 === title || '' === title) return '';
96
- const attrs = attributesToString(attributes, true);
97
- return `<title ${attrs}>${escapeHtml(title)}</title>`;
98
- }
99
- });
100
- const normalizeHelmetTitle = (title)=>{
101
- if ('string' == typeof title) return title;
102
- if (Array.isArray(title)) return title.map((part)=>String(part)).join('');
103
- };
104
- const mergeAttributes = (current, next)=>({
105
- ...current,
106
- ...next ?? {}
107
- });
108
- const collectChildren = (children, draft)=>{
109
- external_react_default().Children.forEach(children, (child)=>{
110
- if (!external_react_default().isValidElement(child)) return;
111
- if (child.type === external_react_default().Fragment) return void collectChildren(child.props.children, draft);
112
- if ('string' != typeof child.type) return;
113
- const { children: nestedChildren, ...props } = child.props;
114
- if ('title' === child.type) {
115
- draft.title = external_react_default().Children.toArray(nestedChildren).join('');
116
- draft.titleAttributes = mergeAttributes(draft.titleAttributes, props);
117
- return;
118
- }
119
- if ('html' === child.type) {
120
- draft.htmlAttributes = mergeAttributes(draft.htmlAttributes ?? {}, props);
121
- return;
122
- }
123
- if ('body' === child.type) {
124
- draft.bodyAttributes = mergeAttributes(draft.bodyAttributes ?? {}, props);
125
- return;
126
- }
127
- if ('base' === child.type || 'link' === child.type || 'meta' === child.type || "noscript" === child.type || "script" === child.type || 'style' === child.type) {
128
- const tag = {
129
- ...props
130
- };
131
- if (("script" === child.type || 'style' === child.type || "noscript" === child.type) && 'string' == typeof nestedChildren) tag['style' === child.type ? 'cssText' : 'innerHTML'] = nestedChildren;
132
- draft[child.type].push(tag);
133
- }
134
- });
135
- };
136
- const createHelmetRecord = (props)=>{
137
- const draft = {
138
- base: [
139
- ...void 0 !== props.base ? [
140
- props.base
141
- ] : []
142
- ],
143
- bodyAttributes: props.bodyAttributes,
144
- htmlAttributes: props.htmlAttributes,
145
- link: [
146
- ...props.link ?? []
147
- ],
148
- meta: [
149
- ...props.meta ?? []
150
- ],
151
- noscript: [
152
- ...props.noscript ?? []
153
- ],
154
- script: [
155
- ...props.script ?? []
156
- ],
157
- style: [
158
- ...props.style ?? []
159
- ],
160
- title: normalizeHelmetTitle(props.title),
161
- titleAttributes: props.titleAttributes ?? {}
162
- };
163
- collectChildren(props.children, draft);
164
- return {
165
- ...draft,
166
- titleTemplate: props.titleTemplate,
167
- defaultTitle: props.defaultTitle
168
- };
169
- };
170
- const getInnermostDefined = (records, pick)=>{
171
- for(let i = records.length - 1; i >= 0; i -= 1){
172
- const value = pick(records[i]);
173
- if (void 0 !== value) return value;
174
- }
175
- };
176
- const deriveTitle = (records)=>{
177
- const innermostTitle = getInnermostDefined(records, (record)=>record.title);
178
- const innermostTemplate = getInnermostDefined(records, (record)=>record.titleTemplate);
179
- if (innermostTemplate && innermostTitle) return innermostTemplate.replaceAll('%s', innermostTitle);
180
- return innermostTitle || getInnermostDefined(records, (record)=>record.defaultTitle);
181
- };
182
- const mergeRecordAttributes = (records, pick)=>records.reduce((merged, record)=>mergeAttributes(merged, pick(record)), {});
183
- const deriveBaseTags = (records)=>{
184
- for(let i = records.length - 1; i >= 0; i -= 1){
185
- const tags = records[i].base;
186
- for(let j = tags.length - 1; j >= 0; j -= 1)if (tags[j].href) return [
187
- tags[j]
188
- ];
189
- }
190
- return [];
191
- };
192
- const TAG_PRIMARY_ATTRIBUTES = {
193
- link: [
194
- 'rel',
195
- 'href'
196
- ],
197
- meta: [
198
- 'name',
199
- 'charset',
200
- 'http-equiv',
201
- 'property',
202
- 'itemprop'
203
- ],
204
- noscript: [
205
- 'innerHTML'
206
- ],
207
- script: [
208
- 'src',
209
- 'innerHTML'
210
- ],
211
- style: [
212
- 'cssText'
213
- ]
214
- };
215
- const getPrimaryAttribute = (tagName, tag)=>{
216
- const candidates = TAG_PRIMARY_ATTRIBUTES[tagName];
217
- let selectedKey;
218
- let selectedValue;
219
- for (const [key, value] of Object.entries(tag)){
220
- const normalizedKey = CONTENT_PROPERTIES.has(key) ? key : toHtmlAttributeName(key).toLowerCase();
221
- if (candidates.includes(normalizedKey)) {
222
- if ('rel' !== selectedKey || 'canonical' !== String(selectedValue).toLowerCase()) {
223
- if ('rel' !== normalizedKey || 'stylesheet' !== String(value).toLowerCase()) {
224
- selectedKey = normalizedKey;
225
- selectedValue = value;
226
- }
227
- }
228
- }
229
- }
230
- if (void 0 === selectedKey || !selectedValue) return;
231
- return {
232
- key: selectedKey,
233
- value: String(selectedValue).toLowerCase()
234
- };
235
- };
236
- const dedupeTags = (tagName, records)=>{
237
- const approvedValues = new Map();
238
- const approved = [];
239
- for(let i = records.length - 1; i >= 0; i -= 1){
240
- const instanceValues = new Map();
241
- const kept = [];
242
- for (const tag of records[i][tagName]){
243
- const primary = getPrimaryAttribute(tagName, tag);
244
- if (void 0 === primary) continue;
245
- if (approvedValues.get(primary.key)?.has(primary.value)) continue;
246
- let seen = instanceValues.get(primary.key);
247
- if (void 0 === seen) {
248
- seen = new Set();
249
- instanceValues.set(primary.key, seen);
250
- }
251
- seen.add(primary.value);
252
- kept.push(tag);
253
- }
254
- approved.unshift(...kept);
255
- for (const [key, values] of instanceValues){
256
- const target = approvedValues.get(key);
257
- if (void 0 === target) approvedValues.set(key, values);
258
- else for (const value of values)target.add(value);
259
- }
260
- }
261
- return approved;
262
- };
263
- const deriveHelmetServerState = (records)=>({
264
- base: createDatum('base', deriveBaseTags(records)),
265
- bodyAttributes: createAttributeDatum(mergeRecordAttributes(records, (record)=>record.bodyAttributes)),
266
- htmlAttributes: createAttributeDatum(mergeRecordAttributes(records, (record)=>record.htmlAttributes)),
267
- link: createDatum('link', dedupeTags('link', records)),
268
- meta: createDatum('meta', dedupeTags('meta', records)),
269
- noscript: createDatum("noscript", dedupeTags("noscript", records)),
270
- priority: createDatum('meta', []),
271
- script: createDatum("script", dedupeTags("script", records)),
272
- style: createDatum('style', dedupeTags('style', records)),
273
- title: createTitleDatum(deriveTitle(records), mergeRecordAttributes(records, (record)=>record.titleAttributes))
274
- });
275
- const serverHelmetRecords = new WeakMap();
276
50
  const collectServerHelmet = (runtimeContext, props)=>{
277
51
  const helmetContext = (0, helmetContext_js_namespaceObject.ensureHelmetContext)(runtimeContext);
278
- let records = serverHelmetRecords.get(helmetContext);
279
- if (void 0 === records) {
280
- records = [];
281
- serverHelmetRecords.set(helmetContext, records);
282
- }
283
- records.push(createHelmetRecord(props));
284
- helmetContext.helmet = deriveHelmetServerState(records);
52
+ const createRecord = ()=>runtime_extensions_namespaceObject.createHelmetRecord(external_react_default(), props);
53
+ const deriveState = (records)=>runtime_extensions_namespaceObject.deriveHelmetServerState(external_react_default(), records);
54
+ const marker = runtime_extensions_namespaceObject.collectHeadState(runtimeContext, createRecord, deriveState, helmetContext);
55
+ if (void 0 !== marker) return marker;
56
+ helmetContext.helmet = runtime_extensions_namespaceObject.collectImmediateHelmetState(external_react_default(), helmetContext, createRecord());
285
57
  };
286
58
  const Helmet = (props)=>{
287
59
  const runtimeContext = external_react_default().useContext(index_js_namespaceObject.InternalRuntimeContext);
288
- if (null !== runtimeContext && false === runtimeContext.isBrowser) {
289
- collectServerHelmet(runtimeContext, props);
290
- return null;
291
- }
60
+ if (null !== runtimeContext && false === runtimeContext.isBrowser) return runtime_extensions_namespaceObject.renderHeadMarker(external_react_default(), collectServerHelmet(runtimeContext, props));
292
61
  return external_react_default().createElement(external_react_helmet_async_namespaceObject.Helmet, props);
293
62
  };
294
63
  const head = {
@@ -298,13 +67,9 @@ const head = {
298
67
  };
299
68
  const exports_head = head;
300
69
  exports.Helmet = __webpack_exports__.Helmet;
301
- exports.HelmetData = __webpack_exports__.HelmetData;
302
- exports.HelmetProvider = __webpack_exports__.HelmetProvider;
303
70
  exports["default"] = __webpack_exports__["default"];
304
71
  for(var __rspack_i in __webpack_exports__)if (-1 === [
305
72
  "Helmet",
306
- "HelmetData",
307
- "HelmetProvider",
308
73
  "default"
309
74
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
310
75
  Object.defineProperty(exports, '__esModule', {
@@ -32,6 +32,7 @@ __webpack_require__.d(__webpack_exports__, {
32
32
  createInMemoryLkgStorage: ()=>createInMemoryLkgStorage,
33
33
  createLastKnownGoodProvider: ()=>createLastKnownGoodProvider
34
34
  });
35
+ const universal_namespaceObject = require("@modern-js/utils/universal");
35
36
  const external_surface_resolution_types_js_namespaceObject = require("./surface-resolution-types.js");
36
37
  const LAST_KNOWN_GOOD_PROVIDER_NAME = 'last-known-good';
37
38
  function createInMemoryLkgStorage() {
@@ -65,16 +66,38 @@ function staleRecordResult(ref, env, ageMs, maxStaleMs) {
65
66
  })
66
67
  };
67
68
  }
69
+ function resolutionAnswersRef(resolved, ref) {
70
+ const selected = (0, universal_namespaceObject.selectResolvedSurface)(resolved, ref);
71
+ return selected.ok && selected.surface.servedMajor === ref.major;
72
+ }
68
73
  function createLastKnownGoodProvider(options) {
69
74
  const storage = options.storage ?? createInMemoryLkgStorage();
70
75
  const now = options.now ?? (()=>Math.floor(performance.timeOrigin + performance.now()));
71
76
  const maxStaleMs = options.freshness?.maxStaleMs;
77
+ let nextResolutionGeneration = 0;
78
+ const latestCacheableGenerationByKey = new Map();
79
+ const writeTailByKey = new Map();
80
+ async function cacheCompatibleResolution(key, generation, record) {
81
+ latestCacheableGenerationByKey.set(key, Math.max(latestCacheableGenerationByKey.get(key) ?? 0, generation));
82
+ const previous = writeTailByKey.get(key) ?? Promise.resolve();
83
+ const write = previous.catch(()=>void 0).then(async ()=>{
84
+ if (latestCacheableGenerationByKey.get(key) !== generation) return;
85
+ await storage.write(key, record);
86
+ });
87
+ writeTailByKey.set(key, write);
88
+ try {
89
+ await write;
90
+ } finally{
91
+ if (writeTailByKey.get(key) === write) writeTailByKey.delete(key);
92
+ }
93
+ }
72
94
  async function serveFromCache(ref, env, fallback) {
73
95
  const key = (0, external_surface_resolution_types_js_namespaceObject.deliveryUnitResolutionKey)(ref.unitId, env);
74
96
  const cached = await storage.read(key);
75
97
  if (!cached) return fallback();
76
98
  if (cached.major !== ref.major) return fallback();
77
- if ('incompatible' === cached.resolved.compatibility.status) return fallback();
99
+ if (!resolutionAnswersRef(cached.resolved, ref)) return fallback();
100
+ if ('compatible' !== cached.resolved.compatibility.status) return fallback();
78
101
  const ageMs = now() - cached.storedAt;
79
102
  if (void 0 !== maxStaleMs && ageMs > maxStaleMs) return staleRecordResult(ref, env, ageMs, maxStaleMs);
80
103
  return {
@@ -86,6 +109,7 @@ function createLastKnownGoodProvider(options) {
86
109
  name: LAST_KNOWN_GOOD_PROVIDER_NAME,
87
110
  async resolve (ref, env) {
88
111
  const key = (0, external_surface_resolution_types_js_namespaceObject.deliveryUnitResolutionKey)(ref.unitId, env);
112
+ const generation = ++nextResolutionGeneration;
89
113
  let resolution;
90
114
  try {
91
115
  resolution = await options.provider.resolve(ref, env);
@@ -102,7 +126,16 @@ function createLastKnownGoodProvider(options) {
102
126
  const failure = resolution;
103
127
  return serveFromCache(ref, env, ()=>failure);
104
128
  }
105
- if ('incompatible' !== resolution.unit.compatibility.status) await storage.write(key, {
129
+ if (!resolutionAnswersRef(resolution.unit, ref)) return serveFromCache(ref, env, ()=>({
130
+ ok: false,
131
+ error: (0, external_surface_resolution_types_js_namespaceObject.createDiscoveryError)('identity-mismatch', ref, `Provider ${options.provider.name} returned a delivery unit that does not answer the requested surface.`, {
132
+ env,
133
+ provider: options.provider.name,
134
+ recordUnitId: resolution.unit.unitId,
135
+ availableSurfaces: resolution.unit.surfaces.map((surface)=>surface.surfaceId)
136
+ })
137
+ }));
138
+ if ('compatible' === resolution.unit.compatibility.status) await cacheCompatibleResolution(key, generation, {
106
139
  resolved: resolution.unit,
107
140
  storedAt: now(),
108
141
  major: ref.major
@@ -41,40 +41,13 @@ __webpack_require__.d(__webpack_exports__, {
41
41
  });
42
42
  const external_node_path_namespaceObject = require("node:path");
43
43
  var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
44
- const promises_namespaceObject = require("node:timers/promises");
45
44
  const utils_namespaceObject = require("@modern-js/utils");
46
45
  const lodash_namespaceObject = require("@modern-js/utils/lodash");
47
- const lockPollIntervalMs = 25;
48
- const staleLockAgeMs = 120000;
49
46
  const pendingUpdates = new Map();
50
47
  let tempFileCounter = 0;
51
- async function acquireSpecLock(specPath) {
52
- const lockDir = `${specPath}.lock`;
53
- await utils_namespaceObject.fs.ensureDir(external_node_path_default().dirname(specPath));
54
- while(true){
55
- try {
56
- await utils_namespaceObject.fs.mkdir(lockDir);
57
- return async ()=>{
58
- await utils_namespaceObject.fs.remove(lockDir);
59
- };
60
- } catch (error) {
61
- if ('EEXIST' !== error.code) throw error;
62
- }
63
- try {
64
- const stat = await utils_namespaceObject.fs.stat(lockDir);
65
- if (performance.timeOrigin + performance.now() - stat.mtimeMs > staleLockAgeMs) {
66
- await utils_namespaceObject.fs.remove(lockDir);
67
- continue;
68
- }
69
- } catch (error) {
70
- if ('ENOENT' !== error.code) throw error;
71
- continue;
72
- }
73
- await (0, promises_namespaceObject.setTimeout)(lockPollIntervalMs);
74
- }
75
- }
76
48
  async function writeJSONAtomically(filePath, value) {
77
49
  const directory = external_node_path_default().dirname(filePath);
50
+ await utils_namespaceObject.fs.ensureDir(directory);
78
51
  const tempPath = external_node_path_default().join(directory, `.${external_node_path_default().basename(filePath)}.${process.pid}.${tempFileCounter += 1}.tmp`);
79
52
  try {
80
53
  await utils_namespaceObject.fs.writeFile(tempPath, `${JSON.stringify(value)}\n`);
@@ -89,16 +62,12 @@ async function updateNestedRoutesSpec(specPath, nextRoutes) {
89
62
  const nextRoutesSnapshot = (0, lodash_namespaceObject.cloneDeep)(nextRoutes);
90
63
  const previousUpdate = pendingUpdates.get(resolvedSpecPath) ?? Promise.resolve();
91
64
  const currentUpdate = previousUpdate.catch(()=>void 0).then(async ()=>{
92
- const releaseLock = await acquireSpecLock(resolvedSpecPath);
93
- try {
94
- const existingRoutes = await utils_namespaceObject.fs.pathExists(resolvedSpecPath) ? await utils_namespaceObject.fs.readJSON(resolvedSpecPath) : {};
95
- await writeJSONAtomically(resolvedSpecPath, {
96
- ...existingRoutes,
97
- ...nextRoutesSnapshot
98
- });
99
- } finally{
100
- await releaseLock();
101
- }
65
+ const existingRoutes = await utils_namespaceObject.fs.pathExists(resolvedSpecPath) ? await utils_namespaceObject.fs.readJSON(resolvedSpecPath) : {};
66
+ const mergedRoutes = {
67
+ ...existingRoutes,
68
+ ...nextRoutesSnapshot
69
+ };
70
+ await writeJSONAtomically(resolvedSpecPath, mergedRoutes);
102
71
  });
103
72
  pendingUpdates.set(resolvedSpecPath, currentUpdate);
104
73
  try {
@@ -22,6 +22,16 @@ var __webpack_require__ = {};
22
22
  define(values, "value");
23
23
  };
24
24
  })();
25
+ (()=>{
26
+ __webpack_require__.g = (()=>{
27
+ if ('object' == typeof globalThis) return globalThis;
28
+ try {
29
+ return this || new Function('return this')();
30
+ } catch (e) {
31
+ if ('object' == typeof window) return window;
32
+ }
33
+ })();
34
+ })();
25
35
  (()=>{
26
36
  __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
27
37
  })();
@@ -35,6 +45,24 @@ var __webpack_require__ = {};
35
45
  });
36
46
  };
37
47
  })();
48
+ (()=>{
49
+ var scriptUrl;
50
+ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + "";
51
+ var document = __webpack_require__.g.document;
52
+ if (!scriptUrl && document) {
53
+ if (document.currentScript && 'SCRIPT' === document.currentScript.tagName.toUpperCase()) scriptUrl = document.currentScript.src;
54
+ if (!scriptUrl) {
55
+ var scripts = document.getElementsByTagName("script");
56
+ if (scripts.length) {
57
+ var i = scripts.length - 1;
58
+ while(i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl)))scriptUrl = scripts[i--].src;
59
+ }
60
+ }
61
+ }
62
+ if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");
63
+ scriptUrl = scriptUrl.replace(/^blob:/, "").replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/");
64
+ __webpack_require__.p = scriptUrl + '../../';
65
+ })();
38
66
  var __webpack_exports__ = {};
39
67
  __webpack_require__.r(__webpack_exports__);
40
68
  __webpack_require__.d(__webpack_exports__, {
@@ -42,10 +70,19 @@ __webpack_require__.d(__webpack_exports__, {
42
70
  NavLink: ()=>NavLink
43
71
  });
44
72
  const jsx_runtime_namespaceObject = require("react/jsx-runtime");
73
+ const runtime_extensions_namespaceObject = require("@modern-js/runtime-extensions");
45
74
  const router_namespaceObject = require("@modern-js/runtime-utils/router");
46
75
  const external_react_namespaceObject = require("react");
47
76
  var external_react_default = /*#__PURE__*/ __webpack_require__.n(external_react_namespaceObject);
48
77
  const index_js_namespaceObject = require("../../core/context/index.js");
78
+ const getWebpackChunkLoader = ()=>__webpack_chunk_load__;
79
+ const getWebpackPublicPath = ()=>{
80
+ try {
81
+ return __webpack_require__.p || '';
82
+ } catch {
83
+ return '';
84
+ }
85
+ };
49
86
  function composeEventHandlers(theirHandler, ourHandler) {
50
87
  return (event)=>{
51
88
  theirHandler?.(event);
@@ -84,8 +121,7 @@ const runNextWarmup = ()=>{
84
121
  const task = warmupQueue.shift();
85
122
  if (task.cancelled) continue;
86
123
  activeWarmups += 1;
87
- task.run().catch((error)=>{
88
- console.error(error);
124
+ task.run().catch(()=>{
89
125
  warmupCache.delete(task.key);
90
126
  }).finally(()=>{
91
127
  activeWarmups -= 1;
@@ -107,6 +143,7 @@ const scheduleWarmup = (key, run)=>{
107
143
  runNextWarmup();
108
144
  return ()=>{
109
145
  task.cancelled = true;
146
+ if (warmupQueue.includes(task)) warmupCache.delete(task.key);
110
147
  };
111
148
  };
112
149
  const setRef = (ref, value)=>{
@@ -190,16 +227,17 @@ function usePrefetchBehavior(prefetch, preload, theirElementProps) {
190
227
  setViewportElement
191
228
  ];
192
229
  }
193
- async function loadRouteModule(route, routeAssets) {
230
+ async function loadRouteModule(route, routeAssets, chunkLoader) {
194
231
  const routeId = route.id;
195
232
  if (!routeId) return;
196
233
  if (!routeAssets[routeId]) return;
197
234
  const { chunkIds } = routeAssets[routeId];
198
235
  if (!chunkIds) return;
199
236
  try {
200
- await Promise.all(chunkIds.map((chunkId)=>__webpack_chunk_load__?.(chunkId)));
237
+ await Promise.all(chunkIds.map((chunkId)=>chunkLoader(chunkId)));
201
238
  } catch (error) {
202
239
  console.error(error);
240
+ throw error;
203
241
  }
204
242
  }
205
243
  const getRequestUrl = (pathname, routeId)=>{
@@ -232,22 +270,31 @@ const PrefetchPageLinks = ({ path, includeData })=>{
232
270
  pathname,
233
271
  routes
234
272
  ]);
273
+ const chunkLoader = getWebpackChunkLoader();
274
+ const routeAssetGeneration = JSON.stringify([
275
+ getWebpackPublicPath(),
276
+ matches?.map(({ route: { id } })=>[
277
+ id,
278
+ routeAssets?.[id]?.chunkIds
279
+ ])
280
+ ]);
235
281
  external_react_default().useEffect(()=>{
236
- if (!allowNetworkWarmup || !Array.isArray(matches) || !routeAssets || !__webpack_chunk_load__) return;
282
+ if (!allowNetworkWarmup || !Array.isArray(matches) || !routeAssets || !chunkLoader) return;
237
283
  const cancellations = matches.map((match)=>{
238
284
  const routeId = match.route.id;
239
285
  const routeAsset = routeId ? routeAssets[routeId] : void 0;
240
286
  const chunkIds = routeAsset?.chunkIds;
241
287
  if (!routeId || !Array.isArray(chunkIds) || 0 === chunkIds.length) return ()=>{};
242
- return scheduleWarmup(`route-module:${routeId}:${chunkIds.join(',')}`, ()=>loadRouteModule(match.route, routeAssets));
288
+ return scheduleWarmup((0, runtime_extensions_namespaceObject.getNavigationWarmupCacheKey)(context, chunkLoader, getWebpackPublicPath(), `route-module:${routeId}:${chunkIds.join(',')}`), ()=>loadRouteModule(match.route, routeAssets, chunkLoader));
243
289
  });
244
290
  return ()=>{
245
291
  cancellations.forEach((cancel)=>cancel());
246
292
  };
247
293
  }, [
248
294
  allowNetworkWarmup,
249
- matches,
250
- routeAssets
295
+ chunkLoader,
296
+ context,
297
+ routeAssetGeneration
251
298
  ]);
252
299
  if (!allowNetworkWarmup || !includeData || !window._SSR_DATA) return null;
253
300
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(PrefetchDataLinks, {
@@ -30,7 +30,17 @@ __webpack_require__.r(__webpack_exports__);
30
30
  const handleRSCRedirect = (headers, basename, status)=>{
31
31
  const newHeaders = new Headers(headers);
32
32
  let redirectUrl = headers.get('Location');
33
- if ('/' !== basename) redirectUrl = redirectUrl.replace(basename, '');
33
+ if (!redirectUrl || ![
34
+ 301,
35
+ 302,
36
+ 303,
37
+ 307,
38
+ 308
39
+ ].includes(status) || !URL.canParse(redirectUrl, 'http://localhost')) return new Response(null, {
40
+ status,
41
+ headers: newHeaders
42
+ });
43
+ if ('/' !== basename && redirectUrl.startsWith(basename)) redirectUrl = redirectUrl.slice(basename.length) || '/';
34
44
  newHeaders.set('X-Modernjs-Redirect', redirectUrl);
35
45
  newHeaders.set('X-Modernjs-BaseUrl', basename);
36
46
  newHeaders.delete('Location');
@@ -227,12 +227,14 @@ function serializeRouteErrorResponse(error) {
227
227
  status: error.status,
228
228
  statusText: 'Internal Server Error',
229
229
  data: 'Unexpected Server Error',
230
+ internal: error.internal,
230
231
  __type: 'RouteErrorResponse'
231
232
  };
232
233
  return {
233
234
  status: error.status,
234
235
  statusText: error.statusText,
235
236
  data: error.data,
237
+ internal: error.internal,
236
238
  __type: 'RouteErrorResponse'
237
239
  };
238
240
  }
@@ -12,7 +12,7 @@ class LoadablePlugin {
12
12
  const chunkLoadingGlobal = this.opts.chunkLoadingGlobal ?? compiler.options.output.chunkLoadingGlobal ?? DEFAULT_CHUNK_LOADING_GLOBAL;
13
13
  compiler.options.output.chunkLoadingGlobal = chunkLoadingGlobal;
14
14
  new compiler.webpack.DefinePlugin({
15
- 'process.env.MODERN_CHUNK_LOADING_GLOBAL': JSON.stringify(chunkLoadingGlobal)
15
+ __MODERN_CHUNK_LOADING_GLOBAL__: JSON.stringify(chunkLoadingGlobal)
16
16
  }).apply(compiler);
17
17
  if (this.opts.outputAsset || this.opts.writeToDisk) compiler.hooks.make.tap(LoadablePlugin.name, (compilation)=>{
18
18
  compilation.hooks.processAssets.tap({
@@ -5,18 +5,8 @@ import { hydrateRoot } from "react-dom/client";
5
5
  import { RenderLevel } from "../constants.mjs";
6
6
  import { wrapRuntimeContextProvider } from "../react/wrapper.mjs";
7
7
  import { WithCallback } from "./withCallback.mjs";
8
- const runtimeProcess = Reflect.get(globalThis, 'process');
9
- const runtimeEnvironment = null !== runtimeProcess && 'object' == typeof runtimeProcess ? Reflect.get(runtimeProcess, 'env') : void 0;
10
- const readRuntimeEnvironment = (name)=>{
11
- if (null === runtimeEnvironment || 'object' != typeof runtimeEnvironment) return;
12
- const value = Reflect.get(runtimeEnvironment, name);
13
- return 'string' == typeof value ? value : void 0;
14
- };
15
8
  const loadableReadyOptions = {
16
- chunkLoadingGlobal: (()=>{
17
- const configured = readRuntimeEnvironment('MODERN_CHUNK_LOADING_GLOBAL');
18
- return void 0 === configured || '' === configured ? '__LOADABLE_LOADED_CHUNKS__' : configured;
19
- })()
9
+ chunkLoadingGlobal: 'string' == typeof __MODERN_CHUNK_LOADING_GLOBAL__ && '' !== __MODERN_CHUNK_LOADING_GLOBAL__ ? __MODERN_CHUNK_LOADING_GLOBAL__ : '__LOADABLE_LOADED_CHUNKS__'
20
10
  };
21
11
  function hydrateWithReact(App, rootElement) {
22
12
  return Promise.resolve(hydrateRoot(rootElement, App, {
@@ -4,8 +4,13 @@ function getStore(context) {
4
4
  }
5
5
  function ensureStore(context) {
6
6
  const target = context;
7
- target[EXTENSIONS_SLOT] ??= new Map();
8
- return target[EXTENSIONS_SLOT];
7
+ const store = target[EXTENSIONS_SLOT] ?? new Map();
8
+ Object.defineProperty(target, EXTENSIONS_SLOT, {
9
+ configurable: true,
10
+ enumerable: true,
11
+ value: store
12
+ });
13
+ return store;
9
14
  }
10
15
  function stripRuntimeContextExtensions(context) {
11
16
  delete context[EXTENSIONS_SLOT];
@@ -3,8 +3,19 @@ const ROUTE_MANIFEST = '_MODERNJS_ROUTE_MANIFEST';
3
3
  const InternalRuntimeContext = createContext({});
4
4
  const getInitialContext = (isBrowser = true, routeManifest)=>{
5
5
  const requestContext = {
6
- request: {},
7
- response: {}
6
+ request: {
7
+ params: {},
8
+ pathname: '',
9
+ query: {},
10
+ headers: {},
11
+ host: '',
12
+ url: ''
13
+ },
14
+ response: {
15
+ setHeader () {},
16
+ status () {},
17
+ locals: {}
18
+ }
8
19
  };
9
20
  return {
10
21
  isBrowser,