@modern-js/plugin-garfish 2.70.1 → 2.70.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.
@@ -29,7 +29,7 @@ function generateRootDom(dom, id) {
29
29
  const mountNode = dom ? dom.querySelector(`#${id}`) || dom : document.getElementById(id);
30
30
  return mountNode;
31
31
  }
32
- function createProvider(id, { customBootstrap, beforeRender, disableComponentCompat } = {}) {
32
+ function createProvider(id, { customBootstrap, beforeRender, disableComponentCompat, basename: customBasename } = {}) {
33
33
  return ({ basename, dom }) => {
34
34
  let root = null;
35
35
  const SubModuleComponent = disableComponentCompat ? null : (props) => {
@@ -48,24 +48,25 @@ function createProvider(id, { customBootstrap, beforeRender, disableComponentCom
48
48
  };
49
49
  return {
50
50
  async render({ basename: basename2, dom: dom2, props, appName }) {
51
+ const finalBasename = customBasename || basename2;
51
52
  const ModernRoot = (0, import_react.createRoot)(null);
52
53
  const mountNode = generateRootDom(dom2, id || "root");
53
54
  if (customBootstrap) {
54
55
  root = await customBootstrap(ModernRoot, () => (0, import_browser.render)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModernRoot, {
55
- basename: basename2,
56
+ basename: finalBasename,
56
57
  appName,
57
58
  ...props
58
59
  }), mountNode));
59
60
  } else {
60
61
  if (beforeRender) {
61
62
  await beforeRender(ModernRoot, {
62
- basename: basename2,
63
+ basename: finalBasename,
63
64
  appName,
64
65
  ...props
65
66
  });
66
67
  }
67
68
  root = await (0, import_browser.render)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModernRoot, {
68
- basename: basename2,
69
+ basename: finalBasename,
69
70
  appName,
70
71
  ...props
71
72
  }), mountNode);
@@ -55,6 +55,35 @@ function pathJoin(...args) {
55
55
  }, "");
56
56
  return res || "/";
57
57
  }
58
+ function deepEqualExcludeFunctions(prev, next) {
59
+ if (prev === next)
60
+ return true;
61
+ if (!prev || !next)
62
+ return false;
63
+ if (typeof prev !== "object" || typeof next !== "object")
64
+ return false;
65
+ const prevKeys = Object.keys(prev).filter((key) => typeof prev[key] !== "function");
66
+ const nextKeys = Object.keys(next).filter((key) => typeof next[key] !== "function");
67
+ if (prevKeys.length !== nextKeys.length)
68
+ return false;
69
+ for (const key of prevKeys) {
70
+ if (!nextKeys.includes(key))
71
+ return false;
72
+ const prevVal = prev[key];
73
+ const nextVal = next[key];
74
+ if (typeof prevVal === "function" || typeof nextVal === "function") {
75
+ continue;
76
+ }
77
+ if (typeof prevVal === "object" && typeof nextVal === "object") {
78
+ if (!deepEqualExcludeFunctions(prevVal, nextVal)) {
79
+ return false;
80
+ }
81
+ } else if (prevVal !== nextVal) {
82
+ return false;
83
+ }
84
+ }
85
+ return true;
86
+ }
58
87
  function getAppInstance(options, appInfo, manifest) {
59
88
  const componentSetterRegistry = {
60
89
  current: null
@@ -63,10 +92,15 @@ function getAppInstance(options, appInfo, manifest) {
63
92
  var _context_router, _context_router1, _context_router2, _context_router3, _context_router4;
64
93
  const appRef = (0, import_react.useRef)(null);
65
94
  const locationHrefRef = (0, import_react.useRef)("");
95
+ const propsRef = (0, import_react.useRef)(props);
96
+ const previousPropsRef = (0, import_react.useRef)(props);
97
+ const propsUpdateCounterRef = (0, import_react.useRef)(0);
66
98
  const domId = (0, import_util.generateSubAppContainerKey)(appInfo);
67
- const [{ component: SubModuleComponent }, setSubModuleComponent] = (0, import_react.useState)({
68
- component: null
99
+ const [{ component: SubModuleComponent, isFromJupiter }, setSubModuleComponent] = (0, import_react.useState)({
100
+ component: null,
101
+ isFromJupiter: false
69
102
  });
103
+ const [propsUpdateKey, setPropsUpdateKey] = (0, import_react.useState)(0);
70
104
  const context = (0, import_react.useContext)(import_runtime.RuntimeReactContext);
71
105
  var _props_useRouteMatch;
72
106
  const useRouteMatch = (_props_useRouteMatch = props.useRouteMatch) !== null && _props_useRouteMatch !== void 0 ? _props_useRouteMatch : context === null || context === void 0 ? void 0 : (_context_router = context.router) === null || _context_router === void 0 ? void 0 : _context_router.useRouteMatch;
@@ -133,9 +167,36 @@ or directly pass the "basename":
133
167
  }, [
134
168
  locationPathname
135
169
  ]);
170
+ (0, import_react.useEffect)(() => {
171
+ const prevPropsForCompare = {
172
+ ...previousPropsRef.current
173
+ };
174
+ const currentPropsForCompare = {
175
+ ...props
176
+ };
177
+ Object.keys(prevPropsForCompare).forEach((key) => {
178
+ if (typeof prevPropsForCompare[key] === "function") {
179
+ delete prevPropsForCompare[key];
180
+ }
181
+ });
182
+ Object.keys(currentPropsForCompare).forEach((key) => {
183
+ if (typeof currentPropsForCompare[key] === "function") {
184
+ delete currentPropsForCompare[key];
185
+ }
186
+ });
187
+ if (!deepEqualExcludeFunctions(prevPropsForCompare, currentPropsForCompare)) {
188
+ previousPropsRef.current = props;
189
+ propsRef.current = props;
190
+ propsUpdateCounterRef.current += 1;
191
+ setPropsUpdateKey((prev) => prev + 1);
192
+ }
193
+ }, [
194
+ props,
195
+ appInfo.name
196
+ ]);
136
197
  (0, import_react.useEffect)(() => {
137
198
  componentSetterRegistry.current = setSubModuleComponent;
138
- const { setLoadingState, ...userProps } = props;
199
+ const { setLoadingState: setLoadingState2, ...userProps } = propsRef.current;
139
200
  const loadAppOptions = {
140
201
  cache: true,
141
202
  insulationVariable: [
@@ -152,13 +213,15 @@ or directly pass the "basename":
152
213
  customLoader: (provider) => {
153
214
  const { render, destroy, SubModuleComponent: SubModuleComponent2, jupiter_submodule_app_key } = provider;
154
215
  const SubComponent = SubModuleComponent2 || jupiter_submodule_app_key;
216
+ const isFromJupiter2 = !SubModuleComponent2 && !!jupiter_submodule_app_key;
155
217
  const componetRenderMode = manifest === null || manifest === void 0 ? void 0 : manifest.componentRender;
156
218
  return {
157
219
  mount: (...props2) => {
158
220
  if (componetRenderMode && SubComponent) {
159
221
  if (componentSetterRegistry.current) {
160
222
  componentSetterRegistry.current({
161
- component: SubComponent
223
+ component: SubComponent,
224
+ isFromJupiter: isFromJupiter2
162
225
  });
163
226
  } else {
164
227
  (0, import_util.logger)(`[Garfish] MicroApp for "${appInfo.name}" tried to mount, but no active component setter was found.`);
@@ -179,7 +242,7 @@ or directly pass the "basename":
179
242
  };
180
243
  }
181
244
  };
182
- setLoadingState({
245
+ setLoadingState2({
183
246
  isLoading: true,
184
247
  error: null
185
248
  });
@@ -193,7 +256,7 @@ or directly pass the "basename":
193
256
  throw new Error(`MicroApp Garfish.loadApp "${appInfo.name}" result is null`);
194
257
  }
195
258
  appRef.current = appInstance;
196
- setLoadingState({
259
+ setLoadingState2({
197
260
  isLoading: false
198
261
  });
199
262
  if (appInstance.mounted && appInstance.appInfo.cache) {
@@ -210,7 +273,7 @@ or directly pass the "basename":
210
273
  await (appInstance === null || appInstance === void 0 ? void 0 : appInstance.mount());
211
274
  }
212
275
  } catch (error) {
213
- setLoadingState({
276
+ setLoadingState2({
214
277
  isLoading: true,
215
278
  error
216
279
  });
@@ -232,12 +295,40 @@ or directly pass the "basename":
232
295
  }
233
296
  }
234
297
  };
235
- }, []);
298
+ }, [
299
+ basename,
300
+ domId,
301
+ appInfo.name
302
+ ]);
303
+ (0, import_react.useEffect)(() => {
304
+ var _appRef_current;
305
+ if ((_appRef_current = appRef.current) === null || _appRef_current === void 0 ? void 0 : _appRef_current.appInfo) {
306
+ const { setLoadingState: setLoadingState2, ...updatedProps } = props;
307
+ const updatedPropsWithKey = {
308
+ ...appInfo.props,
309
+ ...updatedProps,
310
+ _garfishPropsUpdateKey: propsUpdateKey
311
+ };
312
+ appRef.current.appInfo.props = updatedPropsWithKey;
313
+ }
314
+ }, [
315
+ propsUpdateKey,
316
+ props
317
+ ]);
318
+ const { setLoadingState, ...renderProps } = props;
319
+ const finalRenderProps = {
320
+ ...renderProps,
321
+ _garfishPropsUpdateKey: propsUpdateKey
322
+ };
323
+ const componentKey = isFromJupiter ? void 0 : `${appInfo.name}-${propsUpdateKey}`;
236
324
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {
237
325
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
238
326
  id: domId,
239
327
  children: SubModuleComponent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SubModuleComponent, {
240
- ...props
328
+ ...componentKey ? {
329
+ key: componentKey
330
+ } : {},
331
+ ...finalRenderProps
241
332
  })
242
333
  })
243
334
  });
@@ -10,7 +10,7 @@ function generateRootDom(dom, id) {
10
10
  return mountNode;
11
11
  }
12
12
  function createProvider(id) {
13
- var _ref = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, customBootstrap = _ref.customBootstrap, beforeRender = _ref.beforeRender, disableComponentCompat = _ref.disableComponentCompat;
13
+ var _ref = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, customBootstrap = _ref.customBootstrap, beforeRender = _ref.beforeRender, disableComponentCompat = _ref.disableComponentCompat, customBasename = _ref.basename;
14
14
  return function(param) {
15
15
  var basename = param.basename, dom = param.dom;
16
16
  var root = null;
@@ -30,10 +30,11 @@ function createProvider(id) {
30
30
  render: function render1(param2) {
31
31
  var basename2 = param2.basename, dom2 = param2.dom, props = param2.props, appName = param2.appName;
32
32
  return _async_to_generator(function() {
33
- var ModernRoot, mountNode;
33
+ var finalBasename, ModernRoot, mountNode;
34
34
  return _ts_generator(this, function(_state) {
35
35
  switch (_state.label) {
36
36
  case 0:
37
+ finalBasename = customBasename || basename2;
37
38
  ModernRoot = createRoot(null);
38
39
  mountNode = generateRootDom(dom2, id || "root");
39
40
  if (!customBootstrap)
@@ -45,7 +46,7 @@ function createProvider(id) {
45
46
  4,
46
47
  customBootstrap(ModernRoot, function() {
47
48
  return render(/* @__PURE__ */ _jsx(ModernRoot, _object_spread({
48
- basename: basename2,
49
+ basename: finalBasename,
49
50
  appName
50
51
  }, props)), mountNode);
51
52
  })
@@ -65,7 +66,7 @@ function createProvider(id) {
65
66
  return [
66
67
  4,
67
68
  beforeRender(ModernRoot, _object_spread({
68
- basename: basename2,
69
+ basename: finalBasename,
69
70
  appName
70
71
  }, props))
71
72
  ];
@@ -76,7 +77,7 @@ function createProvider(id) {
76
77
  return [
77
78
  4,
78
79
  render(/* @__PURE__ */ _jsx(ModernRoot, _object_spread({
79
- basename: basename2,
80
+ basename: finalBasename,
80
81
  appName
81
82
  }, props)), mountNode)
82
83
  ];
@@ -4,6 +4,7 @@ import { _ as _object_spread_props } from "@swc/helpers/_/_object_spread_props";
4
4
  import { _ as _object_without_properties } from "@swc/helpers/_/_object_without_properties";
5
5
  import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
6
6
  import { _ as _to_consumable_array } from "@swc/helpers/_/_to_consumable_array";
7
+ import { _ as _type_of } from "@swc/helpers/_/_type_of";
7
8
  import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
8
9
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
9
10
  import { RuntimeReactContext } from "@meta/runtime";
@@ -31,6 +32,56 @@ function pathJoin() {
31
32
  }, "");
32
33
  return res || "/";
33
34
  }
35
+ function deepEqualExcludeFunctions(prev, next) {
36
+ if (prev === next)
37
+ return true;
38
+ if (!prev || !next)
39
+ return false;
40
+ if ((typeof prev === "undefined" ? "undefined" : _type_of(prev)) !== "object" || (typeof next === "undefined" ? "undefined" : _type_of(next)) !== "object")
41
+ return false;
42
+ var prevKeys = Object.keys(prev).filter(function(key2) {
43
+ return typeof prev[key2] !== "function";
44
+ });
45
+ var nextKeys = Object.keys(next).filter(function(key2) {
46
+ return typeof next[key2] !== "function";
47
+ });
48
+ if (prevKeys.length !== nextKeys.length)
49
+ return false;
50
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
51
+ try {
52
+ for (var _iterator = prevKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
53
+ var key = _step.value;
54
+ if (!nextKeys.includes(key))
55
+ return false;
56
+ var prevVal = prev[key];
57
+ var nextVal = next[key];
58
+ if (typeof prevVal === "function" || typeof nextVal === "function") {
59
+ continue;
60
+ }
61
+ if ((typeof prevVal === "undefined" ? "undefined" : _type_of(prevVal)) === "object" && (typeof nextVal === "undefined" ? "undefined" : _type_of(nextVal)) === "object") {
62
+ if (!deepEqualExcludeFunctions(prevVal, nextVal)) {
63
+ return false;
64
+ }
65
+ } else if (prevVal !== nextVal) {
66
+ return false;
67
+ }
68
+ }
69
+ } catch (err) {
70
+ _didIteratorError = true;
71
+ _iteratorError = err;
72
+ } finally {
73
+ try {
74
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
75
+ _iterator.return();
76
+ }
77
+ } finally {
78
+ if (_didIteratorError) {
79
+ throw _iteratorError;
80
+ }
81
+ }
82
+ }
83
+ return true;
84
+ }
34
85
  function getAppInstance(options, appInfo, manifest) {
35
86
  var componentSetterRegistry = {
36
87
  current: null
@@ -39,10 +90,15 @@ function getAppInstance(options, appInfo, manifest) {
39
90
  var _context_router, _context_router1, _context_router2, _context_router3, _context_router4;
40
91
  var appRef = useRef(null);
41
92
  var locationHrefRef = useRef("");
93
+ var propsRef = useRef(props);
94
+ var previousPropsRef = useRef(props);
95
+ var propsUpdateCounterRef = useRef(0);
42
96
  var domId = generateSubAppContainerKey(appInfo);
43
97
  var _useState = _sliced_to_array(useState({
44
- component: null
45
- }), 2), _useState_ = _useState[0], SubModuleComponent = _useState_.component, setSubModuleComponent = _useState[1];
98
+ component: null,
99
+ isFromJupiter: false
100
+ }), 2), _useState_ = _useState[0], SubModuleComponent = _useState_.component, isFromJupiter = _useState_.isFromJupiter, setSubModuleComponent = _useState[1];
101
+ var _useState1 = _sliced_to_array(useState(0), 2), propsUpdateKey = _useState1[0], setPropsUpdateKey = _useState1[1];
46
102
  var context = useContext(RuntimeReactContext);
47
103
  var _props_useRouteMatch;
48
104
  var useRouteMatch = (_props_useRouteMatch = props.useRouteMatch) !== null && _props_useRouteMatch !== void 0 ? _props_useRouteMatch : context === null || context === void 0 ? void 0 : (_context_router = context.router) === null || _context_router === void 0 ? void 0 : _context_router.useRouteMatch;
@@ -107,12 +163,37 @@ or directly pass the "basename":
107
163
  }, [
108
164
  locationPathname
109
165
  ]);
166
+ useEffect(function() {
167
+ var prevPropsForCompare = _object_spread({}, previousPropsRef.current);
168
+ var currentPropsForCompare = _object_spread({}, props);
169
+ Object.keys(prevPropsForCompare).forEach(function(key2) {
170
+ if (typeof prevPropsForCompare[key2] === "function") {
171
+ delete prevPropsForCompare[key2];
172
+ }
173
+ });
174
+ Object.keys(currentPropsForCompare).forEach(function(key2) {
175
+ if (typeof currentPropsForCompare[key2] === "function") {
176
+ delete currentPropsForCompare[key2];
177
+ }
178
+ });
179
+ if (!deepEqualExcludeFunctions(prevPropsForCompare, currentPropsForCompare)) {
180
+ previousPropsRef.current = props;
181
+ propsRef.current = props;
182
+ propsUpdateCounterRef.current += 1;
183
+ setPropsUpdateKey(function(prev) {
184
+ return prev + 1;
185
+ });
186
+ }
187
+ }, [
188
+ props,
189
+ appInfo.name
190
+ ]);
110
191
  useEffect(function() {
111
192
  var renderApp = function renderApp2() {
112
193
  return _renderApp.apply(this, arguments);
113
194
  };
114
195
  componentSetterRegistry.current = setSubModuleComponent;
115
- var setLoadingState = props.setLoadingState, userProps = _object_without_properties(props, [
196
+ var _propsRef_current = propsRef.current, setLoadingState2 = _propsRef_current.setLoadingState, userProps = _object_without_properties(_propsRef_current, [
116
197
  "setLoadingState"
117
198
  ]);
118
199
  var loadAppOptions = _object_spread_props(_object_spread({
@@ -127,6 +208,7 @@ or directly pass the "basename":
127
208
  customLoader: function(provider) {
128
209
  var render = provider.render, destroy = provider.destroy, SubModuleComponent2 = provider.SubModuleComponent, jupiter_submodule_app_key = provider.jupiter_submodule_app_key;
129
210
  var SubComponent = SubModuleComponent2 || jupiter_submodule_app_key;
211
+ var isFromJupiter2 = !SubModuleComponent2 && !!jupiter_submodule_app_key;
130
212
  var componetRenderMode = manifest === null || manifest === void 0 ? void 0 : manifest.componentRender;
131
213
  return {
132
214
  mount: function() {
@@ -136,7 +218,8 @@ or directly pass the "basename":
136
218
  if (componetRenderMode && SubComponent) {
137
219
  if (componentSetterRegistry.current) {
138
220
  componentSetterRegistry.current({
139
- component: SubComponent
221
+ component: SubComponent,
222
+ isFromJupiter: isFromJupiter2
140
223
  });
141
224
  } else {
142
225
  logger('[Garfish] MicroApp for "'.concat(appInfo.name, '" tried to mount, but no active component setter was found.'));
@@ -160,7 +243,7 @@ or directly pass the "basename":
160
243
  };
161
244
  }
162
245
  });
163
- setLoadingState({
246
+ setLoadingState2({
164
247
  isLoading: true,
165
248
  error: null
166
249
  });
@@ -189,7 +272,7 @@ or directly pass the "basename":
189
272
  throw new Error('MicroApp Garfish.loadApp "'.concat(appInfo.name, '" result is null'));
190
273
  }
191
274
  appRef.current = appInstance;
192
- setLoadingState({
275
+ setLoadingState2({
193
276
  isLoading: false
194
277
  });
195
278
  if (!(appInstance.mounted && appInstance.appInfo.cache))
@@ -230,7 +313,7 @@ or directly pass the "basename":
230
313
  ];
231
314
  case 6:
232
315
  error = _state.sent();
233
- setLoadingState({
316
+ setLoadingState2({
234
317
  isLoading: true,
235
318
  error
236
319
  });
@@ -263,11 +346,39 @@ or directly pass the "basename":
263
346
  }
264
347
  }
265
348
  };
266
- }, []);
349
+ }, [
350
+ basename,
351
+ domId,
352
+ appInfo.name
353
+ ]);
354
+ useEffect(function() {
355
+ var _appRef_current;
356
+ if ((_appRef_current = appRef.current) === null || _appRef_current === void 0 ? void 0 : _appRef_current.appInfo) {
357
+ var setLoadingState2 = props.setLoadingState, updatedProps = _object_without_properties(props, [
358
+ "setLoadingState"
359
+ ]);
360
+ var updatedPropsWithKey = _object_spread_props(_object_spread({}, appInfo.props, updatedProps), {
361
+ _garfishPropsUpdateKey: propsUpdateKey
362
+ });
363
+ appRef.current.appInfo.props = updatedPropsWithKey;
364
+ }
365
+ }, [
366
+ propsUpdateKey,
367
+ props
368
+ ]);
369
+ var setLoadingState = props.setLoadingState, renderProps = _object_without_properties(props, [
370
+ "setLoadingState"
371
+ ]);
372
+ var finalRenderProps = _object_spread_props(_object_spread({}, renderProps), {
373
+ _garfishPropsUpdateKey: propsUpdateKey
374
+ });
375
+ var componentKey = isFromJupiter ? void 0 : "".concat(appInfo.name, "-").concat(propsUpdateKey);
267
376
  return /* @__PURE__ */ _jsx(_Fragment, {
268
377
  children: /* @__PURE__ */ _jsx("div", {
269
378
  id: domId,
270
- children: SubModuleComponent && /* @__PURE__ */ _jsx(SubModuleComponent, _object_spread({}, props))
379
+ children: SubModuleComponent && /* @__PURE__ */ _jsx(SubModuleComponent, _object_spread({}, componentKey ? {
380
+ key: componentKey
381
+ } : {}, finalRenderProps))
271
382
  })
272
383
  });
273
384
  }
@@ -6,7 +6,7 @@ function generateRootDom(dom, id) {
6
6
  const mountNode = dom ? dom.querySelector(`#${id}`) || dom : document.getElementById(id);
7
7
  return mountNode;
8
8
  }
9
- function createProvider(id, { customBootstrap, beforeRender, disableComponentCompat } = {}) {
9
+ function createProvider(id, { customBootstrap, beforeRender, disableComponentCompat, basename: customBasename } = {}) {
10
10
  return ({ basename, dom }) => {
11
11
  let root = null;
12
12
  const SubModuleComponent = disableComponentCompat ? null : (props) => {
@@ -25,24 +25,25 @@ function createProvider(id, { customBootstrap, beforeRender, disableComponentCom
25
25
  };
26
26
  return {
27
27
  async render({ basename: basename2, dom: dom2, props, appName }) {
28
+ const finalBasename = customBasename || basename2;
28
29
  const ModernRoot = createRoot(null);
29
30
  const mountNode = generateRootDom(dom2, id || "root");
30
31
  if (customBootstrap) {
31
32
  root = await customBootstrap(ModernRoot, () => render(/* @__PURE__ */ _jsx(ModernRoot, {
32
- basename: basename2,
33
+ basename: finalBasename,
33
34
  appName,
34
35
  ...props
35
36
  }), mountNode));
36
37
  } else {
37
38
  if (beforeRender) {
38
39
  await beforeRender(ModernRoot, {
39
- basename: basename2,
40
+ basename: finalBasename,
40
41
  appName,
41
42
  ...props
42
43
  });
43
44
  }
44
45
  root = await render(/* @__PURE__ */ _jsx(ModernRoot, {
45
- basename: basename2,
46
+ basename: finalBasename,
46
47
  appName,
47
48
  ...props
48
49
  }), mountNode);
@@ -21,6 +21,35 @@ function pathJoin(...args) {
21
21
  }, "");
22
22
  return res || "/";
23
23
  }
24
+ function deepEqualExcludeFunctions(prev, next) {
25
+ if (prev === next)
26
+ return true;
27
+ if (!prev || !next)
28
+ return false;
29
+ if (typeof prev !== "object" || typeof next !== "object")
30
+ return false;
31
+ const prevKeys = Object.keys(prev).filter((key) => typeof prev[key] !== "function");
32
+ const nextKeys = Object.keys(next).filter((key) => typeof next[key] !== "function");
33
+ if (prevKeys.length !== nextKeys.length)
34
+ return false;
35
+ for (const key of prevKeys) {
36
+ if (!nextKeys.includes(key))
37
+ return false;
38
+ const prevVal = prev[key];
39
+ const nextVal = next[key];
40
+ if (typeof prevVal === "function" || typeof nextVal === "function") {
41
+ continue;
42
+ }
43
+ if (typeof prevVal === "object" && typeof nextVal === "object") {
44
+ if (!deepEqualExcludeFunctions(prevVal, nextVal)) {
45
+ return false;
46
+ }
47
+ } else if (prevVal !== nextVal) {
48
+ return false;
49
+ }
50
+ }
51
+ return true;
52
+ }
24
53
  function getAppInstance(options, appInfo, manifest) {
25
54
  const componentSetterRegistry = {
26
55
  current: null
@@ -29,10 +58,15 @@ function getAppInstance(options, appInfo, manifest) {
29
58
  var _context_router, _context_router1, _context_router2, _context_router3, _context_router4;
30
59
  const appRef = useRef(null);
31
60
  const locationHrefRef = useRef("");
61
+ const propsRef = useRef(props);
62
+ const previousPropsRef = useRef(props);
63
+ const propsUpdateCounterRef = useRef(0);
32
64
  const domId = generateSubAppContainerKey(appInfo);
33
- const [{ component: SubModuleComponent }, setSubModuleComponent] = useState({
34
- component: null
65
+ const [{ component: SubModuleComponent, isFromJupiter }, setSubModuleComponent] = useState({
66
+ component: null,
67
+ isFromJupiter: false
35
68
  });
69
+ const [propsUpdateKey, setPropsUpdateKey] = useState(0);
36
70
  const context = useContext(RuntimeReactContext);
37
71
  var _props_useRouteMatch;
38
72
  const useRouteMatch = (_props_useRouteMatch = props.useRouteMatch) !== null && _props_useRouteMatch !== void 0 ? _props_useRouteMatch : context === null || context === void 0 ? void 0 : (_context_router = context.router) === null || _context_router === void 0 ? void 0 : _context_router.useRouteMatch;
@@ -99,9 +133,36 @@ or directly pass the "basename":
99
133
  }, [
100
134
  locationPathname
101
135
  ]);
136
+ useEffect(() => {
137
+ const prevPropsForCompare = {
138
+ ...previousPropsRef.current
139
+ };
140
+ const currentPropsForCompare = {
141
+ ...props
142
+ };
143
+ Object.keys(prevPropsForCompare).forEach((key) => {
144
+ if (typeof prevPropsForCompare[key] === "function") {
145
+ delete prevPropsForCompare[key];
146
+ }
147
+ });
148
+ Object.keys(currentPropsForCompare).forEach((key) => {
149
+ if (typeof currentPropsForCompare[key] === "function") {
150
+ delete currentPropsForCompare[key];
151
+ }
152
+ });
153
+ if (!deepEqualExcludeFunctions(prevPropsForCompare, currentPropsForCompare)) {
154
+ previousPropsRef.current = props;
155
+ propsRef.current = props;
156
+ propsUpdateCounterRef.current += 1;
157
+ setPropsUpdateKey((prev) => prev + 1);
158
+ }
159
+ }, [
160
+ props,
161
+ appInfo.name
162
+ ]);
102
163
  useEffect(() => {
103
164
  componentSetterRegistry.current = setSubModuleComponent;
104
- const { setLoadingState, ...userProps } = props;
165
+ const { setLoadingState: setLoadingState2, ...userProps } = propsRef.current;
105
166
  const loadAppOptions = {
106
167
  cache: true,
107
168
  insulationVariable: [
@@ -118,13 +179,15 @@ or directly pass the "basename":
118
179
  customLoader: (provider) => {
119
180
  const { render, destroy, SubModuleComponent: SubModuleComponent2, jupiter_submodule_app_key } = provider;
120
181
  const SubComponent = SubModuleComponent2 || jupiter_submodule_app_key;
182
+ const isFromJupiter2 = !SubModuleComponent2 && !!jupiter_submodule_app_key;
121
183
  const componetRenderMode = manifest === null || manifest === void 0 ? void 0 : manifest.componentRender;
122
184
  return {
123
185
  mount: (...props2) => {
124
186
  if (componetRenderMode && SubComponent) {
125
187
  if (componentSetterRegistry.current) {
126
188
  componentSetterRegistry.current({
127
- component: SubComponent
189
+ component: SubComponent,
190
+ isFromJupiter: isFromJupiter2
128
191
  });
129
192
  } else {
130
193
  logger(`[Garfish] MicroApp for "${appInfo.name}" tried to mount, but no active component setter was found.`);
@@ -145,7 +208,7 @@ or directly pass the "basename":
145
208
  };
146
209
  }
147
210
  };
148
- setLoadingState({
211
+ setLoadingState2({
149
212
  isLoading: true,
150
213
  error: null
151
214
  });
@@ -159,7 +222,7 @@ or directly pass the "basename":
159
222
  throw new Error(`MicroApp Garfish.loadApp "${appInfo.name}" result is null`);
160
223
  }
161
224
  appRef.current = appInstance;
162
- setLoadingState({
225
+ setLoadingState2({
163
226
  isLoading: false
164
227
  });
165
228
  if (appInstance.mounted && appInstance.appInfo.cache) {
@@ -176,7 +239,7 @@ or directly pass the "basename":
176
239
  await (appInstance === null || appInstance === void 0 ? void 0 : appInstance.mount());
177
240
  }
178
241
  } catch (error) {
179
- setLoadingState({
242
+ setLoadingState2({
180
243
  isLoading: true,
181
244
  error
182
245
  });
@@ -198,12 +261,40 @@ or directly pass the "basename":
198
261
  }
199
262
  }
200
263
  };
201
- }, []);
264
+ }, [
265
+ basename,
266
+ domId,
267
+ appInfo.name
268
+ ]);
269
+ useEffect(() => {
270
+ var _appRef_current;
271
+ if ((_appRef_current = appRef.current) === null || _appRef_current === void 0 ? void 0 : _appRef_current.appInfo) {
272
+ const { setLoadingState: setLoadingState2, ...updatedProps } = props;
273
+ const updatedPropsWithKey = {
274
+ ...appInfo.props,
275
+ ...updatedProps,
276
+ _garfishPropsUpdateKey: propsUpdateKey
277
+ };
278
+ appRef.current.appInfo.props = updatedPropsWithKey;
279
+ }
280
+ }, [
281
+ propsUpdateKey,
282
+ props
283
+ ]);
284
+ const { setLoadingState, ...renderProps } = props;
285
+ const finalRenderProps = {
286
+ ...renderProps,
287
+ _garfishPropsUpdateKey: propsUpdateKey
288
+ };
289
+ const componentKey = isFromJupiter ? void 0 : `${appInfo.name}-${propsUpdateKey}`;
202
290
  return /* @__PURE__ */ _jsx(_Fragment, {
203
291
  children: /* @__PURE__ */ _jsx("div", {
204
292
  id: domId,
205
293
  children: SubModuleComponent && /* @__PURE__ */ _jsx(SubModuleComponent, {
206
- ...props
294
+ ...componentKey ? {
295
+ key: componentKey
296
+ } : {},
297
+ ...finalRenderProps
207
298
  })
208
299
  })
209
300
  });
@@ -1,9 +1,10 @@
1
1
  import { type RenderFunc } from '@meta/runtime/browser';
2
2
  import type { Root } from 'react-dom/client';
3
- export declare function createProvider(id?: string, { customBootstrap, beforeRender, disableComponentCompat, }?: {
3
+ export declare function createProvider(id?: string, { customBootstrap, beforeRender, disableComponentCompat, basename: customBasename, }?: {
4
4
  customBootstrap?: (App: React.ComponentType, render: RenderFunc) => Promise<HTMLElement | Root>;
5
5
  beforeRender?: (App: React.ComponentType, props?: Record<string, any>) => Promise<any>;
6
6
  disableComponentCompat?: boolean;
7
+ basename?: string;
7
8
  }): ({ basename, dom }: {
8
9
  basename: string;
9
10
  dom: HTMLElement;
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "modern",
16
16
  "modern.js"
17
17
  ],
18
- "version": "2.70.1",
18
+ "version": "2.70.2",
19
19
  "jsnext:source": "./src/cli/index.ts",
20
20
  "types": "./dist/types/cli/index.d.ts",
21
21
  "typesVersions": {
@@ -69,12 +69,12 @@
69
69
  "debug": "4.3.7",
70
70
  "garfish": "^1.8.1",
71
71
  "react-loadable": "^5.5.0",
72
- "@modern-js/plugin-v2": "2.70.1",
73
- "@modern-js/runtime-utils": "2.70.1",
74
- "@modern-js/utils": "2.70.1"
72
+ "@modern-js/plugin-v2": "2.70.2",
73
+ "@modern-js/runtime-utils": "2.70.2",
74
+ "@modern-js/utils": "2.70.2"
75
75
  },
76
76
  "peerDependencies": {
77
- "@modern-js/runtime": "^2.70.1",
77
+ "@modern-js/runtime": "^2.70.2",
78
78
  "react": ">=17",
79
79
  "react-dom": ">=17"
80
80
  },
@@ -91,15 +91,15 @@
91
91
  "jest-location-mock": "2.0.0",
92
92
  "react": "^18.3.1",
93
93
  "react-dom": "^18.3.1",
94
- "react-router-dom": "6.27.0",
94
+ "react-router-dom": "6.30.3",
95
95
  "typescript": "^5",
96
- "@modern-js/app-tools": "2.70.1",
97
- "@modern-js/core": "2.70.1",
98
- "@modern-js/plugin-router-v5": "2.70.1",
99
- "@modern-js/runtime": "2.70.1",
100
- "@modern-js/types": "2.70.1",
96
+ "@modern-js/app-tools": "2.70.2",
97
+ "@modern-js/plugin-router-v5": "2.70.2",
98
+ "@modern-js/core": "2.70.2",
99
+ "@modern-js/types": "2.70.2",
101
100
  "@scripts/build": "2.66.0",
102
- "@scripts/jest-config": "2.66.0"
101
+ "@scripts/jest-config": "2.66.0",
102
+ "@modern-js/runtime": "2.70.2"
103
103
  },
104
104
  "sideEffects": false,
105
105
  "publishConfig": {