@shuvi/platform-web 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/shared/routeTypes.d.ts +0 -3
- package/esm/shuvi-app/app/client.js +11 -1
- package/esm/shuvi-app/app/server.js +12 -2
- package/esm/shuvi-app/helper/isThirdSite.d.ts +2 -0
- package/esm/shuvi-app/helper/isThirdSite.js +5 -0
- package/esm/shuvi-app/react/AppContainer.jsx +4 -4
- package/esm/shuvi-app/react/view/ReactView.server.jsx +6 -2
- package/lib/node/features/custom-server/server.js +4 -0
- package/lib/node/features/filesystem-routes/api/apiRouteHandler.d.ts +0 -9
- package/lib/node/features/filesystem-routes/api/apiRouteHandler.js +2 -18
- package/lib/node/features/html-render/lib/getPageMiddleware.js +19 -2
- package/lib/node/features/html-render/serverHooks.d.ts +8 -2
- package/lib/node/features/html-render/serverHooks.js +4 -2
- package/lib/node/shuvi-runtime-server.d.ts +3 -0
- package/lib/shared/routeTypes.d.ts +0 -3
- package/package.json +13 -15
|
@@ -15,6 +15,7 @@ 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
17
|
import { serializeServerError } from '../helper/serializeServerError';
|
|
18
|
+
import isThirdSite from '../helper/isThirdSite';
|
|
18
19
|
let app;
|
|
19
20
|
export const createApp = ({ routes, appData, appComponent }) => {
|
|
20
21
|
// app is a singleton in client side
|
|
@@ -98,7 +99,16 @@ export const createApp = ({ routes, appData, appComponent }) => {
|
|
|
98
99
|
}
|
|
99
100
|
catch (error) {
|
|
100
101
|
if (isRedirect(error)) {
|
|
101
|
-
|
|
102
|
+
const location = error.headers.get('Location');
|
|
103
|
+
if (isThirdSite(location)) {
|
|
104
|
+
window.location.replace(location);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
next({
|
|
108
|
+
path: location,
|
|
109
|
+
replace: true
|
|
110
|
+
});
|
|
111
|
+
}
|
|
102
112
|
return;
|
|
103
113
|
}
|
|
104
114
|
if (isResponse(error) && error.status >= 400 && error.status < 600) {
|
|
@@ -12,7 +12,7 @@ import { getRoutes, app as AppComponent } from '@shuvi/app/core/platform';
|
|
|
12
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
|
-
import { createRouter, createMemoryHistory } from '@shuvi/router';
|
|
15
|
+
import { createRouter, createMemoryHistory, pathToString } from '@shuvi/router';
|
|
16
16
|
import logger from '@shuvi/utils/lib/logger';
|
|
17
17
|
import { serializeServerError } from '../helper/serializeServerError';
|
|
18
18
|
export const createApp = options => {
|
|
@@ -39,7 +39,17 @@ export const createApp = options => {
|
|
|
39
39
|
}
|
|
40
40
|
catch (error) {
|
|
41
41
|
if (isRedirect(error)) {
|
|
42
|
-
|
|
42
|
+
const location = error.headers.get('Location');
|
|
43
|
+
const status = error.status;
|
|
44
|
+
next({
|
|
45
|
+
path: pathToString(to),
|
|
46
|
+
replace: true,
|
|
47
|
+
skipGuards: true,
|
|
48
|
+
state: {
|
|
49
|
+
location,
|
|
50
|
+
status
|
|
51
|
+
}
|
|
52
|
+
});
|
|
43
53
|
return;
|
|
44
54
|
}
|
|
45
55
|
if (isResponse(error) && error.status >= 400 && error.status < 600) {
|
|
@@ -12,11 +12,11 @@ function ErrorGuard({ children = null }) {
|
|
|
12
12
|
return <>{children}</>;
|
|
13
13
|
}
|
|
14
14
|
export default function AppContainer({ app, children }) {
|
|
15
|
-
return (<
|
|
16
|
-
<
|
|
15
|
+
return (<AppProvider app={app}>
|
|
16
|
+
<ErrorBoundary>
|
|
17
17
|
<Provider store={app.store}>
|
|
18
18
|
<ErrorGuard>{children}</ErrorGuard>
|
|
19
19
|
</Provider>
|
|
20
|
-
</
|
|
21
|
-
</
|
|
20
|
+
</ErrorBoundary>
|
|
21
|
+
</AppProvider>);
|
|
22
22
|
}
|
|
@@ -17,6 +17,7 @@ import Loadable, { LoadableContext } from '../loadable';
|
|
|
17
17
|
import AppContainer from '../AppContainer';
|
|
18
18
|
import { Head } from '../head';
|
|
19
19
|
import { serializeServerError } from '../../helper/serializeServerError';
|
|
20
|
+
import isThirdSite from '../../helper/isThirdSite';
|
|
20
21
|
export class ReactServerView {
|
|
21
22
|
constructor() {
|
|
22
23
|
this.renderApp = ({ req, app, manifest }) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -24,13 +25,16 @@ export class ReactServerView {
|
|
|
24
25
|
const { router, appComponent: AppComponent, setError: setAppError } = app;
|
|
25
26
|
yield router.ready;
|
|
26
27
|
// todo: move these into renderer
|
|
27
|
-
let {
|
|
28
|
+
let { matches, redirected, state, pathname } = router.current;
|
|
28
29
|
// handler no matches
|
|
29
30
|
if (!matches.length) {
|
|
30
31
|
setAppError(SHUVI_ERROR.PAGE_NOT_FOUND);
|
|
31
32
|
}
|
|
32
33
|
if (redirected) {
|
|
33
|
-
|
|
34
|
+
const { location, status } = state;
|
|
35
|
+
return redirect(isThirdSite(location)
|
|
36
|
+
? location
|
|
37
|
+
: router.resolve(location, pathname).href, status);
|
|
34
38
|
}
|
|
35
39
|
const loadableModules = [];
|
|
36
40
|
let htmlContent = undefined;
|
|
@@ -33,5 +33,9 @@ exports.default = (0, service_1.createServerPlugin)({
|
|
|
33
33
|
modifyHtml: (document, context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
34
|
var _a, _b, _c;
|
|
35
35
|
yield ((_c = (_b = (_a = resources_1.default.server) === null || _a === void 0 ? void 0 : _a.server) === null || _b === void 0 ? void 0 : _b.modifyHtml) === null || _c === void 0 ? void 0 : _c.call(_b, document, context));
|
|
36
|
+
}),
|
|
37
|
+
sendHtml: (originalSendHtml) => __awaiter(void 0, void 0, void 0, function* () {
|
|
38
|
+
var _d, _e;
|
|
39
|
+
return (((_e = (_d = resources_1.default.server.server) === null || _d === void 0 ? void 0 : _d.sendHtml) === null || _e === void 0 ? void 0 : _e.call(_d, originalSendHtml)) || originalSendHtml);
|
|
36
40
|
})
|
|
37
41
|
});
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { IncomingMessage } from 'http';
|
|
3
1
|
import { ShuviRequest, ShuviResponse } from '@shuvi/service';
|
|
4
2
|
import { IApiRequestHandler, IApiResponse } from '../../../../shared';
|
|
5
3
|
export { IApiRequestHandler };
|
|
@@ -9,13 +7,6 @@ export declare function apiRouteHandler(req: ShuviRequest, res: ShuviResponse, r
|
|
|
9
7
|
* @param req request object
|
|
10
8
|
*/
|
|
11
9
|
export declare function parseBody(req: ShuviRequest, limit: string | number): Promise<any>;
|
|
12
|
-
/**
|
|
13
|
-
* Parse cookies from `req` header
|
|
14
|
-
* @param req request object
|
|
15
|
-
*/
|
|
16
|
-
export declare function getCookieParser(req: IncomingMessage): {
|
|
17
|
-
[key: string]: string;
|
|
18
|
-
};
|
|
19
10
|
/**
|
|
20
11
|
*
|
|
21
12
|
* @param res ServerResponse object
|
|
@@ -35,10 +35,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
36
|
};
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.ApiError = exports.sendJson = exports.sendData = exports.redirect = exports.sendStatusCode = exports.
|
|
38
|
+
exports.ApiError = exports.sendJson = exports.sendData = exports.redirect = exports.sendStatusCode = exports.parseBody = exports.apiRouteHandler = void 0;
|
|
39
39
|
const stream_1 = require("stream");
|
|
40
40
|
const querystring = __importStar(require("querystring"));
|
|
41
|
-
const cookie = __importStar(require("cookie"));
|
|
42
41
|
const getRawBody = require('raw-body');
|
|
43
42
|
const contentType = __importStar(require("content-type"));
|
|
44
43
|
const logger_1 = __importDefault(require("@shuvi/utils/lib/logger"));
|
|
@@ -46,10 +45,7 @@ function apiRouteHandler(req, res, resolver, apiRoutesConfig) {
|
|
|
46
45
|
return __awaiter(this, void 0, void 0, function* () {
|
|
47
46
|
try {
|
|
48
47
|
const { bodyParser } = apiRoutesConfig || {};
|
|
49
|
-
const apiReq = {
|
|
50
|
-
// Parsing of cookies
|
|
51
|
-
cookies: getCookieParser(req)
|
|
52
|
-
};
|
|
48
|
+
const apiReq = {};
|
|
53
49
|
// Parsing of body
|
|
54
50
|
if (bodyParser && !apiReq.body) {
|
|
55
51
|
apiReq.body = yield parseBody(req, bodyParser && bodyParser.sizeLimit ? bodyParser.sizeLimit : '1mb');
|
|
@@ -135,18 +131,6 @@ function parseJson(str) {
|
|
|
135
131
|
throw new ApiError(400, 'Invalid JSON');
|
|
136
132
|
}
|
|
137
133
|
}
|
|
138
|
-
/**
|
|
139
|
-
* Parse cookies from `req` header
|
|
140
|
-
* @param req request object
|
|
141
|
-
*/
|
|
142
|
-
function getCookieParser(req) {
|
|
143
|
-
const header = req.headers.cookie;
|
|
144
|
-
if (!header) {
|
|
145
|
-
return {};
|
|
146
|
-
}
|
|
147
|
-
return cookie.parse(Array.isArray(header) ? header.join(';') : header);
|
|
148
|
-
}
|
|
149
|
-
exports.getCookieParser = getCookieParser;
|
|
150
134
|
/**
|
|
151
135
|
*
|
|
152
136
|
* @param res ServerResponse object
|
|
@@ -14,6 +14,11 @@ const utils_1 = require("@shuvi/service/lib/server/utils");
|
|
|
14
14
|
const shared_1 = require("@shuvi/platform-shared/shared");
|
|
15
15
|
const renderToHTML_1 = require("./renderToHTML");
|
|
16
16
|
function createPageHandler(serverPluginContext) {
|
|
17
|
+
const wrappedSendHtml = (html, { req, res }) => __awaiter(this, void 0, void 0, function* () {
|
|
18
|
+
(0, utils_1.sendHTML)(req, res, html);
|
|
19
|
+
});
|
|
20
|
+
let sendHtml;
|
|
21
|
+
let pendingSendHtml;
|
|
17
22
|
return function (req, res) {
|
|
18
23
|
return __awaiter(this, void 0, void 0, function* () {
|
|
19
24
|
const result = yield (0, renderToHTML_1.renderToHTML)({
|
|
@@ -30,7 +35,14 @@ function createPageHandler(serverPluginContext) {
|
|
|
30
35
|
else if ((0, shared_1.isText)(result)) {
|
|
31
36
|
const textResp = result;
|
|
32
37
|
res.statusCode = textResp.status;
|
|
33
|
-
(
|
|
38
|
+
if (!sendHtml) {
|
|
39
|
+
if (!pendingSendHtml) {
|
|
40
|
+
pendingSendHtml =
|
|
41
|
+
serverPluginContext.serverPluginRunner.sendHtml(wrappedSendHtml);
|
|
42
|
+
}
|
|
43
|
+
sendHtml = yield pendingSendHtml;
|
|
44
|
+
}
|
|
45
|
+
yield sendHtml(textResp.data, { req, res });
|
|
34
46
|
}
|
|
35
47
|
else {
|
|
36
48
|
// shuold never reach here
|
|
@@ -43,10 +55,15 @@ function getPageMiddleware(api) {
|
|
|
43
55
|
return __awaiter(this, void 0, void 0, function* () {
|
|
44
56
|
const defaultPageHandler = createPageHandler(api);
|
|
45
57
|
let pageHandler;
|
|
58
|
+
let pendingPageHandler;
|
|
46
59
|
return function (req, res, next) {
|
|
47
60
|
return __awaiter(this, void 0, void 0, function* () {
|
|
48
61
|
if (!pageHandler) {
|
|
49
|
-
|
|
62
|
+
if (!pendingPageHandler) {
|
|
63
|
+
pendingPageHandler =
|
|
64
|
+
api.serverPluginRunner.handlePageRequest(defaultPageHandler);
|
|
65
|
+
}
|
|
66
|
+
pageHandler = yield pendingPageHandler;
|
|
50
67
|
}
|
|
51
68
|
try {
|
|
52
69
|
yield pageHandler(req, res);
|
|
@@ -7,9 +7,15 @@ export interface ModifyHtmlContext {
|
|
|
7
7
|
req: ShuviRequest;
|
|
8
8
|
appContext: IAppContext;
|
|
9
9
|
}
|
|
10
|
-
export declare type IHandlePageRequest = (req: IncomingMessage, res: ServerResponse) =>
|
|
10
|
+
export declare type IHandlePageRequest = (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
11
|
+
export declare type RequestContext = {
|
|
12
|
+
req: IncomingMessage;
|
|
13
|
+
res: ServerResponse;
|
|
14
|
+
};
|
|
15
|
+
export declare type ISendHtml = (html: string, requestContext: RequestContext) => Promise<void>;
|
|
11
16
|
export declare const extendedHooks: {
|
|
12
17
|
getPageData: import("@shuvi/hook").AsyncParallelHook<void, IAppContext, Record<string, unknown>>;
|
|
13
|
-
handlePageRequest: import("@shuvi/hook").
|
|
18
|
+
handlePageRequest: import("@shuvi/hook").AsyncSeriesWaterfallHook<IHandlePageRequest, void>;
|
|
14
19
|
modifyHtml: import("@shuvi/hook").AsyncSeriesHook<IHtmlDocument, ModifyHtmlContext, void>;
|
|
20
|
+
sendHtml: import("@shuvi/hook").AsyncSeriesWaterfallHook<ISendHtml, void>;
|
|
15
21
|
};
|
|
@@ -3,10 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.extendedHooks = void 0;
|
|
4
4
|
const hook_1 = require("@shuvi/hook");
|
|
5
5
|
const getPageData = (0, hook_1.createAsyncParallelHook)();
|
|
6
|
-
const handlePageRequest = (0, hook_1.
|
|
6
|
+
const handlePageRequest = (0, hook_1.createAsyncSeriesWaterfallHook)();
|
|
7
7
|
const modifyHtml = (0, hook_1.createAsyncSeriesHook)();
|
|
8
|
+
const sendHtml = (0, hook_1.createAsyncSeriesWaterfallHook)();
|
|
8
9
|
exports.extendedHooks = {
|
|
9
10
|
getPageData,
|
|
10
11
|
handlePageRequest,
|
|
11
|
-
modifyHtml
|
|
12
|
+
modifyHtml,
|
|
13
|
+
sendHtml
|
|
12
14
|
};
|
|
@@ -7,6 +7,7 @@ declare global {
|
|
|
7
7
|
getPageData: typeof extendedHooks.getPageData;
|
|
8
8
|
handlePageRequest: typeof extendedHooks.handlePageRequest;
|
|
9
9
|
modifyHtml: typeof extendedHooks.modifyHtml;
|
|
10
|
+
sendHtml: typeof extendedHooks.sendHtml;
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
13
|
}
|
|
@@ -18,9 +19,11 @@ export declare type ShuviApiHandler = IApiRequestHandler;
|
|
|
18
19
|
export declare type GetPageDataFunction = RemoveLast<ServerPluginConstructor['getPageData']>;
|
|
19
20
|
export declare type HandlePageRequestFunction = RemoveLast<ServerPluginConstructor['handlePageRequest']>;
|
|
20
21
|
export declare type ModifyHtmlFunction = RemoveLast<ServerPluginConstructor['modifyHtml']>;
|
|
22
|
+
export declare type SendHtmlFunction = RemoveLast<ServerPluginConstructor['sendHtml']>;
|
|
21
23
|
export interface IServerModule {
|
|
22
24
|
getPageData?: GetPageDataFunction;
|
|
23
25
|
handlePageRequest?: HandlePageRequestFunction;
|
|
24
26
|
modifyHtml?: ModifyHtmlFunction;
|
|
27
|
+
sendHtml?: SendHtmlFunction;
|
|
25
28
|
}
|
|
26
29
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shuvi/platform-web",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/shuvijs/shuvi.git",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
53
|
"./shuvi-type-extensions-node": {
|
|
54
|
-
"types": "./shuvi-type-extensions-node.d.
|
|
54
|
+
"types": "./shuvi-type-extensions-node.d.ts",
|
|
55
55
|
"default": "./shuvi-type-extensions-node.js"
|
|
56
56
|
},
|
|
57
57
|
"./shuvi-type-extensions-runtime": "./shuvi-type-extensions-runtime.d.ts",
|
|
@@ -72,20 +72,19 @@
|
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"@next/react-refresh-utils": "12.1.6",
|
|
75
|
-
"@shuvi/error-overlay": "1.0.
|
|
76
|
-
"@shuvi/hook": "1.0.
|
|
77
|
-
"@shuvi/platform-shared": "1.0.
|
|
75
|
+
"@shuvi/error-overlay": "1.0.2",
|
|
76
|
+
"@shuvi/hook": "1.0.2",
|
|
77
|
+
"@shuvi/platform-shared": "1.0.2",
|
|
78
78
|
"@shuvi/redox": "0.0.7",
|
|
79
79
|
"@shuvi/redox-react": "0.0.7",
|
|
80
|
-
"@shuvi/router": "1.0.
|
|
81
|
-
"@shuvi/router-react": "1.0.
|
|
82
|
-
"@shuvi/runtime": "1.0.
|
|
83
|
-
"@shuvi/service": "1.0.
|
|
84
|
-
"@shuvi/shared": "1.0.
|
|
85
|
-
"@shuvi/toolpack": "1.0.
|
|
86
|
-
"@shuvi/utils": "1.0.
|
|
80
|
+
"@shuvi/router": "1.0.2",
|
|
81
|
+
"@shuvi/router-react": "1.0.2",
|
|
82
|
+
"@shuvi/runtime": "1.0.2",
|
|
83
|
+
"@shuvi/service": "1.0.2",
|
|
84
|
+
"@shuvi/shared": "1.0.2",
|
|
85
|
+
"@shuvi/toolpack": "1.0.2",
|
|
86
|
+
"@shuvi/utils": "1.0.2",
|
|
87
87
|
"content-type": "1.0.4",
|
|
88
|
-
"cookie": "0.4.1",
|
|
89
88
|
"core-js": "3.6.5",
|
|
90
89
|
"ejs": "3.1.5",
|
|
91
90
|
"fs-extra": "9.0.1",
|
|
@@ -100,12 +99,11 @@
|
|
|
100
99
|
"whatwg-fetch": "3.0.0"
|
|
101
100
|
},
|
|
102
101
|
"peerDependencies": {
|
|
103
|
-
"@shuvi/service": "1.0.
|
|
102
|
+
"@shuvi/service": "1.0.2"
|
|
104
103
|
},
|
|
105
104
|
"devDependencies": {
|
|
106
105
|
"@testing-library/react": "^13.2.0",
|
|
107
106
|
"@types/content-type": "^1.1.5",
|
|
108
|
-
"@types/cookie": "^0.4.1",
|
|
109
107
|
"@types/ejs": "^3.1.0",
|
|
110
108
|
"@types/raw-body": "^2.3.0",
|
|
111
109
|
"@types/react": "18.0.9",
|