@shuvi/platform-web 1.0.1 → 1.0.3
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/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/html-render/index.js +1 -4
- 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/package.json +12 -12
|
@@ -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
|
});
|
|
@@ -14,7 +14,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.getPlugin = exports.getPageMiddleware = void 0;
|
|
16
16
|
const service_1 = require("@shuvi/service");
|
|
17
|
-
const config_1 = require("@shuvi/toolpack/lib/webpack/config");
|
|
18
17
|
const copy_file_plugin_1 = require("@shuvi/toolpack/lib/webpack/plugins/copy-file-plugin");
|
|
19
18
|
const shared_1 = require("../../../shared");
|
|
20
19
|
const paths_1 = require("../../paths");
|
|
@@ -89,13 +88,11 @@ const getPlugin = (platformContext) => {
|
|
|
89
88
|
return chain;
|
|
90
89
|
},
|
|
91
90
|
addExtraTarget: ({ createConfig }, context) => {
|
|
92
|
-
const serverWebpackHelpers = (0, config_1.webpackHelpers)();
|
|
93
91
|
const serverChain = createConfig({
|
|
94
92
|
name: shared_1.BUNDLER_TARGET_SERVER,
|
|
95
93
|
node: true,
|
|
96
94
|
entry: getServerEntry(),
|
|
97
|
-
outputDir: shared_1.SERVER_OUTPUT_DIR
|
|
98
|
-
webpackHelpers: serverWebpackHelpers
|
|
95
|
+
outputDir: shared_1.SERVER_OUTPUT_DIR
|
|
99
96
|
});
|
|
100
97
|
return {
|
|
101
98
|
name: shared_1.BUNDLER_TARGET_SERVER,
|
|
@@ -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.3",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/shuvijs/shuvi.git",
|
|
@@ -72,18 +72,17 @@
|
|
|
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.3",
|
|
76
|
+
"@shuvi/hook": "1.0.3",
|
|
77
|
+
"@shuvi/platform-shared": "1.0.3",
|
|
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/
|
|
84
|
-
"@shuvi/
|
|
85
|
-
"@shuvi/
|
|
86
|
-
"@shuvi/utils": "1.0.1",
|
|
80
|
+
"@shuvi/router": "1.0.3",
|
|
81
|
+
"@shuvi/router-react": "1.0.3",
|
|
82
|
+
"@shuvi/runtime": "1.0.3",
|
|
83
|
+
"@shuvi/shared": "1.0.3",
|
|
84
|
+
"@shuvi/toolpack": "1.0.3",
|
|
85
|
+
"@shuvi/utils": "1.0.3",
|
|
87
86
|
"content-type": "1.0.4",
|
|
88
87
|
"core-js": "3.6.5",
|
|
89
88
|
"ejs": "3.1.5",
|
|
@@ -99,9 +98,10 @@
|
|
|
99
98
|
"whatwg-fetch": "3.0.0"
|
|
100
99
|
},
|
|
101
100
|
"peerDependencies": {
|
|
102
|
-
"@shuvi/service": "1.0.
|
|
101
|
+
"@shuvi/service": "1.0.3"
|
|
103
102
|
},
|
|
104
103
|
"devDependencies": {
|
|
104
|
+
"@shuvi/service": "workspace:*",
|
|
105
105
|
"@testing-library/react": "^13.2.0",
|
|
106
106
|
"@types/content-type": "^1.1.5",
|
|
107
107
|
"@types/ejs": "^3.1.0",
|