@modern-js/runtime 1.4.4 → 1.16.0

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 (88) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/js/modern/cli/index.js +6 -6
  3. package/dist/js/modern/core/app-config.js +10 -0
  4. package/dist/js/modern/core/compatible.js +241 -0
  5. package/dist/js/modern/core/index.js +7 -0
  6. package/dist/js/modern/core/loader/index.js +1 -0
  7. package/dist/js/modern/core/loader/loaderManager.js +189 -0
  8. package/dist/js/modern/core/loader/useLoader.js +105 -0
  9. package/dist/js/modern/core/plugin.js +63 -0
  10. package/dist/js/modern/core/runtime-context.js +2 -0
  11. package/dist/js/modern/exports/styled.js +2 -2
  12. package/dist/js/modern/index.js +1 -1
  13. package/dist/js/modern/router/runtime/plugin.js +1 -1
  14. package/dist/js/modern/router/runtime/utils.js +3 -1
  15. package/dist/js/modern/ssr/index.js +34 -13
  16. package/dist/js/modern/ssr/index.node.js +1 -1
  17. package/dist/js/modern/ssr/prefetch.js +2 -2
  18. package/dist/js/modern/ssr/react/withCallback/index.js +17 -0
  19. package/dist/js/modern/ssr/serverRender/helmet.js +2 -2
  20. package/dist/js/modern/ssr/serverRender/index.js +1 -1
  21. package/dist/js/modern/ssr/serverRender/styledComponent.js +1 -1
  22. package/dist/js/modern/ssr/utils.js +9 -3
  23. package/dist/js/modern/state/runtime/plugin.js +1 -1
  24. package/dist/js/node/cli/index.js +5 -5
  25. package/dist/js/node/core/app-config.js +22 -0
  26. package/dist/js/node/core/compatible.js +271 -0
  27. package/dist/js/node/core/index.js +111 -0
  28. package/dist/js/node/core/loader/index.js +15 -0
  29. package/dist/js/node/core/loader/loaderManager.js +201 -0
  30. package/dist/js/node/core/loader/useLoader.js +118 -0
  31. package/dist/js/node/core/plugin.js +79 -0
  32. package/dist/js/node/core/runtime-context.js +11 -0
  33. package/dist/js/node/exports/styled.js +5 -5
  34. package/dist/js/node/index.js +10 -10
  35. package/dist/js/node/router/runtime/plugin.js +3 -3
  36. package/dist/js/node/router/runtime/utils.js +3 -1
  37. package/dist/js/node/ssr/index.js +37 -15
  38. package/dist/js/node/ssr/index.node.js +2 -2
  39. package/dist/js/node/ssr/react/withCallback/index.js +27 -0
  40. package/dist/js/node/ssr/serverRender/helmet.js +2 -2
  41. package/dist/js/node/ssr/serverRender/index.js +2 -2
  42. package/dist/js/node/ssr/serverRender/styledComponent.js +2 -2
  43. package/dist/js/node/ssr/utils.js +9 -3
  44. package/dist/js/node/state/runtime/plugin.js +3 -3
  45. package/dist/js/treeshaking/cli/index.js +6 -6
  46. package/dist/js/treeshaking/core/app-config.js +13 -0
  47. package/dist/js/treeshaking/core/compatible.js +297 -0
  48. package/dist/js/treeshaking/core/index.js +7 -0
  49. package/dist/js/treeshaking/core/loader/index.js +1 -0
  50. package/dist/js/treeshaking/core/loader/loaderManager.js +267 -0
  51. package/dist/js/treeshaking/core/loader/useLoader.js +107 -0
  52. package/dist/js/treeshaking/core/plugin.js +105 -0
  53. package/dist/js/treeshaking/core/runtime-context.js +2 -0
  54. package/dist/js/treeshaking/exports/styled.js +2 -2
  55. package/dist/js/treeshaking/index.js +1 -1
  56. package/dist/js/treeshaking/router/runtime/plugin.js +1 -1
  57. package/dist/js/treeshaking/router/runtime/utils.js +3 -1
  58. package/dist/js/treeshaking/ssr/index.js +45 -33
  59. package/dist/js/treeshaking/ssr/index.node.js +1 -1
  60. package/dist/js/treeshaking/ssr/prefetch.js +2 -2
  61. package/dist/js/treeshaking/ssr/react/withCallback/index.js +16 -0
  62. package/dist/js/treeshaking/ssr/serverRender/helmet.js +2 -2
  63. package/dist/js/treeshaking/ssr/serverRender/index.js +1 -1
  64. package/dist/js/treeshaking/ssr/serverRender/styledComponent.js +1 -1
  65. package/dist/js/treeshaking/ssr/utils.js +8 -3
  66. package/dist/js/treeshaking/state/runtime/plugin.js +1 -1
  67. package/dist/types/core/app-config.d.ts +6 -0
  68. package/dist/types/core/compatible.d.ts +17 -0
  69. package/dist/types/core/index.d.ts +9 -0
  70. package/dist/types/core/loader/index.d.ts +2 -0
  71. package/dist/types/core/loader/loaderManager.d.ts +57 -0
  72. package/dist/types/core/loader/useLoader.d.ts +54 -0
  73. package/dist/types/core/plugin.d.ts +215 -0
  74. package/dist/types/core/runtime-context.d.ts +13 -0
  75. package/dist/types/exports/styled.d.ts +2 -2
  76. package/dist/types/index.d.ts +4 -9
  77. package/dist/types/router/runtime/plugin.d.ts +1 -1
  78. package/dist/types/ssr/index.d.ts +2 -2
  79. package/dist/types/ssr/index.node.d.ts +1 -1
  80. package/dist/types/ssr/prefetch.d.ts +2 -2
  81. package/dist/types/ssr/react/nossr/index.d.ts +1 -1
  82. package/dist/types/ssr/react/withCallback/index.d.ts +5 -0
  83. package/dist/types/ssr/serverRender/entry.d.ts +1 -1
  84. package/dist/types/ssr/serverRender/index.d.ts +1 -1
  85. package/dist/types/ssr/serverRender/type.d.ts +1 -1
  86. package/dist/types/state/runtime/plugin.d.ts +2 -2
  87. package/lib/types.d.ts +10 -0
  88. package/package.json +39 -27
package/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # @modern-js/runtime
2
2
 
3
+ ## 1.16.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1100dd58c: chore: support react 18
8
+
9
+ chore: 支持 React 18
10
+
11
+ ### Patch Changes
12
+
13
+ - a480d6ad0: fix: remove helmet regexp's global tag
14
+ fix: 删除 helmet 中正则匹配的全局标记
15
+ - Updated dependencies [641592f52]
16
+ - Updated dependencies [3904b30a5]
17
+ - Updated dependencies [1100dd58c]
18
+ - Updated dependencies [e04e6e76a]
19
+ - Updated dependencies [81c66e4a4]
20
+ - Updated dependencies [2c305b6f5]
21
+ - @modern-js/utils@1.16.0
22
+ - @modern-js/webpack@1.16.0
23
+ - @modern-js/plugin@1.16.0
24
+
25
+ ## 1.15.0
26
+
27
+ ### Patch Changes
28
+
29
+ - 335c97c: fix: fix runtime context format bug
30
+ fix: 修复 runtimeContext 数据格式化时的问题
31
+ - a04a11b: fix: 修复 SSR 物理降级时,获取不到请求上下文的问题
32
+ fix: should get ssrContext anyway if entry is ssr enable
33
+ - Updated dependencies [8658a78]
34
+ - Updated dependencies [0df4970]
35
+ - Updated dependencies [05d4a4f]
36
+ - Updated dependencies [ad05af9]
37
+ - Updated dependencies [5d53d1c]
38
+ - Updated dependencies [37cd159]
39
+ - @modern-js/utils@1.15.0
40
+ - @modern-js/webpack@1.15.0
41
+ - @modern-js/plugin@1.15.0
42
+
43
+ ## 1.5.0
44
+
45
+ ### Minor Changes
46
+
47
+ - 59c941a: chore(runtime): merge `@modern-js/runtime-core` to `@modern-js/runtime`
48
+
49
+ chore(runtime): 合并 `@modern-js/runtime-core` 到 `@modern-js/runtime`
50
+
51
+ ### Patch Changes
52
+
53
+ - e0cd14a: feat: support runtime router and state type
54
+
55
+ feat: 支持在 `modern.config.ts` 中提示 `runtime.router` and `runtime.state` 类型
56
+
57
+ - 287ac8b: fix(runtime): router plugin replace error
58
+
59
+ fix(runtime): router 插件 replace 报错
60
+
61
+ - Updated dependencies [79e83ef]
62
+ - Updated dependencies [5f1a231]
63
+ - Updated dependencies [22f4dca]
64
+ - Updated dependencies [7b9067f]
65
+ - @modern-js/utils@1.9.0
66
+ - @modern-js/webpack@1.12.4
67
+
3
68
  ## 1.4.3
4
69
 
5
70
  ### Patch Changes
@@ -1,5 +1,5 @@
1
1
  import path from 'path';
2
- import { PLUGIN_SCHEMAS, createRuntimeExportsUtils, cleanRequireCache } from '@modern-js/utils';
2
+ import { PLUGIN_SCHEMAS, createRuntimeExportsUtils, cleanRequireCache, isReact18 } from '@modern-js/utils';
3
3
  import PluginState from "../state/cli";
4
4
  import PluginSSR from "../ssr/cli";
5
5
  import PluginRouter from "../router/cli";
@@ -11,8 +11,9 @@ export default (() => ({
11
11
  let runtimeExportsUtils = {};
12
12
  return {
13
13
  config() {
14
- const dir = api.useAppContext().internalDirectory;
14
+ const dir = api.useAppContext().internalDirectory || '';
15
15
  runtimeExportsUtils = createRuntimeExportsUtils(dir, 'index');
16
+ process.env.IS_REACT18 = isReact18(path.join(dir, '../../')).toString();
16
17
  return {
17
18
  runtime: {},
18
19
  runtimeByEntries: {},
@@ -25,10 +26,9 @@ export default (() => ({
25
26
  * But it will not be installed under the user project.
26
27
  * So need to add alias
27
28
  */
28
- 'styled-components': require.resolve('styled-components', {
29
- paths: [require.resolve('@modern-js/runtime-core')]
30
- })
31
- }
29
+ 'styled-components': require.resolve('styled-components')
30
+ },
31
+ envVars: ['IS_REACT18']
32
32
  }
33
33
  };
34
34
  },
@@ -0,0 +1,10 @@
1
+ const APP_CONFIG_SYMBOL = 'config';
2
+ export const getConfig = Component => // eslint-disable-next-line @typescript-eslint/ban-ts-comment
3
+ // @ts-expect-error
4
+ Component[APP_CONFIG_SYMBOL];
5
+ export const defineConfig = (Component, config) => {
6
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
7
+ // @ts-expect-error
8
+ Component[APP_CONFIG_SYMBOL] = config;
9
+ return Component;
10
+ };
@@ -0,0 +1,241 @@
1
+ const _excluded = ["context"];
2
+
3
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
4
+
5
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
6
+
7
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
8
+
9
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
10
+
11
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
12
+
13
+ import React, { useContext, useMemo } from 'react';
14
+ import defaultReactDOM from 'react-dom';
15
+ import hoistNonReactStatics from 'hoist-non-react-statics';
16
+ import { runtime } from "./plugin";
17
+ import { RuntimeReactContext } from "./runtime-context";
18
+ import { createLoaderManager } from "./loader/loaderManager";
19
+ import { jsx as _jsx } from "react/jsx-runtime";
20
+ const IS_REACT18 = process.env.IS_REACT18 === 'true';
21
+
22
+ function isClientArgs(id) {
23
+ return typeof id === 'string' || typeof HTMLElement !== 'undefined' && id instanceof HTMLElement;
24
+ }
25
+
26
+ const runnerMap = new WeakMap();
27
+
28
+ const getInitialContext = runner => ({
29
+ loaderManager: createLoaderManager({}),
30
+ runner,
31
+ isBrowser: true
32
+ });
33
+
34
+ export const createApp = ({
35
+ plugins
36
+ }) => {
37
+ const appRuntime = runtime.clone();
38
+ appRuntime.usePlugin(...plugins);
39
+ return App => {
40
+ const runner = appRuntime.init();
41
+
42
+ const WrapperComponent = props => {
43
+ const element = /*#__PURE__*/React.createElement(App || React.Fragment, _objectSpread({}, props), props.children);
44
+ const context = useContext(RuntimeReactContext);
45
+ return runner.provide({
46
+ element,
47
+ props: _objectSpread({}, props),
48
+ context
49
+ }, {
50
+ onLast: ({
51
+ element
52
+ }) => element
53
+ });
54
+ };
55
+
56
+ if (App) {
57
+ hoistNonReactStatics(WrapperComponent, App);
58
+ }
59
+
60
+ const HOCApp = runner.hoc({
61
+ App: WrapperComponent
62
+ }, {
63
+ onLast: ({
64
+ App
65
+ }) => {
66
+ const WrapComponent = _ref => {
67
+ var _contextValue;
68
+
69
+ let {
70
+ context
71
+ } = _ref,
72
+ props = _objectWithoutProperties(_ref, _excluded);
73
+
74
+ let contextValue = context; // We should construct the context, when root component is not passed into `bootstrap`.
75
+
76
+ if (!((_contextValue = contextValue) !== null && _contextValue !== void 0 && _contextValue.runner)) {
77
+ contextValue = getInitialContext(runner);
78
+ runner.init({
79
+ context: contextValue
80
+ }, {
81
+ onLast: ({
82
+ context: context1
83
+ }) => {
84
+ var _App$init;
85
+
86
+ return App === null || App === void 0 ? void 0 : (_App$init = App.init) === null || _App$init === void 0 ? void 0 : _App$init.call(App, context1);
87
+ }
88
+ });
89
+ }
90
+
91
+ return /*#__PURE__*/_jsx(RuntimeReactContext.Provider, {
92
+ value: contextValue,
93
+ children: /*#__PURE__*/_jsx(App, _objectSpread({}, props))
94
+ });
95
+ };
96
+
97
+ return hoistNonReactStatics(WrapComponent, App);
98
+ }
99
+ });
100
+ runnerMap.set(HOCApp, runner);
101
+ return HOCApp;
102
+ };
103
+ };
104
+ export const bootstrap = async (BootApp,
105
+ /**
106
+ * When csr, id is root id.
107
+ * When ssr, id is serverContext
108
+ */
109
+ id,
110
+ /**
111
+ * root.render need use root to run function
112
+ */
113
+ root, render = defaultReactDOM.render, hydrate = defaultReactDOM.hydrate) => {
114
+ let App = BootApp;
115
+ let runner = runnerMap.get(App); // ensure Component used is created by `createApp`
116
+
117
+ if (!runner) {
118
+ App = createApp({
119
+ plugins: []
120
+ })(App);
121
+ runner = runnerMap.get(App);
122
+ }
123
+
124
+ const context = getInitialContext(runner);
125
+
126
+ const runInit = _context => runner.init({
127
+ context: _context
128
+ }, {
129
+ onLast: ({
130
+ context: context1
131
+ }) => {
132
+ var _App, _App$init2;
133
+
134
+ return (_App = App) === null || _App === void 0 ? void 0 : (_App$init2 = _App.init) === null || _App$init2 === void 0 ? void 0 : _App$init2.call(_App, context1);
135
+ }
136
+ }); // don't mount the App, let user in charge of it.
137
+
138
+
139
+ if (!id) {
140
+ return /*#__PURE__*/React.createElement(App, {
141
+ context
142
+ });
143
+ }
144
+
145
+ const isBrowser = typeof window !== 'undefined' && window.name !== 'nodejs';
146
+
147
+ if (isBrowser) {
148
+ if (isClientArgs(id)) {
149
+ var _ssrData$data, _ssrData$data2;
150
+
151
+ const ssrData = window._SSR_DATA;
152
+ const loadersData = (ssrData === null || ssrData === void 0 ? void 0 : (_ssrData$data = ssrData.data) === null || _ssrData$data === void 0 ? void 0 : _ssrData$data.loadersData) || {};
153
+ const initialLoadersState = Object.keys(loadersData).reduce((res, key) => {
154
+ const loaderData = loadersData[key];
155
+
156
+ if (loaderData.loading !== false) {
157
+ return res;
158
+ }
159
+
160
+ res[key] = loaderData;
161
+ return res;
162
+ }, {});
163
+ Object.assign(context, _objectSpread({
164
+ loaderManager: createLoaderManager(initialLoadersState, {
165
+ skipStatic: true
166
+ })
167
+ }, ssrData ? {
168
+ ssrContext: ssrData === null || ssrData === void 0 ? void 0 : ssrData.context
169
+ } : {}));
170
+ context.initialData = ssrData === null || ssrData === void 0 ? void 0 : (_ssrData$data2 = ssrData.data) === null || _ssrData$data2 === void 0 ? void 0 : _ssrData$data2.initialData;
171
+ const initialData = await runInit(context);
172
+
173
+ if (initialData) {
174
+ context.initialData = initialData;
175
+ }
176
+
177
+ const rootElement = typeof id !== 'string' ? id : document.getElementById(id || 'root'); // https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html
178
+
179
+ const ModernRender = App => {
180
+ if (IS_REACT18) {
181
+ root.render(App);
182
+ } else {
183
+ render(App, rootElement);
184
+ }
185
+ };
186
+
187
+ const ModernHydrate = (App, callback) => {
188
+ if (IS_REACT18) {
189
+ hydrate(rootElement, App);
190
+ } else {
191
+ hydrate(App, rootElement, callback);
192
+ }
193
+ };
194
+
195
+ return runner.client({
196
+ App,
197
+ context,
198
+ ModernRender,
199
+ ModernHydrate
200
+ }, {
201
+ onLast: ({
202
+ App
203
+ }) => {
204
+ ModernRender( /*#__PURE__*/React.createElement(App, {
205
+ context
206
+ }));
207
+ }
208
+ });
209
+ } else {
210
+ throw Error('`bootstrap` needs id in browser environment, it needs to be string or element');
211
+ }
212
+ } else {
213
+ Object.assign(context, {
214
+ ssrContext: id,
215
+ isBrowser: false,
216
+ loaderManager: createLoaderManager({}, {
217
+ skipNonStatic: id.staticGenerate,
218
+ // if not static generate, only non-static loader can exec on prod env
219
+ skipStatic: process.env.NODE_ENV === 'production' && !id.staticGenerate
220
+ })
221
+ });
222
+ const initialData = await runInit(context);
223
+ context.initialData = initialData;
224
+ return runner.server({
225
+ App,
226
+ context
227
+ });
228
+ }
229
+ };
230
+ export const useRuntimeContext = () => {
231
+ const context = useContext(RuntimeReactContext);
232
+ const memoizedContext = useMemo(() => context.runner.pickContext({
233
+ context,
234
+ pickedContext: {}
235
+ }, {
236
+ onLast: ({
237
+ pickedContext
238
+ }) => pickedContext
239
+ }), [context]);
240
+ return memoizedContext;
241
+ };
@@ -0,0 +1,7 @@
1
+ export { createPlugin, createRuntime, runtime, registerInit, registerPrefetch } from "./plugin";
2
+ export { defineConfig, getConfig } from "./app-config";
3
+ // compatible
4
+ export * from "./compatible";
5
+ export { RuntimeReactContext } from "./runtime-context";
6
+ export * from "./loader";
7
+ export * from '@modern-js/plugin';
@@ -0,0 +1 @@
1
+ export { default as useLoader } from "./useLoader";
@@ -0,0 +1,189 @@
1
+ import invariant from 'invariant';
2
+
3
+ /**
4
+ * Calc id from string or object
5
+ */
6
+ const createGetId = () => {
7
+ const idCache = new Map();
8
+ return objectId => {
9
+ const cachedId = idCache.get(objectId);
10
+
11
+ if (cachedId) {
12
+ return cachedId;
13
+ } // WARNING: id should be unique after serialize.
14
+
15
+
16
+ const id = JSON.stringify(objectId);
17
+ invariant(id, 'params should be not null value');
18
+ idCache.set(objectId, id);
19
+ return id;
20
+ };
21
+ };
22
+
23
+ export let LoaderStatus;
24
+
25
+ (function (LoaderStatus) {
26
+ LoaderStatus[LoaderStatus["idle"] = 0] = "idle";
27
+ LoaderStatus[LoaderStatus["loading"] = 1] = "loading";
28
+ LoaderStatus[LoaderStatus["fulfilled"] = 2] = "fulfilled";
29
+ LoaderStatus[LoaderStatus["rejected"] = 3] = "rejected";
30
+ })(LoaderStatus || (LoaderStatus = {}));
31
+
32
+ const createLoader = (id, initialData = {
33
+ loading: false,
34
+ reloading: false,
35
+ data: undefined,
36
+ error: undefined
37
+ }, loaderFn, skip = false) => {
38
+ let promise;
39
+ let status = LoaderStatus.idle;
40
+ let {
41
+ data,
42
+ error
43
+ } = initialData;
44
+ let hasLoaded = false;
45
+ const handlers = new Set();
46
+
47
+ const load = async () => {
48
+ if (skip) {
49
+ return promise;
50
+ }
51
+
52
+ if (status === LoaderStatus.loading) {
53
+ return promise;
54
+ }
55
+
56
+ status = LoaderStatus.loading;
57
+ notify();
58
+ promise = loaderFn().then(value => {
59
+ data = value;
60
+ error = null;
61
+ status = LoaderStatus.fulfilled;
62
+ }).catch(e => {
63
+ error = e;
64
+ data = null;
65
+ status = LoaderStatus.rejected;
66
+ }).finally(() => {
67
+ promise = null;
68
+ hasLoaded = true;
69
+ notify();
70
+ });
71
+ return promise;
72
+ };
73
+
74
+ const getResult = () => ({
75
+ loading: !hasLoaded && status === LoaderStatus.loading,
76
+ reloading: hasLoaded && status === LoaderStatus.loading,
77
+ data,
78
+ error: error instanceof Error ? `${error.message}` : error,
79
+ // redundant fields for ssr log
80
+ _error: error
81
+ });
82
+
83
+ const notify = () => {
84
+ // don't iterate handlers directly, since it could be modified during iteration
85
+ [...handlers].forEach(handler => {
86
+ handler(status, getResult());
87
+ });
88
+ };
89
+
90
+ const onChange = handler => {
91
+ handlers.add(handler);
92
+ return () => {
93
+ handlers.delete(handler);
94
+ };
95
+ };
96
+
97
+ return {
98
+ get result() {
99
+ return getResult();
100
+ },
101
+
102
+ get promise() {
103
+ return promise;
104
+ },
105
+
106
+ onChange,
107
+ load
108
+ };
109
+ };
110
+
111
+ /**
112
+ * Create loaders manager. It's returned instance will add to context
113
+ * @param initialDataMap used to initialing loader data
114
+ */
115
+ export const createLoaderManager = (initialDataMap, managerOptions = {}) => {
116
+ const {
117
+ skipStatic = false,
118
+ skipNonStatic = false
119
+ } = managerOptions;
120
+ const loadersMap = new Map();
121
+ const getId = createGetId();
122
+
123
+ const add = (loaderFn, loaderOptions) => {
124
+ const id = getId(loaderOptions.params);
125
+ let loader = loadersMap.get(id); // private property for opting out loader cache, maybe change in future
126
+
127
+ const cache = loaderOptions._cache;
128
+
129
+ if (!loader || cache === false) {
130
+ // ignore non-static loader on static phase
131
+ const ignoreNonStatic = skipNonStatic && !loaderOptions.static; // ignore static loader on non-static phase
132
+
133
+ const ignoreStatic = skipStatic && loaderOptions.static;
134
+ const skipExec = ignoreNonStatic || ignoreStatic;
135
+ loader = createLoader(id, typeof initialDataMap[id] !== 'undefined' ? initialDataMap[id] : {
136
+ data: loaderOptions.initialData
137
+ }, loaderFn, // Todo whether static loader is exec when CSR
138
+ skipExec);
139
+ loadersMap.set(id, loader);
140
+ }
141
+
142
+ return id;
143
+ };
144
+
145
+ const get = id => loadersMap.get(id); // check if there has pending loaders
146
+
147
+
148
+ const hasPendingLoaders = () => {
149
+ for (const loader of loadersMap.values()) {
150
+ const {
151
+ promise
152
+ } = loader;
153
+
154
+ if (promise instanceof Promise) {
155
+ return true;
156
+ }
157
+ }
158
+
159
+ return false;
160
+ }; // waiting for all pending loaders to be settled
161
+
162
+
163
+ const awaitPendingLoaders = async () => {
164
+ const pendingLoaders = [];
165
+
166
+ for (const [id, loader] of loadersMap) {
167
+ const {
168
+ promise
169
+ } = loader;
170
+
171
+ if (promise instanceof Promise) {
172
+ pendingLoaders.push([id, loader]);
173
+ }
174
+ }
175
+
176
+ await Promise.all(pendingLoaders.map(item => item[1].promise));
177
+ return pendingLoaders.reduce((res, [id, loader]) => {
178
+ res[id] = loader.result;
179
+ return res;
180
+ }, {});
181
+ };
182
+
183
+ return {
184
+ hasPendingLoaders,
185
+ awaitPendingLoaders,
186
+ add,
187
+ get
188
+ };
189
+ };
@@ -0,0 +1,105 @@
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
2
+
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
+
5
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
+
7
+ import { useContext, useRef, useMemo, useState, useCallback, useEffect } from 'react';
8
+ import invariant from 'invariant';
9
+ import { RuntimeReactContext } from "../runtime-context";
10
+ import { LoaderStatus } from "./loaderManager";
11
+
12
+ const useLoader = (loaderFn, options = {
13
+ params: undefined
14
+ }) => {
15
+ const context = useContext(RuntimeReactContext);
16
+ const isSSRRender = Boolean(context.ssr);
17
+ const {
18
+ loaderManager
19
+ } = context;
20
+ const loaderRef = useRef();
21
+ const unlistenLoaderChangeRef = useRef(null); // SSR render should ignore `_cache` prop
22
+
23
+ if (isSSRRender && Object.prototype.hasOwnProperty.call(options, '_cache')) {
24
+ delete options._cache;
25
+ }
26
+
27
+ const load = useCallback(params => {
28
+ var _unlistenLoaderChange, _window, _window$_SSR_DATA, _window$_SSR_DATA$dat, _window$_SSR_DATA$dat2, _loaderRef$current2;
29
+
30
+ if (typeof params === 'undefined') {
31
+ var _loaderRef$current;
32
+
33
+ return (_loaderRef$current = loaderRef.current) === null || _loaderRef$current === void 0 ? void 0 : _loaderRef$current.load();
34
+ }
35
+
36
+ const id = loaderManager.add(() => {
37
+ try {
38
+ const res = loaderFn(context, params);
39
+
40
+ if (res instanceof Promise) {
41
+ return res;
42
+ }
43
+
44
+ return Promise.resolve(res);
45
+ } catch (e) {
46
+ return Promise.reject(e);
47
+ }
48
+ }, _objectSpread(_objectSpread({}, options), {}, {
49
+ params
50
+ }));
51
+ loaderRef.current = loaderManager.get(id); // unsubscribe old loader onChange event
52
+
53
+ (_unlistenLoaderChange = unlistenLoaderChangeRef.current) === null || _unlistenLoaderChange === void 0 ? void 0 : _unlistenLoaderChange.call(unlistenLoaderChangeRef);
54
+
55
+ if (isSSRRender) {
56
+ return undefined;
57
+ } // skip this loader, then try to unlisten loader change
58
+
59
+
60
+ if (options.skip) {
61
+ return undefined;
62
+ } // do not load data again in CSR hydrate stage if SSR data exists
63
+
64
+
65
+ if (context._hydration && ((_window = window) === null || _window === void 0 ? void 0 : (_window$_SSR_DATA = _window._SSR_DATA) === null || _window$_SSR_DATA === void 0 ? void 0 : (_window$_SSR_DATA$dat = _window$_SSR_DATA.data) === null || _window$_SSR_DATA$dat === void 0 ? void 0 : (_window$_SSR_DATA$dat2 = _window$_SSR_DATA$dat.loadersData[id]) === null || _window$_SSR_DATA$dat2 === void 0 ? void 0 : _window$_SSR_DATA$dat2.error) === null) {
66
+ return undefined;
67
+ }
68
+
69
+ const res = loaderRef.current.load();
70
+ unlistenLoaderChangeRef.current = (_loaderRef$current2 = loaderRef.current) === null || _loaderRef$current2 === void 0 ? void 0 : _loaderRef$current2.onChange((_status, _result) => {
71
+ setResult(_result);
72
+
73
+ if (_status === LoaderStatus.fulfilled) {
74
+ var _options$onSuccess;
75
+
76
+ options === null || options === void 0 ? void 0 : (_options$onSuccess = options.onSuccess) === null || _options$onSuccess === void 0 ? void 0 : _options$onSuccess.call(options, _result.data);
77
+ }
78
+
79
+ if (_status === LoaderStatus.rejected) {
80
+ var _options$onError;
81
+
82
+ options === null || options === void 0 ? void 0 : (_options$onError = options.onError) === null || _options$onError === void 0 ? void 0 : _options$onError.call(options, _result.error);
83
+ }
84
+ });
85
+ return res;
86
+ }, [options.skip]);
87
+ useEffect(() => () => {
88
+ var _unlistenLoaderChange2;
89
+
90
+ (_unlistenLoaderChange2 = unlistenLoaderChangeRef.current) === null || _unlistenLoaderChange2 === void 0 ? void 0 : _unlistenLoaderChange2.call(unlistenLoaderChangeRef);
91
+ }, []);
92
+ useMemo(() => {
93
+ var _options$params;
94
+
95
+ const p = (_options$params = options.params) !== null && _options$params !== void 0 ? _options$params : loaderFn.id;
96
+ invariant(typeof p !== 'undefined' && p !== null, 'Params is required in useLoader');
97
+ load(p);
98
+ }, [options.params]);
99
+ const [result, setResult] = useState(loaderRef.current.result);
100
+ return _objectSpread(_objectSpread({}, result), {}, {
101
+ reload: load
102
+ });
103
+ };
104
+
105
+ export default useLoader;