@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.
- package/esm/shared/appTypes.d.ts +5 -3
- package/esm/shared/renderTypes.d.ts +6 -5
- package/esm/shared/routeTypes.d.ts +4 -9
- package/esm/shuvi-app/app/client.d.ts +2 -0
- package/esm/shuvi-app/app/client.js +13 -17
- package/esm/shuvi-app/app/server.js +10 -9
- package/esm/shuvi-app/dev/eventsource.d.ts +1 -0
- package/esm/shuvi-app/dev/eventsource.js +60 -0
- package/esm/shuvi-app/dev/hotDevClient.d.ts +32 -0
- package/esm/shuvi-app/dev/hotDevClient.js +327 -0
- package/esm/shuvi-app/dev/index.d.ts +3 -0
- package/esm/shuvi-app/dev/index.js +27 -0
- package/esm/shuvi-app/dev/websocket.d.ts +16 -0
- package/esm/shuvi-app/dev/websocket.js +61 -0
- package/esm/shuvi-app/entry/client/app.d.ts +2 -1
- package/esm/shuvi-app/entry/client/app.js +2 -2
- package/esm/shuvi-app/entry/client/run.dev.js +4 -4
- package/esm/shuvi-app/entry/server/index.d.ts +5 -4
- package/esm/shuvi-app/entry/server/index.js +5 -4
- package/esm/shuvi-app/helper/serializeServerError.d.ts +2 -0
- package/esm/shuvi-app/helper/serializeServerError.js +21 -0
- package/esm/shuvi-app/react/AppContainer.d.ts +2 -3
- package/esm/shuvi-app/react/AppContainer.jsx +3 -4
- package/esm/shuvi-app/react/getRoutes.d.ts +2 -2
- package/esm/shuvi-app/react/getRoutes.js +9 -8
- package/esm/shuvi-app/react/{redox-react → model}/RedoxWrapper.d.ts +3 -3
- package/esm/shuvi-app/react/{redox-react → model}/RedoxWrapper.jsx +3 -3
- package/esm/shuvi-app/react/model/runtime.d.ts +8 -0
- package/esm/shuvi-app/react/{redox-react → model}/runtime.js +8 -3
- package/esm/shuvi-app/react/store.d.ts +5 -0
- package/esm/shuvi-app/react/store.js +3 -0
- package/esm/shuvi-app/react/types.d.ts +0 -7
- package/esm/shuvi-app/react/useLoaderData.js +9 -20
- package/esm/shuvi-app/react/view/ReactView.client.jsx +25 -4
- package/esm/shuvi-app/react/view/ReactView.server.jsx +17 -14
- package/esm/shuvi-app/shuvi-runtime-index.d.ts +3 -3
- package/esm/shuvi-app/shuvi-runtime-index.js +1 -1
- package/lib/node/features/custom-server/index.d.ts +1 -1
- package/lib/node/features/custom-server/server.d.ts +1 -1
- package/lib/node/features/filesystem-routes/api/apiRouteHandler.d.ts +7 -7
- package/lib/node/features/filesystem-routes/api/apiRouteHandler.js +0 -4
- package/lib/node/features/filesystem-routes/api/middleware.d.ts +2 -2
- package/lib/node/features/filesystem-routes/index.d.ts +1 -13
- package/lib/node/features/filesystem-routes/index.js +20 -48
- package/lib/node/features/filesystem-routes/middleware/middleware.d.ts +2 -2
- package/lib/node/features/filesystem-routes/page/routes.d.ts +2 -2
- package/lib/node/features/filesystem-routes/page/routes.js +29 -11
- package/lib/node/features/html-render/index.d.ts +3 -18
- package/lib/node/features/html-render/index.js +87 -16
- package/lib/node/features/{main → html-render/lib}/buildHtml.d.ts +0 -0
- package/lib/node/features/{main → html-render/lib}/buildHtml.js +0 -0
- package/lib/node/features/html-render/lib/generateFilesByRoutId.d.ts +2 -2
- package/lib/node/features/html-render/lib/generateFilesByRoutId.js +3 -3
- package/lib/node/features/{main → html-render/lib}/generateResource.d.ts +0 -0
- package/lib/node/features/{main → html-render/lib}/generateResource.js +0 -0
- package/lib/node/features/html-render/lib/getPageMiddleware.d.ts +2 -2
- package/lib/node/features/html-render/lib/index.d.ts +0 -1
- package/lib/node/features/html-render/lib/index.js +1 -3
- package/lib/node/features/html-render/lib/renderToHTML.d.ts +2 -2
- package/lib/node/features/html-render/lib/renderToHTML.js +7 -48
- package/lib/node/features/html-render/lib/renderer/base.d.ts +6 -6
- package/lib/node/features/html-render/lib/renderer/base.js +5 -5
- package/lib/node/features/html-render/lib/renderer/index.d.ts +5 -4
- package/lib/node/features/html-render/lib/renderer/index.js +69 -6
- package/lib/node/features/html-render/lib/renderer/spa.d.ts +2 -2
- package/lib/node/features/html-render/lib/renderer/spa.js +4 -6
- package/lib/node/features/html-render/lib/renderer/ssr.d.ts +2 -2
- package/lib/node/features/html-render/lib/renderer/ssr.js +5 -6
- package/lib/node/features/html-render/lib/renderer/types.d.ts +8 -5
- package/lib/node/features/html-render/server.d.ts +1 -1
- package/lib/node/features/index.d.ts +3 -31
- package/lib/node/features/index.js +6 -7
- package/lib/node/features/model/index.d.ts +1 -13
- package/lib/node/features/model/runtime.d.ts +3 -8
- package/lib/node/features/model/runtime.js +13 -17
- package/lib/node/features/model/server.js +2 -3
- package/lib/node/features/model/shuvi-app.d.ts +2 -2
- package/lib/node/features/on-demand-compile-page/index.d.ts +3 -13
- package/lib/node/features/on-demand-compile-page/index.js +4 -1
- package/lib/node/features/on-demand-compile-page/onDemandRouteManager.d.ts +3 -3
- package/lib/node/features/on-demand-compile-page/onDemandRouteManager.js +2 -4
- package/lib/node/index.js +1 -3
- package/lib/node/paths.js +0 -2
- package/lib/node/shuvi-runtime-server.d.ts +18 -0
- package/lib/node/shuvi-runtime-server.js +2 -0
- package/lib/node/shuvi-type-extensions-node.d.ts +2 -6
- package/lib/node/targets/react/bundler/index.d.ts +1 -13
- package/lib/node/targets/react/bundler/index.js +5 -0
- package/lib/node/targets/react/index.d.ts +2 -26
- package/lib/node/targets/react/index.js +2 -2
- package/lib/node/targets/react/model/index.d.ts +6 -0
- package/lib/node/targets/react/{redox-react → model}/index.js +7 -6
- package/lib/shared/appTypes.d.ts +5 -3
- package/lib/shared/renderTypes.d.ts +6 -5
- package/lib/shared/routeTypes.d.ts +4 -9
- package/package.json +20 -15
- package/shuvi-env.d.ts +10 -0
- package/shuvi-image.d.ts +54 -0
- package/shuvi-type-extensions-node.js +1 -0
- package/shuvi-type-extensions-runtime.d.ts +2 -2
- package/esm/shuvi-app/dev/webpackHotDevClient.d.ts +0 -5
- package/esm/shuvi-app/dev/webpackHotDevClient.js +0 -34
- package/esm/shuvi-app/react/redox-react/runtime.d.ts +0 -2
- package/esm/shuvi-app/shuvi-runtime-server.d.ts +0 -6
- package/esm/shuvi-app/shuvi-runtime-server.js +0 -1
- package/lib/node/features/main/index.d.ts +0 -3
- package/lib/node/features/main/index.js +0 -82
- 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
|
+
}
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
6
|
-
|
|
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
|
|
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
|
-
|
|
7
|
-
|
|
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,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({
|
|
3
|
+
export default function AppContainer({ app, children }: React.PropsWithChildren<{
|
|
4
4
|
app: IApplication;
|
|
5
|
-
|
|
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
|
-
|
|
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({
|
|
14
|
+
export default function AppContainer({ app, children }) {
|
|
16
15
|
return (<ErrorBoundary>
|
|
17
16
|
<AppProvider app={app}>
|
|
18
|
-
<Provider
|
|
17
|
+
<Provider store={app.store}>
|
|
19
18
|
<ErrorGuard>{children}</ErrorGuard>
|
|
20
19
|
</Provider>
|
|
21
20
|
</AppProvider>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { IPageRouteRecord
|
|
2
|
-
export default function getRoutes(routes:
|
|
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 {
|
|
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 (
|
|
22
|
-
route.component = loadRouteComponent(__import__, {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
});
|
|
20
|
+
if (__import__) {
|
|
21
|
+
route.component = loadRouteComponent(__import__, Object.assign({ webpack: __resolveWeak__ }, (__componentRawRequest__ && {
|
|
22
|
+
modules: [__componentRawRequest__]
|
|
23
|
+
})));
|
|
26
24
|
}
|
|
27
|
-
|
|
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 {
|
|
2
|
+
import type { RedoxStore } from '@shuvi/redox';
|
|
3
3
|
export declare const RedoxWrapper: (App: any, appContext: {
|
|
4
|
-
|
|
4
|
+
store: RedoxStore;
|
|
5
5
|
}) => {
|
|
6
|
-
(
|
|
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(
|
|
5
|
-
return (<RedoxRoot
|
|
6
|
-
<App
|
|
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 {
|
|
10
|
+
import { createRuntimePluginAfter } from '@shuvi/platform-shared/shared';
|
|
11
11
|
import { RedoxWrapper } from './RedoxWrapper';
|
|
12
|
-
|
|
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,
|
|
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 };
|
|
@@ -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 {
|
|
3
|
-
import {
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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,
|
|
22
|
+
this.renderApp = ({ req, app, manifest, isDev }) => __awaiter(this, void 0, void 0, function* () {
|
|
21
23
|
yield Loadable.preloadAll();
|
|
22
|
-
const {
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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 {
|
|
1
|
+
import { ShuviRequestHandler } from '@shuvi/service';
|
|
2
2
|
import { IApiRequestHandler } from '../shared';
|
|
3
|
-
export declare type
|
|
4
|
-
export declare type
|
|
3
|
+
export declare type ShuviMiddlewareHandler = ShuviRequestHandler;
|
|
4
|
+
export declare type ShuviApiHandler = IApiRequestHandler;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// exported by @shuvi/
|
|
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").
|
|
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").
|
|
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 {
|
|
3
|
+
import { ShuviRequest, ShuviResponse } from '@shuvi/service';
|
|
4
4
|
import { IApiRequestHandler, IApiResponse } from '../../../../shared';
|
|
5
5
|
export { IApiRequestHandler };
|
|
6
|
-
export declare function apiRouteHandler(req:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
};
|