@shuvi/platform-web 1.0.0-rc.4 → 1.0.0-rc.7

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 (77) hide show
  1. package/esm/shared/appTypes.d.ts +4 -2
  2. package/esm/shared/renderTypes.d.ts +6 -5
  3. package/esm/shared/routeTypes.d.ts +4 -9
  4. package/esm/shuvi-app/app/client.js +11 -16
  5. package/esm/shuvi-app/app/server.js +10 -9
  6. package/esm/shuvi-app/dev/hotDevClient.d.ts +0 -1
  7. package/esm/shuvi-app/dev/hotDevClient.js +30 -51
  8. package/esm/shuvi-app/dev/websocket.d.ts +0 -1
  9. package/esm/shuvi-app/helper/serializeServerError.d.ts +2 -0
  10. package/esm/shuvi-app/helper/serializeServerError.js +21 -0
  11. package/esm/shuvi-app/react/AppContainer.d.ts +2 -3
  12. package/esm/shuvi-app/react/AppContainer.jsx +3 -4
  13. package/esm/shuvi-app/react/getRoutes.js +5 -3
  14. package/esm/shuvi-app/react/{redox-react → model}/RedoxWrapper.d.ts +3 -3
  15. package/esm/shuvi-app/react/{redox-react → model}/RedoxWrapper.jsx +3 -3
  16. package/esm/shuvi-app/react/model/runtime.d.ts +8 -0
  17. package/esm/shuvi-app/react/{redox-react → model}/runtime.js +6 -3
  18. package/esm/shuvi-app/react/store.d.ts +5 -0
  19. package/esm/shuvi-app/react/store.js +3 -0
  20. package/esm/shuvi-app/react/types.d.ts +0 -7
  21. package/esm/shuvi-app/react/useLoaderData.js +9 -20
  22. package/esm/shuvi-app/react/view/ReactView.client.jsx +25 -4
  23. package/esm/shuvi-app/react/view/ReactView.server.jsx +17 -14
  24. package/esm/shuvi-app/shuvi-runtime-index.d.ts +3 -3
  25. package/lib/node/features/custom-server/index.d.ts +1 -1
  26. package/lib/node/features/custom-server/server.d.ts +1 -1
  27. package/lib/node/features/filesystem-routes/api/apiRouteHandler.d.ts +7 -7
  28. package/lib/node/features/filesystem-routes/api/apiRouteHandler.js +0 -4
  29. package/lib/node/features/filesystem-routes/api/middleware.d.ts +2 -2
  30. package/lib/node/features/filesystem-routes/index.d.ts +1 -13
  31. package/lib/node/features/filesystem-routes/index.js +3 -41
  32. package/lib/node/features/filesystem-routes/middleware/middleware.d.ts +2 -2
  33. package/lib/node/features/filesystem-routes/page/routes.js +1 -1
  34. package/lib/node/features/html-render/index.js +1 -1
  35. package/lib/node/features/html-render/lib/getPageMiddleware.d.ts +2 -2
  36. package/lib/node/features/html-render/lib/index.d.ts +0 -1
  37. package/lib/node/features/html-render/lib/index.js +1 -3
  38. package/lib/node/features/html-render/lib/renderToHTML.d.ts +2 -2
  39. package/lib/node/features/html-render/lib/renderToHTML.js +7 -48
  40. package/lib/node/features/html-render/lib/renderer/base.d.ts +6 -6
  41. package/lib/node/features/html-render/lib/renderer/base.js +5 -5
  42. package/lib/node/features/html-render/lib/renderer/index.d.ts +5 -4
  43. package/lib/node/features/html-render/lib/renderer/index.js +69 -6
  44. package/lib/node/features/html-render/lib/renderer/spa.d.ts +2 -2
  45. package/lib/node/features/html-render/lib/renderer/spa.js +4 -6
  46. package/lib/node/features/html-render/lib/renderer/ssr.d.ts +2 -2
  47. package/lib/node/features/html-render/lib/renderer/ssr.js +5 -6
  48. package/lib/node/features/html-render/lib/renderer/types.d.ts +8 -5
  49. package/lib/node/features/html-render/server.d.ts +1 -1
  50. package/lib/node/features/index.js +1 -3
  51. package/lib/node/features/model/index.d.ts +1 -13
  52. package/lib/node/features/model/runtime.d.ts +3 -3
  53. package/lib/node/features/model/runtime.js +2 -0
  54. package/lib/node/features/model/shuvi-app.d.ts +2 -2
  55. package/lib/node/features/on-demand-compile-page/index.d.ts +1 -13
  56. package/lib/node/features/on-demand-compile-page/onDemandRouteManager.d.ts +3 -3
  57. package/lib/node/paths.js +0 -2
  58. package/lib/node/shuvi-runtime-server.d.ts +18 -0
  59. package/lib/node/shuvi-runtime-server.js +2 -0
  60. package/lib/node/shuvi-type-extensions-node.d.ts +0 -6
  61. package/lib/node/targets/react/bundler/index.d.ts +1 -13
  62. package/lib/node/targets/react/index.d.ts +2 -26
  63. package/lib/node/targets/react/index.js +2 -2
  64. package/lib/node/targets/react/model/index.d.ts +6 -0
  65. package/lib/node/targets/react/{redox-react → model}/index.js +7 -6
  66. package/lib/shared/appTypes.d.ts +4 -2
  67. package/lib/shared/renderTypes.d.ts +6 -5
  68. package/lib/shared/routeTypes.d.ts +4 -9
  69. package/package.json +14 -14
  70. package/esm/shuvi-app/react/redox-react/runtime.d.ts +0 -8
  71. package/esm/shuvi-app/shuvi-runtime-server.d.ts +0 -6
  72. package/esm/shuvi-app/shuvi-runtime-server.js +0 -1
  73. package/lib/node/features/webpack-watch-wait-for-file-builder/index.d.ts +0 -16
  74. package/lib/node/features/webpack-watch-wait-for-file-builder/index.js +0 -25
  75. package/lib/node/features/webpack-watch-wait-for-file-builder/webpack-watch-wait-for-file-builder-plugin.d.ts +0 -12
  76. package/lib/node/features/webpack-watch-wait-for-file-builder/webpack-watch-wait-for-file-builder-plugin.js +0 -32
  77. package/lib/node/targets/react/redox-react/index.d.ts +0 -18
@@ -1,9 +1,11 @@
1
- import { IRequest, IPageRouteRecord, IAppData, IAppState } from '@shuvi/platform-shared/shared';
1
+ import { IPageRouteRecord, IAppData, IAppState } from '@shuvi/platform-shared/shared';
2
2
  import { Application } from '@shuvi/platform-shared/shuvi-app/application';
3
+ import type { ShuviRequest } from '@shuvi/service';
3
4
  export interface CreateAppServer {
4
5
  (options: {
5
- req: IRequest;
6
+ req: ShuviRequest;
6
7
  ssr: boolean;
8
+ isDev: boolean;
7
9
  }): Application;
8
10
  }
9
11
  export interface CreateAppClient {
@@ -1,10 +1,10 @@
1
1
  import { IManifest } from '@shuvi/toolpack/lib/webpack/types';
2
- import { Response, IApplication, IRequest, IAppData } from '@shuvi/platform-shared/shared';
3
- export declare type IRenderDocumentOptions = {
2
+ import type { ShuviRequest } from '@shuvi/service';
3
+ import { Response, IApplication, IAppData } from '@shuvi/platform-shared/shared';
4
+ export declare type IRenderViewOptions = {
4
5
  app: IApplication;
5
- req?: IRequest;
6
6
  };
7
- export interface IRenderOptions extends IRenderDocumentOptions {
7
+ export interface IRenderOptions extends IRenderViewOptions {
8
8
  }
9
9
  export interface IView<RenderOption extends IRenderOptions = any, RenderResult = void> {
10
10
  renderApp(options: RenderOption): RenderResult;
@@ -35,8 +35,9 @@ export interface IClientRendererOptions<ExtraAppData = {}> extends IRenderOption
35
35
  appData: IAppData<ExtraAppData>;
36
36
  }
37
37
  export interface IServerRendererOptions extends IRenderOptions {
38
+ req: ShuviRequest;
38
39
  manifest: IManifest;
39
- getAssetPublicUrl(path: string): string;
40
+ isDev?: boolean;
40
41
  }
41
42
  export interface IViewClient<ExtraAppData = {}> extends IView<IClientRendererOptions<ExtraAppData>> {
42
43
  }
@@ -1,10 +1,5 @@
1
- import { IURLParams, IURLQuery } from '@shuvi/platform-shared/shared';
2
- import { IRequestHandlerWithNext } from '@shuvi/service';
3
- import { IResponse, IRequest } from '@shuvi/service';
1
+ import { ShuviRequest, ShuviResponse, ShuviRequestHandler } from '@shuvi/service';
4
2
  export interface IApiReq {
5
- pathname: string;
6
- query: IURLQuery;
7
- params: IURLParams;
8
3
  cookies: {
9
4
  [key: string]: string;
10
5
  };
@@ -12,7 +7,7 @@ export interface IApiReq {
12
7
  [key: string]: any;
13
8
  };
14
9
  }
15
- export declare type IApiRequest = IRequest & IApiReq;
10
+ export declare type IApiRequest = ShuviRequest & IApiReq;
16
11
  export declare type Send<T> = (body: T) => void;
17
12
  export declare type IApiRes<T = any> = {
18
13
  send: Send<T>;
@@ -21,7 +16,7 @@ export declare type IApiRes<T = any> = {
21
16
  redirect(url: string): IApiRes<T>;
22
17
  redirect(status: number, url: string): IApiRes<T>;
23
18
  };
24
- export declare type IApiResponse<T = any> = IResponse & IApiRes<T>;
19
+ export declare type IApiResponse<T = any> = ShuviResponse & IApiRes<T>;
25
20
  export declare type IApiRequestHandler<T = any> = (req: IApiRequest, res: IApiResponse<T>) => void | Promise<void>;
26
21
  export interface IApiConfig {
27
22
  api?: {
@@ -35,7 +30,7 @@ export interface IApiHandler {
35
30
  config?: IApiConfig;
36
31
  }
37
32
  export interface IMiddlewareConfig {
38
- default: IRequestHandlerWithNext;
33
+ default: ShuviRequestHandler;
39
34
  }
40
35
  export declare type IApiRoutes = {
41
36
  path: string;
@@ -8,12 +8,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { getRoutes } from '@shuvi/app/core/platform';
11
- import { runPreload, runLoaders, getRouteMatchesWithInvalidLoader, getLoaderManager, isRedirect, isResponse } from '@shuvi/platform-shared/shared';
11
+ import { runPreload, runLoaders, getRouteMatchesWithInvalidLoader, isRedirect, isResponse } from '@shuvi/platform-shared/shared';
12
12
  import application, { Application } from '@shuvi/platform-shared/shuvi-app/application';
13
13
  import { createRouter, createBrowserHistory, createHashHistory } from '@shuvi/router';
14
14
  import pageLoaders from '@shuvi/app/files/page-loaders';
15
15
  import { historyMode } from '@shuvi/app/files/routerConfig';
16
16
  import { SHUVI_ERROR } from '@shuvi/shared/lib/constants';
17
+ import { serializeServerError } from '../helper/serializeServerError';
17
18
  let app;
18
19
  export { Application };
19
20
  export const createApp = ({ routes, appData, appComponent }) => {
@@ -21,7 +22,7 @@ export const createApp = ({ routes, appData, appComponent }) => {
21
22
  if (app) {
22
23
  return app;
23
24
  }
24
- const { loadersData = {}, appState, ssr } = appData;
25
+ const { appState, ssr } = appData;
25
26
  let history;
26
27
  if (historyMode === 'hash') {
27
28
  history = createHashHistory();
@@ -38,14 +39,14 @@ export const createApp = ({ routes, appData, appComponent }) => {
38
39
  AppComponent: appComponent,
39
40
  router
40
41
  });
42
+ const loadersData = app.getLoadersData();
41
43
  const hasHydrateData = Object.keys(loadersData).length > 0;
42
- const loaderManager = getLoaderManager();
43
44
  let shouldHydrate = ssr && hasHydrateData;
44
- let hasServerError = app.error.hasError;
45
+ let hasServerError = !!app.error;
45
46
  router.beforeResolve((to, from, next) => __awaiter(void 0, void 0, void 0, function* () {
46
47
  if (shouldHydrate) {
47
48
  shouldHydrate = false;
48
- loaderManager.setDatas(loadersData);
49
+ app.setLoadersData(loadersData);
49
50
  return next();
50
51
  }
51
52
  if (hasServerError) {
@@ -53,12 +54,11 @@ export const createApp = ({ routes, appData, appComponent }) => {
53
54
  return next();
54
55
  }
55
56
  if (!to.matches.length) {
56
- app.error.error(SHUVI_ERROR.PAGE_NOT_FOUND);
57
+ app.setError(SHUVI_ERROR.PAGE_NOT_FOUND);
57
58
  next();
58
59
  return;
59
60
  }
60
61
  const matches = getRouteMatchesWithInvalidLoader(to, from, pageLoaders);
61
- let isPreloadError = false;
62
62
  try {
63
63
  const loaderDatas = yield new Promise((resolve, reject) => {
64
64
  let value;
@@ -79,11 +79,9 @@ export const createApp = ({ routes, appData, appComponent }) => {
79
79
  runPreload(to)
80
80
  .then(tryResolve)
81
81
  .catch(err => {
82
- isPreloadError = true;
83
82
  reject(err);
84
83
  });
85
84
  runLoaders(matches, pageLoaders, {
86
- isServer: false,
87
85
  query: to.query,
88
86
  getAppContext: () => app.context
89
87
  })
@@ -96,7 +94,7 @@ export const createApp = ({ routes, appData, appComponent }) => {
96
94
  tryResolve();
97
95
  });
98
96
  });
99
- loaderManager.setDatas(loaderDatas);
97
+ app.setLoadersData(loaderDatas);
100
98
  }
101
99
  catch (error) {
102
100
  if (isRedirect(error)) {
@@ -104,22 +102,19 @@ export const createApp = ({ routes, appData, appComponent }) => {
104
102
  return;
105
103
  }
106
104
  if (isResponse(error) && error.status >= 400 && error.status < 600) {
107
- app.error.error({
105
+ app.setError({
108
106
  code: error.status,
109
107
  message: error.data
110
108
  });
111
109
  next();
112
110
  return;
113
111
  }
114
- app.error.error({
115
- code: SHUVI_ERROR.APP_ERROR.code,
116
- message: error.message || isPreloadError ? 'Preload Error' : 'Loader Error'
117
- });
112
+ app.setError(serializeServerError(error, process.env.NODE_ENV === 'development'));
118
113
  next();
119
114
  return;
120
115
  }
121
116
  next(() => {
122
- app.error.clear();
117
+ app.clearError();
123
118
  });
124
119
  }));
125
120
  return app;
@@ -9,12 +9,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import routes from '@shuvi/app/files/routes';
11
11
  import { getRoutes, app as AppComponent } from '@shuvi/app/core/platform';
12
- import { runLoaders, getRouteMatchesWithInvalidLoader, isResponse, isRedirect, getLoaderManager } from '@shuvi/platform-shared/shared';
12
+ import { runLoaders, getRouteMatchesWithInvalidLoader, isResponse, isRedirect } from '@shuvi/platform-shared/shared';
13
13
  import pageLoaders from '@shuvi/app/files/page-loaders';
14
14
  import application from '@shuvi/platform-shared/shuvi-app/application';
15
15
  import { createRouter, createMemoryHistory } from '@shuvi/router';
16
+ import chalk from '@shuvi/utils/lib/chalk';
17
+ import { serializeServerError } from '../helper/serializeServerError';
16
18
  export const createApp = options => {
17
- const { req, ssr } = options;
19
+ const { req, ssr, isDev } = options;
18
20
  const history = createMemoryHistory({
19
21
  initialEntries: [(req && req.url) || '/'],
20
22
  initialIndex: 0
@@ -24,18 +26,16 @@ export const createApp = options => {
24
26
  routes: getRoutes(routes)
25
27
  });
26
28
  let app;
27
- const loaderManager = getLoaderManager();
28
29
  if (ssr) {
29
30
  router.beforeResolve((to, from, next) => __awaiter(void 0, void 0, void 0, function* () {
30
31
  const matches = getRouteMatchesWithInvalidLoader(to, from, pageLoaders);
31
32
  try {
32
33
  const loaderResult = yield runLoaders(matches, pageLoaders, {
33
- isServer: true,
34
34
  req,
35
35
  query: to.query,
36
36
  getAppContext: () => app.context
37
37
  });
38
- loaderManager.setDatas(loaderResult);
38
+ app.setLoadersData(loaderResult);
39
39
  }
40
40
  catch (error) {
41
41
  if (isRedirect(error)) {
@@ -43,16 +43,17 @@ export const createApp = options => {
43
43
  return;
44
44
  }
45
45
  if (isResponse(error) && error.status >= 400 && error.status < 600) {
46
- app.error.error({
46
+ app.setError({
47
47
  code: error.status,
48
48
  message: error.data
49
49
  });
50
50
  next();
51
51
  return;
52
52
  }
53
- app.error.error({
54
- message: error.message || 'Loader Error'
55
- });
53
+ if (isDev) {
54
+ console.error(chalk.red('error') + ' - ' + error.stack);
55
+ }
56
+ app.setError(serializeServerError(error, isDev));
56
57
  next();
57
58
  return;
58
59
  }
@@ -24,7 +24,6 @@ SOFTWARE.
24
24
  export declare type HotDevClient = {
25
25
  sendMessage: (data: any) => void;
26
26
  subscribeToHmrEvent: (handler: any) => void;
27
- reportRuntimeError: (err: any) => void;
28
27
  };
29
28
  export default function connect(options: {
30
29
  launchEditorEndpoint: string;
@@ -34,9 +34,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
34
34
  });
35
35
  };
36
36
  // @ts-nocheck
37
- import * as ErrorOverlay from 'react-error-overlay';
38
37
  import stripAnsi from 'strip-ansi';
39
38
  import formatWebpackMessages from '@shuvi/toolpack/lib/utils/formatWebpackMessages';
39
+ import { startReportingRuntimeErrors, stopReportingRuntimeErrors, onBuildError, onBuildOk, onRefresh } from '@shuvi/error-overlay';
40
40
  import { DEV_SOCKET_TIMEOUT_MS } from '@shuvi/shared/esm/constants';
41
41
  import { connectHMR, addMessageListener, sendMessage } from './websocket';
42
42
  // This alternative WebpackDevServer combines the functionality of:
@@ -52,33 +52,14 @@ import { connectHMR, addMessageListener, sendMessage } from './websocket';
52
52
  let hadRuntimeError = false;
53
53
  let customHmrEventHandler;
54
54
  export default function connect(options) {
55
- // Open stack traces in an editor.
56
- ErrorOverlay.setEditorHandler(function editorHandler({ fileName, lineNumber, colNumber }) {
57
- // Resolve invalid paths coming from react-error-overlay
58
- const resolvedFilename = fileName.replace(/^webpack:\/\/[^/]+/ /* webpack://namaspcae/resourcepath */, '');
59
- fetch(options.launchEditorEndpoint +
60
- '?fileName=' +
61
- window.encodeURIComponent(resolvedFilename) +
62
- '&lineNumber=' +
63
- window.encodeURIComponent(lineNumber || 1) +
64
- '&colNumber=' +
65
- window.encodeURIComponent(colNumber || 1));
66
- });
67
- // We need to keep track of if there has been a runtime error.
68
- // Essentially, we cannot guarantee application state was not corrupted by the
69
- // runtime error. To prevent confusing behavior, we forcibly reload the entire
70
- // application. This is handled below when we are notified of a compile (code
71
- // change).
72
- // See https://github.com/facebook/create-react-app/issues/3096
73
- ErrorOverlay.startReportingRuntimeErrors({
55
+ startReportingRuntimeErrors({
74
56
  onError: function () {
75
57
  hadRuntimeError = true;
76
58
  }
77
59
  });
78
60
  if (module.hot && typeof module.hot.dispose === 'function') {
79
61
  module.hot.dispose(function () {
80
- // TODO: why do we need this?
81
- ErrorOverlay.stopReportingRuntimeErrors();
62
+ stopReportingRuntimeErrors();
82
63
  });
83
64
  }
84
65
  connectHMR(Object.assign(Object.assign({}, options), { log: true }));
@@ -104,9 +85,6 @@ export default function connect(options) {
104
85
  },
105
86
  subscribeToHmrEvent(handler) {
106
87
  customHmrEventHandler = handler;
107
- },
108
- reportRuntimeError(err) {
109
- ErrorOverlay.reportRuntimeError(err);
110
88
  }
111
89
  };
112
90
  }
@@ -123,8 +101,11 @@ function clearOutdatedErrors() {
123
101
  }
124
102
  }
125
103
  let startLatency = undefined;
126
- function onFastRefresh() {
127
- tryDismissErrorOverlay();
104
+ function onFastRefresh(hasUpdates) {
105
+ onBuildOk();
106
+ if (hasUpdates) {
107
+ onRefresh();
108
+ }
128
109
  if (startLatency) {
129
110
  const endLatency = Date.now();
130
111
  const latency = endLatency - startLatency;
@@ -139,10 +120,10 @@ function handleSuccess() {
139
120
  hasCompileErrors = false;
140
121
  // Attempt to apply hot updates or reload.
141
122
  if (isHotUpdate) {
142
- tryApplyUpdates(function onHotUpdateSuccess() {
123
+ tryApplyUpdates(function onHotUpdateSuccess(hasUpdates) {
143
124
  // Only dismiss it when we're sure it's a hot update.
144
125
  // Otherwise it would flicker right before the reload.
145
- onFastRefresh();
126
+ onFastRefresh(hasUpdates);
146
127
  });
147
128
  }
148
129
  }
@@ -169,16 +150,18 @@ function handleWarnings(warnings) {
169
150
  }
170
151
  // Attempt to apply hot updates or reload.
171
152
  if (isHotUpdate) {
172
- tryApplyUpdates(function onSuccessfulHotUpdate() {
153
+ tryApplyUpdates(function onSuccessfulHotUpdate(hasUpdates) {
173
154
  // Only dismiss it when we're sure it's a hot update.
174
155
  // Otherwise it would flicker right before the reload.
175
- tryDismissErrorOverlay();
176
- onFastRefresh();
156
+ onFastRefresh(hasUpdates);
177
157
  });
178
158
  }
179
159
  }
180
160
  // Compilation with errors (e.g. syntax error or missing modules).
181
161
  function handleErrors(errors) {
162
+ if (!Boolean(errors && errors.length)) {
163
+ return;
164
+ }
182
165
  clearOutdatedErrors();
183
166
  isFirstCompilation = false;
184
167
  hasCompileErrors = true;
@@ -188,7 +171,7 @@ function handleErrors(errors) {
188
171
  warnings: []
189
172
  });
190
173
  // Only show the first error.
191
- ErrorOverlay.reportBuildError(formatted.errors[0]);
174
+ onBuildError(formatted.errors[0]);
192
175
  // Also log them to the console.
193
176
  if (typeof console !== 'undefined' && typeof console.error === 'function') {
194
177
  for (var i = 0; i < formatted.errors.length; i++) {
@@ -196,11 +179,6 @@ function handleErrors(errors) {
196
179
  }
197
180
  }
198
181
  }
199
- function tryDismissErrorOverlay() {
200
- if (!hasCompileErrors) {
201
- ErrorOverlay.dismissBuildError();
202
- }
203
- }
204
182
  // There is a newer version of the code available.
205
183
  function handleAvailableHash(hash) {
206
184
  // Update last known compilation hash.
@@ -286,7 +264,7 @@ function tryApplyUpdates(onHotUpdateSuccess) {
286
264
  return;
287
265
  }
288
266
  if (!isUpdateAvailable() || !canApplyUpdates()) {
289
- ErrorOverlay.dismissBuildError();
267
+ onBuildOk();
290
268
  // HMR failed, need to refresh
291
269
  const hmrStatus = module.hot.status();
292
270
  if (hmrStatus === 'abort' || hmrStatus === 'fail') {
@@ -295,24 +273,25 @@ function tryApplyUpdates(onHotUpdateSuccess) {
295
273
  return;
296
274
  }
297
275
  function handleApplyUpdates(err, updatedModules) {
298
- const needForcedReload = err || hadRuntimeError;
299
- if (needForcedReload) {
300
- if (hadRuntimeError) {
301
- hadRuntimeError = false;
302
- window.location.reload();
303
- }
304
- else {
305
- ErrorOverlay.reportRuntimeError(err);
306
- hadRuntimeError = true;
307
- }
276
+ const hasUpdates = Boolean(updatedModules === null || updatedModules === void 0 ? void 0 : updatedModules.length);
277
+ if (hadRuntimeError) {
278
+ hadRuntimeError = false;
279
+ window.location.reload();
280
+ return;
281
+ }
282
+ if (err) {
283
+ hadRuntimeError = true;
308
284
  }
309
285
  if (typeof onHotUpdateSuccess === 'function') {
310
286
  // Maybe we want to do something.
311
- onHotUpdateSuccess();
287
+ onHotUpdateSuccess(hasUpdates);
312
288
  }
313
289
  if (isUpdateAvailable()) {
314
290
  // While we were updating, there was a new update! Do it again.
315
- tryApplyUpdates(onHotUpdateSuccess);
291
+ tryApplyUpdates(hasUpdates ? onBuildOk : onHotUpdateSuccess);
292
+ }
293
+ else {
294
+ onBuildOk();
316
295
  }
317
296
  }
318
297
  try {
@@ -3,7 +3,6 @@ export declare function sendMessage(data: any): any;
3
3
  export declare type HotDevClient = {
4
4
  sendMessage: (data: any) => void;
5
5
  subscribeToHmrEvent?: (handler: any) => void;
6
- reportRuntimeError?: (err: any) => void;
7
6
  };
8
7
  export declare function connectHMR(options: {
9
8
  path: string;
@@ -0,0 +1,2 @@
1
+ import { IError } from '@shuvi/platform-shared/shared';
2
+ export declare function serializeServerError(err: Error, dev: boolean | undefined): IError;
@@ -0,0 +1,21 @@
1
+ // @ts-ignore
2
+ import stripAnsi from 'strip-ansi';
3
+ function errorToJSON(err) {
4
+ return {
5
+ code: 500,
6
+ message: stripAnsi(err.message),
7
+ name: err.name,
8
+ source: 'server',
9
+ stack: err.stack
10
+ };
11
+ }
12
+ export function serializeServerError(err, dev) {
13
+ if (dev) {
14
+ return errorToJSON(err);
15
+ }
16
+ return {
17
+ code: 500,
18
+ message: 'Internal Server Error',
19
+ name: 'Internal Server Error'
20
+ };
21
+ }
@@ -1,6 +1,5 @@
1
1
  import * as React from 'react';
2
2
  import { IApplication } from '@shuvi/platform-shared/shared';
3
- export default function AppContainer({ children, app }: {
3
+ export default function AppContainer({ app, children }: React.PropsWithChildren<{
4
4
  app: IApplication;
5
- children: React.ReactElement;
6
- }): JSX.Element;
5
+ }>): JSX.Element;
@@ -1,10 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import { errorModel } from '@shuvi/platform-shared/shared';
3
- import { createContainer } from '@shuvi/redox-react';
4
3
  import { AppProvider } from './applicationContext';
5
4
  import ErrorPage from './ErrorPage';
6
5
  import { ErrorBoundary } from './ErrorBoundary';
7
- const { Provider, useSharedModel } = createContainer();
6
+ import { Provider, useSharedModel } from './store';
8
7
  function ErrorGuard({ children = null }) {
9
8
  const [errorState] = useSharedModel(errorModel);
10
9
  if (errorState.error !== undefined) {
@@ -12,10 +11,10 @@ function ErrorGuard({ children = null }) {
12
11
  }
13
12
  return <>{children}</>;
14
13
  }
15
- export default function AppContainer({ children, app }) {
14
+ export default function AppContainer({ app, children }) {
16
15
  return (<ErrorBoundary>
17
16
  <AppProvider app={app}>
18
- <Provider storeManager={app.storeManager}>
17
+ <Provider store={app.store}>
19
18
  <ErrorGuard>{children}</ErrorGuard>
20
19
  </Provider>
21
20
  </AppProvider>
@@ -13,8 +13,7 @@ import { loadRouteComponent } from './loadRouteComponent';
13
13
  export default function getRoutes(routes) {
14
14
  const getRoutesWithRequire = (routes) => routes.map(x => {
15
15
  const originalRoute = Object.assign({}, x);
16
- const { __componentRawRequest__, __import__, __resolveWeak__, children } = originalRoute, rest = __rest(originalRoute, ["__componentRawRequest__", "__import__", "__resolveWeak__", "children"]);
17
- const route = Object.assign({}, rest);
16
+ const { __componentRawRequest__, __import__, __resolveWeak__, children } = originalRoute, route = __rest(originalRoute, ["__componentRawRequest__", "__import__", "__resolveWeak__", "children"]);
18
17
  if (children) {
19
18
  route.children = getRoutesWithRequire(children);
20
19
  }
@@ -23,7 +22,10 @@ export default function getRoutes(routes) {
23
22
  modules: [__componentRawRequest__]
24
23
  })));
25
24
  }
26
- return Object.assign({ __componentRawRequest__, __resolveWeak__ }, route);
25
+ if (__componentRawRequest__) {
26
+ route.__componentRawRequest__ = __componentRawRequest__;
27
+ }
28
+ return route;
27
29
  });
28
30
  const routesWithRequire = getRoutesWithRequire(routes || []);
29
31
  return routesWithRequire;
@@ -1,8 +1,8 @@
1
1
  /// <reference types="react" />
2
- import type { IStoreManager } from '@shuvi/redox';
2
+ import type { RedoxStore } from '@shuvi/redox';
3
3
  export declare const RedoxWrapper: (App: any, appContext: {
4
- storeManager: IStoreManager;
4
+ store: RedoxStore;
5
5
  }) => {
6
- (appProps: any): JSX.Element;
6
+ (): JSX.Element;
7
7
  displayName: string;
8
8
  };
@@ -1,9 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import { RedoxRoot } from '@shuvi/redox-react';
3
3
  export const RedoxWrapper = (App, appContext) => {
4
- function RedoxAppWrapper(appProps) {
5
- return (<RedoxRoot storeManager={appContext.storeManager}>
6
- <App {...appProps}/>
4
+ function RedoxAppWrapper() {
5
+ return (<RedoxRoot store={appContext.store}>
6
+ <App />
7
7
  </RedoxRoot>);
8
8
  }
9
9
  RedoxAppWrapper.displayName = 'RedoxAppWrapper';
@@ -0,0 +1,8 @@
1
+ import { RedoxStore } from '@shuvi/redox';
2
+ declare module '@shuvi/runtime' {
3
+ interface CustomAppContext {
4
+ store: RedoxStore;
5
+ }
6
+ }
7
+ declare const _default: import("@shuvi/platform-shared/shared").IPluginInstance<import("@shuvi/platform-shared/shared").RuntimePluginHooks, void>;
8
+ export default _default;
@@ -7,12 +7,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { createRuntimePlugin } from '@shuvi/platform-shared/shared';
10
+ import { createRuntimePluginAfter } from '@shuvi/platform-shared/shared';
11
11
  import { RedoxWrapper } from './RedoxWrapper';
12
- export default createRuntimePlugin({
12
+ // this needs to be run last
13
+ export default createRuntimePluginAfter({
13
14
  appComponent: (App, appContext) => __awaiter(void 0, void 0, void 0, function* () {
14
15
  return RedoxWrapper(App, {
15
- storeManager: appContext.store
16
+ store: appContext.store
16
17
  });
17
18
  })
19
+ }, {
20
+ name: 'model-react'
18
21
  });
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ declare const Provider: (props: import("react").PropsWithChildren<{
3
+ store?: import("@shuvi/redox").RedoxStore | undefined;
4
+ }>) => JSX.Element, useSharedModel: import("@shuvi/redox-react/esm/types").IUseModel, useStaticModel: import("@shuvi/redox-react/esm/types").IUseStaticModel;
5
+ export { Provider, useSharedModel, useStaticModel };
@@ -0,0 +1,3 @@
1
+ import { createContainer } from '@shuvi/redox-react';
2
+ const { Provider, useSharedModel, useStaticModel } = createContainer();
3
+ export { Provider, useSharedModel, useStaticModel };
@@ -1,14 +1,7 @@
1
- import { IAppState } from '@shuvi/platform-shared/shared';
2
1
  import { IHtmlTag, IViewClient, IViewServer } from '../../shared';
3
2
  export { IHtmlTag };
4
3
  export declare type IReactAppData = {
5
- appProps?: Record<string, any>;
6
- errorProps?: {
7
- notFound: boolean;
8
- };
9
4
  dynamicIds?: Array<string | number>;
10
- appState?: IAppState;
11
- loadersData: any;
12
5
  };
13
6
  export declare type IReactServerView = IViewServer<IReactAppData>;
14
7
  export declare type IReactClientView = IViewClient<IReactAppData>;
@@ -1,27 +1,16 @@
1
1
  import { useMatchedRoute } from '@shuvi/router-react';
2
- import { getLoaderManager } from '@shuvi/platform-shared/shared';
3
- import { useRef, useEffect, useReducer } from 'react';
2
+ import { loaderModel } from '@shuvi/platform-shared/shared';
3
+ import { useStaticModel } from './store';
4
4
  export const noLoaderMessage = 'Warning: no loader found. Please make sure the page component where `useLoaderData` is called has a `loader` export.';
5
+ const hasOwn = Object.prototype.hasOwnProperty;
5
6
  export const useLoaderData = () => {
6
- var _a;
7
7
  const currentMatch = useMatchedRoute();
8
- const loaderManager = getLoaderManager();
9
- const id = (_a = currentMatch.route) === null || _a === void 0 ? void 0 : _a.id;
10
- const data = loaderManager.getData(id);
11
- if (data === null) {
8
+ const id = currentMatch.route.id;
9
+ // we don't need to watch the model change, cause it always change with
10
+ // matched route
11
+ const [state] = useStaticModel(loaderModel);
12
+ if (!hasOwn.call(state.current.dataByRouteId, id)) {
12
13
  throw Error(noLoaderMessage);
13
14
  }
14
- const dataRef = useRef(data);
15
- const [_, forceUpdate] = useReducer(state => state * -1, 1);
16
- useEffect(() => {
17
- const cancel = loaderManager.subscribe(() => {
18
- const newData = loaderManager.getData(id);
19
- if (newData !== data) {
20
- dataRef.current = newData;
21
- forceUpdate();
22
- }
23
- });
24
- return cancel;
25
- }, []);
26
- return dataRef.current;
15
+ return state.current.dataByRouteId[id];
27
16
  };