@shuvi/platform-web 1.0.0-rc.3 → 1.0.0-rc.6

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 (108) hide show
  1. package/esm/shared/appTypes.d.ts +5 -3
  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.d.ts +2 -0
  5. package/esm/shuvi-app/app/client.js +13 -17
  6. package/esm/shuvi-app/app/server.js +10 -9
  7. package/esm/shuvi-app/dev/eventsource.d.ts +1 -0
  8. package/esm/shuvi-app/dev/eventsource.js +60 -0
  9. package/esm/shuvi-app/dev/hotDevClient.d.ts +32 -0
  10. package/esm/shuvi-app/dev/hotDevClient.js +327 -0
  11. package/esm/shuvi-app/dev/index.d.ts +3 -0
  12. package/esm/shuvi-app/dev/index.js +27 -0
  13. package/esm/shuvi-app/dev/websocket.d.ts +16 -0
  14. package/esm/shuvi-app/dev/websocket.js +61 -0
  15. package/esm/shuvi-app/entry/client/app.d.ts +2 -1
  16. package/esm/shuvi-app/entry/client/app.js +2 -2
  17. package/esm/shuvi-app/entry/client/run.dev.js +4 -4
  18. package/esm/shuvi-app/entry/server/index.d.ts +5 -4
  19. package/esm/shuvi-app/entry/server/index.js +5 -4
  20. package/esm/shuvi-app/helper/serializeServerError.d.ts +2 -0
  21. package/esm/shuvi-app/helper/serializeServerError.js +21 -0
  22. package/esm/shuvi-app/react/AppContainer.d.ts +2 -3
  23. package/esm/shuvi-app/react/AppContainer.jsx +3 -4
  24. package/esm/shuvi-app/react/getRoutes.d.ts +2 -2
  25. package/esm/shuvi-app/react/getRoutes.js +9 -8
  26. package/esm/shuvi-app/react/{redox-react → model}/RedoxWrapper.d.ts +3 -3
  27. package/esm/shuvi-app/react/{redox-react → model}/RedoxWrapper.jsx +3 -3
  28. package/esm/shuvi-app/react/model/runtime.d.ts +8 -0
  29. package/esm/shuvi-app/react/{redox-react → model}/runtime.js +8 -3
  30. package/esm/shuvi-app/react/store.d.ts +5 -0
  31. package/esm/shuvi-app/react/store.js +3 -0
  32. package/esm/shuvi-app/react/types.d.ts +0 -7
  33. package/esm/shuvi-app/react/useLoaderData.js +9 -20
  34. package/esm/shuvi-app/react/view/ReactView.client.jsx +25 -4
  35. package/esm/shuvi-app/react/view/ReactView.server.jsx +17 -14
  36. package/esm/shuvi-app/shuvi-runtime-index.d.ts +3 -3
  37. package/esm/shuvi-app/shuvi-runtime-index.js +1 -1
  38. package/lib/node/features/custom-server/index.d.ts +1 -1
  39. package/lib/node/features/custom-server/server.d.ts +1 -1
  40. package/lib/node/features/filesystem-routes/api/apiRouteHandler.d.ts +7 -7
  41. package/lib/node/features/filesystem-routes/api/apiRouteHandler.js +0 -4
  42. package/lib/node/features/filesystem-routes/api/middleware.d.ts +2 -2
  43. package/lib/node/features/filesystem-routes/index.d.ts +1 -13
  44. package/lib/node/features/filesystem-routes/index.js +20 -48
  45. package/lib/node/features/filesystem-routes/middleware/middleware.d.ts +2 -2
  46. package/lib/node/features/filesystem-routes/page/routes.d.ts +2 -2
  47. package/lib/node/features/filesystem-routes/page/routes.js +29 -11
  48. package/lib/node/features/html-render/index.d.ts +3 -18
  49. package/lib/node/features/html-render/index.js +87 -16
  50. package/lib/node/features/{main → html-render/lib}/buildHtml.d.ts +0 -0
  51. package/lib/node/features/{main → html-render/lib}/buildHtml.js +0 -0
  52. package/lib/node/features/html-render/lib/generateFilesByRoutId.d.ts +2 -2
  53. package/lib/node/features/html-render/lib/generateFilesByRoutId.js +3 -3
  54. package/lib/node/features/{main → html-render/lib}/generateResource.d.ts +0 -0
  55. package/lib/node/features/{main → html-render/lib}/generateResource.js +0 -0
  56. package/lib/node/features/html-render/lib/getPageMiddleware.d.ts +2 -2
  57. package/lib/node/features/html-render/lib/index.d.ts +0 -1
  58. package/lib/node/features/html-render/lib/index.js +1 -3
  59. package/lib/node/features/html-render/lib/renderToHTML.d.ts +2 -2
  60. package/lib/node/features/html-render/lib/renderToHTML.js +7 -48
  61. package/lib/node/features/html-render/lib/renderer/base.d.ts +6 -6
  62. package/lib/node/features/html-render/lib/renderer/base.js +5 -5
  63. package/lib/node/features/html-render/lib/renderer/index.d.ts +5 -4
  64. package/lib/node/features/html-render/lib/renderer/index.js +69 -6
  65. package/lib/node/features/html-render/lib/renderer/spa.d.ts +2 -2
  66. package/lib/node/features/html-render/lib/renderer/spa.js +4 -6
  67. package/lib/node/features/html-render/lib/renderer/ssr.d.ts +2 -2
  68. package/lib/node/features/html-render/lib/renderer/ssr.js +5 -6
  69. package/lib/node/features/html-render/lib/renderer/types.d.ts +8 -5
  70. package/lib/node/features/html-render/server.d.ts +1 -1
  71. package/lib/node/features/index.d.ts +3 -31
  72. package/lib/node/features/index.js +6 -7
  73. package/lib/node/features/model/index.d.ts +1 -13
  74. package/lib/node/features/model/runtime.d.ts +3 -8
  75. package/lib/node/features/model/runtime.js +13 -17
  76. package/lib/node/features/model/server.js +2 -3
  77. package/lib/node/features/model/shuvi-app.d.ts +2 -2
  78. package/lib/node/features/on-demand-compile-page/index.d.ts +3 -13
  79. package/lib/node/features/on-demand-compile-page/index.js +4 -1
  80. package/lib/node/features/on-demand-compile-page/onDemandRouteManager.d.ts +3 -3
  81. package/lib/node/features/on-demand-compile-page/onDemandRouteManager.js +2 -4
  82. package/lib/node/index.js +1 -3
  83. package/lib/node/paths.js +0 -2
  84. package/lib/node/shuvi-runtime-server.d.ts +18 -0
  85. package/lib/node/shuvi-runtime-server.js +2 -0
  86. package/lib/node/shuvi-type-extensions-node.d.ts +2 -6
  87. package/lib/node/targets/react/bundler/index.d.ts +1 -13
  88. package/lib/node/targets/react/bundler/index.js +5 -0
  89. package/lib/node/targets/react/index.d.ts +2 -26
  90. package/lib/node/targets/react/index.js +2 -2
  91. package/lib/node/targets/react/model/index.d.ts +6 -0
  92. package/lib/node/targets/react/{redox-react → model}/index.js +7 -6
  93. package/lib/shared/appTypes.d.ts +5 -3
  94. package/lib/shared/renderTypes.d.ts +6 -5
  95. package/lib/shared/routeTypes.d.ts +4 -9
  96. package/package.json +20 -15
  97. package/shuvi-env.d.ts +10 -0
  98. package/shuvi-image.d.ts +54 -0
  99. package/shuvi-type-extensions-node.js +1 -0
  100. package/shuvi-type-extensions-runtime.d.ts +2 -2
  101. package/esm/shuvi-app/dev/webpackHotDevClient.d.ts +0 -5
  102. package/esm/shuvi-app/dev/webpackHotDevClient.js +0 -34
  103. package/esm/shuvi-app/react/redox-react/runtime.d.ts +0 -2
  104. package/esm/shuvi-app/shuvi-runtime-server.d.ts +0 -6
  105. package/esm/shuvi-app/shuvi-runtime-server.js +0 -1
  106. package/lib/node/features/main/index.d.ts +0 -3
  107. package/lib/node/features/main/index.js +0 -82
  108. package/lib/node/targets/react/redox-react/index.d.ts +0 -18
@@ -0,0 +1,27 @@
1
+ import { DEV_SOCKET_TIMEOUT_MS, DEV_HOT_MIDDLEWARE_PATH, DEV_HOT_LAUNCH_EDITOR_ENDPOINT } from '@shuvi/shared/esm/constants';
2
+ import connect from './hotDevClient';
3
+ let devClient;
4
+ export const initHMRAndDevClient = (app) => {
5
+ if (devClient) {
6
+ return devClient;
7
+ }
8
+ devClient = connect({
9
+ launchEditorEndpoint: DEV_HOT_LAUNCH_EDITOR_ENDPOINT,
10
+ path: DEV_HOT_MIDDLEWARE_PATH,
11
+ location
12
+ });
13
+ setInterval(() => {
14
+ devClient.sendMessage(JSON.stringify({
15
+ event: 'updatePageStatus',
16
+ currentRoutes: app.router.current.matches.map(({ route: { __componentRawRequest__ } }) => __componentRawRequest__),
17
+ page: location.pathname
18
+ }));
19
+ }, DEV_SOCKET_TIMEOUT_MS / 2);
20
+ devClient.subscribeToHmrEvent((event) => {
21
+ // if (obj.action === "reloadPage") {
22
+ // return window.location.reload();
23
+ // }
24
+ // throw new Error("Unexpected action " + obj.action);
25
+ });
26
+ return devClient;
27
+ };
@@ -0,0 +1,16 @@
1
+ export declare function addMessageListener(cb: (event: any) => void): void;
2
+ export declare function sendMessage(data: any): any;
3
+ export declare type HotDevClient = {
4
+ sendMessage: (data: any) => void;
5
+ subscribeToHmrEvent?: (handler: any) => void;
6
+ };
7
+ export declare function connectHMR(options: {
8
+ path: string;
9
+ timeout: number;
10
+ log?: boolean;
11
+ location: {
12
+ protocol: string;
13
+ hostname: string;
14
+ port?: string;
15
+ };
16
+ }): void;
@@ -0,0 +1,61 @@
1
+ let source;
2
+ const eventCallbacks = [];
3
+ let lastActivity = Date.now();
4
+ let initDataBeforeWsOnline = [];
5
+ function getSocketProtocol(protocol) {
6
+ return protocol === 'http:' ? 'ws' : 'wss';
7
+ }
8
+ export function addMessageListener(cb) {
9
+ eventCallbacks.push(cb);
10
+ }
11
+ export function sendMessage(data) {
12
+ if (!source || source.readyState !== source.OPEN) {
13
+ initDataBeforeWsOnline.push(data);
14
+ return;
15
+ }
16
+ return source.send(data);
17
+ }
18
+ export function connectHMR(options) {
19
+ if (!options.timeout) {
20
+ options.timeout = 5000;
21
+ }
22
+ init();
23
+ let timer = setInterval(function () {
24
+ if (Date.now() - lastActivity > options.timeout) {
25
+ handleDisconnect();
26
+ }
27
+ }, options.timeout / 2);
28
+ function init() {
29
+ if (source)
30
+ source.close();
31
+ let { protocol, hostname, port } = options.location;
32
+ protocol = getSocketProtocol(protocol);
33
+ let url = `${protocol}://${hostname}:${port}`;
34
+ source = new WebSocket(`${url}${options.path}`);
35
+ source.onopen = handleOnline;
36
+ source.onerror = handleDisconnect;
37
+ source.onmessage = handleMessage;
38
+ }
39
+ function handleOnline() {
40
+ if (initDataBeforeWsOnline.length !== 0) {
41
+ initDataBeforeWsOnline.forEach(data => {
42
+ sendMessage(data);
43
+ });
44
+ initDataBeforeWsOnline = [];
45
+ }
46
+ if (options.log)
47
+ console.log('[HMR] connected');
48
+ lastActivity = Date.now();
49
+ }
50
+ function handleMessage(event) {
51
+ lastActivity = Date.now();
52
+ eventCallbacks.forEach(cb => {
53
+ cb(event);
54
+ });
55
+ }
56
+ function handleDisconnect() {
57
+ clearInterval(timer);
58
+ source.close();
59
+ setTimeout(init, options.timeout);
60
+ }
61
+ }
@@ -1,2 +1,3 @@
1
+ declare const app: import("../../app/client").Application;
1
2
  declare const run: () => Promise<void>;
2
- export { run };
3
+ export { run, app };
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { CLIENT_CONTAINER_ID } from '@shuvi/shared/lib/constants';
11
11
  // renderer must be imported before application
12
- // we need to init init renderer before import AppComponent
12
+ // we need to init renderer before import AppComponent
13
13
  import { view, getRoutes, app as PlatformAppComponent } from '@shuvi/app/core/platform';
14
14
  import routes from '@shuvi/app/files/routes';
15
15
  import { getAppData } from '@shuvi/platform-shared/shared/helper/getAppData';
@@ -32,7 +32,7 @@ const run = () => __awaiter(void 0, void 0, void 0, function* () {
32
32
  yield app.init();
33
33
  render();
34
34
  });
35
- export { run };
35
+ export { run, app };
36
36
  if (module.hot) {
37
37
  const handleHotUpdate = () => __awaiter(void 0, void 0, void 0, function* () {
38
38
  const rerender = () => __awaiter(void 0, void 0, void 0, function* () {
@@ -9,11 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  /// <reference lib="dom" />
11
11
  import { DEV_STYLE_HIDE_FOUC, DEV_STYLE_PREPARE } from '@shuvi/shared/lib/constants';
12
- import initWebpackHMR from '../../dev/webpackHotDevClient';
13
- import { run } from './app';
12
+ import { initHMRAndDevClient } from '../../dev';
13
+ import { run, app } from './app';
14
14
  function init() {
15
15
  return __awaiter(this, void 0, void 0, function* () {
16
- initWebpackHMR();
16
+ initHMRAndDevClient(app);
17
17
  // reduce FOUC caused by style-loader
18
18
  const styleReady = new Promise(resolve => {
19
19
  (window.requestAnimationFrame || setTimeout)(() => __awaiter(this, void 0, void 0, function* () {
@@ -27,4 +27,4 @@ function init() {
27
27
  yield styleReady;
28
28
  });
29
29
  }
30
- init().then(run);
30
+ init().then(() => run());
@@ -1,6 +1,7 @@
1
- import * as application from '../../app/server';
2
- import * as server from '@shuvi/app/user/server';
1
+ import { default as pageRoutes } from '@shuvi/app/files/routes';
3
2
  import { default as apiRoutes } from '@shuvi/app/files/apiRoutes';
4
3
  import { default as middlewareRoutes } from '@shuvi/app/files/middlewareRoutes';
5
- export { server, application, apiRoutes, middlewareRoutes };
6
- export { view } from '@shuvi/app/core/platform';
4
+ import { view } from '@shuvi/app/core/platform';
5
+ import * as server from '@shuvi/app/user/server';
6
+ import * as application from '../../app/server';
7
+ export { pageRoutes, apiRoutes, middlewareRoutes, server, view, application };
@@ -1,7 +1,8 @@
1
1
  // This is the shuvi server-side main module exports collection
2
- import * as application from '../../app/server';
3
- import * as server from '@shuvi/app/user/server';
2
+ import { default as pageRoutes } from '@shuvi/app/files/routes';
4
3
  import { default as apiRoutes } from '@shuvi/app/files/apiRoutes';
5
4
  import { default as middlewareRoutes } from '@shuvi/app/files/middlewareRoutes';
6
- export { server, application, apiRoutes, middlewareRoutes };
7
- export { view } from '@shuvi/app/core/platform';
5
+ import { view } from '@shuvi/app/core/platform';
6
+ import * as server from '@shuvi/app/user/server';
7
+ import * as application from '../../app/server';
8
+ export { pageRoutes, apiRoutes, middlewareRoutes, server, view, application };
@@ -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>
@@ -1,2 +1,2 @@
1
- import { IPageRouteRecord, IRawPageRouteRecord } from '@shuvi/platform-shared/shared';
2
- export default function getRoutes(routes: IRawPageRouteRecord[]): IPageRouteRecord[];
1
+ import { IPageRouteRecord } from '@shuvi/platform-shared/shared';
2
+ export default function getRoutes(routes: IPageRouteRecord[]): IPageRouteRecord[];
@@ -13,18 +13,19 @@ 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 { __componentSource__, __componentSourceWithAffix__, __import__, __resolveWeak__, children } = originalRoute, rest = __rest(originalRoute, ["__componentSource__", "__componentSourceWithAffix__", "__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
  }
21
- if (__componentSourceWithAffix__ && __import__) {
22
- route.component = loadRouteComponent(__import__, {
23
- webpack: __resolveWeak__,
24
- modules: [__componentSourceWithAffix__]
25
- });
20
+ if (__import__) {
21
+ route.component = loadRouteComponent(__import__, Object.assign({ webpack: __resolveWeak__ }, (__componentRawRequest__ && {
22
+ modules: [__componentRawRequest__]
23
+ })));
26
24
  }
27
- return Object.assign({ __componentSourceWithAffix__, __resolveWeak__ }, route);
25
+ if (__componentRawRequest__) {
26
+ route.__componentRawRequest__ = __componentRawRequest__;
27
+ }
28
+ return route;
28
29
  });
29
30
  const routesWithRequire = getRoutesWithRequire(routes || []);
30
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,10 +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
- return RedoxWrapper(App, appContext);
15
+ return RedoxWrapper(App, {
16
+ store: appContext.store
17
+ });
15
18
  })
19
+ }, {
20
+ name: 'model-react'
16
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
  };
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import * as React from 'react';
11
11
  import { SHUVI_ERROR } from '@shuvi/shared/lib/constants';
12
12
  import { Router } from '@shuvi/router-react';
13
+ import { getServerError } from '@shuvi/error-overlay';
13
14
  import AppContainer from '../AppContainer';
14
15
  import { HeadManager, HeadManagerContext } from '../head';
15
16
  import Loadable from '../loadable';
@@ -20,8 +21,8 @@ export class ReactClientView {
20
21
  this._isInitialRender = true;
21
22
  this.renderApp = ({ appContainer, app, appData }) => __awaiter(this, void 0, void 0, function* () {
22
23
  const { _isInitialRender: isInitialRender } = this;
23
- const { router, appComponent: AppComponent, error } = app;
24
- let { ssr, appProps, dynamicIds } = appData;
24
+ const { router, appComponent: AppComponent, setError: setAppError, error: appError } = app;
25
+ let { ssr, dynamicIds } = appData;
25
26
  // For e2e test
26
27
  if (window.__SHUVI) {
27
28
  window.__SHUVI.router = router;
@@ -29,6 +30,26 @@ export class ReactClientView {
29
30
  else {
30
31
  window.__SHUVI = { router };
31
32
  }
33
+ if (process.env.NODE_ENV === 'development') {
34
+ if (appError && appError.source === 'server') {
35
+ setTimeout(() => {
36
+ var _a;
37
+ let error;
38
+ try {
39
+ // Generate a new error object. We `throw` it because some browsers
40
+ // will set the `stack` when thrown, and we want to ensure ours is
41
+ // not overridden when we re-throw it below.
42
+ throw new Error(appError.message);
43
+ }
44
+ catch (e) {
45
+ error = e;
46
+ }
47
+ error.name = (_a = appError.name) !== null && _a !== void 0 ? _a : '';
48
+ error.stack = appError.stack;
49
+ throw getServerError(error);
50
+ });
51
+ }
52
+ }
32
53
  const TypedAppComponent = AppComponent;
33
54
  if (ssr) {
34
55
  yield Loadable.preloadReady(dynamicIds);
@@ -39,13 +60,13 @@ export class ReactClientView {
39
60
  const { matches } = router.current;
40
61
  if (!matches.length) {
41
62
  // no handler no matches
42
- error.error(SHUVI_ERROR.PAGE_NOT_FOUND);
63
+ setAppError(SHUVI_ERROR.PAGE_NOT_FOUND);
43
64
  }
44
65
  }
45
66
  const root = (<Router router={router}>
46
67
  <AppContainer app={app}>
47
68
  <HeadManagerContext.Provider value={headManager.updateHead}>
48
- <TypedAppComponent {...appProps}/>
69
+ <TypedAppComponent />
49
70
  </HeadManagerContext.Provider>
50
71
  </AppContainer>
51
72
  </Router>);
@@ -9,32 +9,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import * as React from 'react';
11
11
  import { renderToString } from 'react-dom/server';
12
- import { getLoaderManager, redirect } from '@shuvi/platform-shared/shared';
12
+ import { redirect } from '@shuvi/platform-shared/shared';
13
13
  import { SHUVI_ERROR } from '@shuvi/shared/lib/constants';
14
14
  import { Router } from '@shuvi/router-react';
15
+ import chalk from '@shuvi/utils/lib/chalk';
15
16
  import Loadable, { LoadableContext } from '../loadable';
16
17
  import AppContainer from '../AppContainer';
17
18
  import { Head } from '../head';
19
+ import { serializeServerError } from '../../helper/serializeServerError';
18
20
  export class ReactServerView {
19
21
  constructor() {
20
- this.renderApp = ({ app, manifest, getAssetPublicUrl }) => __awaiter(this, void 0, void 0, function* () {
22
+ this.renderApp = ({ req, app, manifest, isDev }) => __awaiter(this, void 0, void 0, function* () {
21
23
  yield Loadable.preloadAll();
22
- const { storeManager, router, error: appError, appComponent: AppComponent } = app;
24
+ const { router, appComponent: AppComponent, setError: setAppError } = app;
23
25
  yield router.ready;
24
26
  // todo: move these into renderer
25
27
  let { pathname, matches, redirected } = router.current;
26
28
  // handler no matches
27
29
  if (!matches.length) {
28
- appError.error(SHUVI_ERROR.PAGE_NOT_FOUND);
30
+ setAppError(SHUVI_ERROR.PAGE_NOT_FOUND);
29
31
  }
30
32
  if (redirected) {
31
33
  return redirect(pathname);
32
34
  }
33
- // todo: move loader into app, avoid using global module
34
- const loaderManager = getLoaderManager();
35
- const loadersData = yield loaderManager.getAllData();
36
35
  const loadableModules = [];
37
- let htmlContent;
36
+ let htmlContent = undefined;
38
37
  let head;
39
38
  const RootApp = (<Router static router={router}>
40
39
  <AppContainer app={app}>
@@ -46,8 +45,14 @@ export class ReactServerView {
46
45
  try {
47
46
  htmlContent = renderToString(RootApp);
48
47
  }
48
+ catch (error) {
49
+ if (isDev) {
50
+ console.error(chalk.red('error') + ' - ' + error.stack);
51
+ }
52
+ setAppError(serializeServerError(error, isDev));
53
+ htmlContent = renderToString(RootApp); // Consistency on both server and client side
54
+ }
49
55
  finally {
50
- loaderManager.clearAllData();
51
56
  head = Head.rewind() || [];
52
57
  }
53
58
  const { loadble } = manifest;
@@ -72,7 +77,7 @@ export class ReactServerView {
72
77
  tagName: 'link',
73
78
  attrs: {
74
79
  rel: 'preload',
75
- href: getAssetPublicUrl(file),
80
+ href: req.getAssetUrl(file),
76
81
  as: 'script'
77
82
  }
78
83
  });
@@ -82,19 +87,17 @@ export class ReactServerView {
82
87
  tagName: 'link',
83
88
  attrs: {
84
89
  rel: 'stylesheet',
85
- href: getAssetPublicUrl(file)
90
+ href: req.getAssetUrl(file)
86
91
  }
87
92
  });
88
93
  }
89
94
  }
90
95
  const appData = {
91
- dynamicIds: [...dynamicImportIdSet],
92
- loadersData
96
+ dynamicIds: [...dynamicImportIdSet]
93
97
  };
94
98
  if (dynamicImportIdSet.size) {
95
99
  appData.dynamicIds = Array.from(dynamicImportIdSet);
96
100
  }
97
- appData.appState = storeManager.getState();
98
101
  return {
99
102
  appData,
100
103
  content: htmlContent,
@@ -1,4 +1,4 @@
1
- import { IRequestHandlerWithNext } from '@shuvi/service';
1
+ import { ShuviRequestHandler } from '@shuvi/service';
2
2
  import { IApiRequestHandler } from '../shared';
3
- export declare type MiddlewareHandler = IRequestHandlerWithNext;
4
- export declare type APIHandler = IApiRequestHandler;
3
+ export declare type ShuviMiddlewareHandler = ShuviRequestHandler;
4
+ export declare type ShuviApiHandler = IApiRequestHandler;
@@ -1,2 +1,2 @@
1
- // exported by @shuvi/runtme
1
+ // exported by @shuvi/runtime
2
2
  export {};
@@ -1,4 +1,4 @@
1
1
  declare const _default: {
2
- server: import("@shuvi/hook").IPluginInstance<import("@shuvi/service/lib/server/plugin").BuiltInServerPluginHooks & import("@shuvi/service/lib/server/pluginTypes").CustomServerPluginHooks, import("@shuvi/service").IServerPluginContext>;
2
+ server: import("@shuvi/hook").IPluginInstance<import("@shuvi/service/lib/server/plugin").ServerPluginHooks, import("@shuvi/service").IServerPluginContext>;
3
3
  };
4
4
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: import("@shuvi/hook").IPluginInstance<import("@shuvi/service/lib/server/plugin").BuiltInServerPluginHooks & import("@shuvi/service/lib/server/pluginTypes").CustomServerPluginHooks, import("@shuvi/service").IServerPluginContext>;
1
+ declare const _default: import("@shuvi/hook").IPluginInstance<import("@shuvi/service/lib/server/plugin").ServerPluginHooks, import("@shuvi/service").IServerPluginContext>;
2
2
  export default _default;
@@ -1,14 +1,14 @@
1
1
  /// <reference types="node" />
2
2
  import { IncomingMessage } from 'http';
3
- import { IResponse, IRequest } from '@shuvi/service';
3
+ import { ShuviRequest, ShuviResponse } from '@shuvi/service';
4
4
  import { IApiRequestHandler, IApiResponse } from '../../../../shared';
5
5
  export { IApiRequestHandler };
6
- export declare function apiRouteHandler(req: IRequest, res: IResponse, resolver: IApiRequestHandler, apiRoutesConfig: any): Promise<void>;
6
+ export declare function apiRouteHandler(req: ShuviRequest, res: ShuviResponse, resolver: IApiRequestHandler, apiRoutesConfig: any): Promise<void>;
7
7
  /**
8
8
  * Parse incoming message like `json` or `urlencoded`
9
9
  * @param req request object
10
10
  */
11
- export declare function parseBody(req: IRequest, limit: string | number): Promise<any>;
11
+ export declare function parseBody(req: ShuviRequest, limit: string | number): Promise<any>;
12
12
  /**
13
13
  * Parse cookies from `req` header
14
14
  * @param req request object
@@ -21,27 +21,27 @@ export declare function getCookieParser(req: IncomingMessage): {
21
21
  * @param res ServerResponse object
22
22
  * @param statusCode `HTTP` status code of response
23
23
  */
24
- export declare function sendStatusCode<IRes extends IApiResponse>(res: IResponse, statusCode: number): IRes;
24
+ export declare function sendStatusCode<IRes extends IApiResponse>(res: ShuviResponse, statusCode: number): IRes;
25
25
  /**
26
26
  *
27
27
  * @param res response object
28
28
  * @param [statusOrUrl] `HTTP` status code of redirect
29
29
  * @param url URL of redirect
30
30
  */
31
- export declare function redirect<IRes extends IApiResponse>(res: IResponse, statusOrUrl: string | number, url?: string): IRes;
31
+ export declare function redirect<IRes extends IApiResponse>(res: ShuviResponse, statusOrUrl: string | number, url?: string): IRes;
32
32
  /**
33
33
  * Send `any` body to response
34
34
  * @param req request object
35
35
  * @param res response object
36
36
  * @param body of response
37
37
  */
38
- export declare function sendData(req: IRequest, res: IResponse, body: any): void;
38
+ export declare function sendData(req: ShuviRequest, res: ShuviResponse, body: any): void;
39
39
  /**
40
40
  * Send `JSON` object
41
41
  * @param res response object
42
42
  * @param jsonBody of data
43
43
  */
44
- export declare function sendJson(req: IRequest, res: IResponse, jsonBody: any): void;
44
+ export declare function sendJson(req: ShuviRequest, res: ShuviResponse, jsonBody: any): void;
45
45
  /**
46
46
  * Custom error class
47
47
  */
@@ -42,11 +42,7 @@ function apiRouteHandler(req, res, resolver, apiRoutesConfig) {
42
42
  return __awaiter(this, void 0, void 0, function* () {
43
43
  try {
44
44
  const { bodyParser } = apiRoutesConfig || {};
45
- const { pathname, query, params } = req;
46
45
  const apiReq = {
47
- pathname,
48
- query,
49
- params,
50
46
  // Parsing of cookies
51
47
  cookies: getCookieParser(req)
52
48
  };