@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.
@@ -1,8 +1,5 @@
1
1
  import { ShuviRequest, ShuviResponse, ShuviRequestHandler } from '@shuvi/service';
2
2
  export interface IApiReq {
3
- cookies: {
4
- [key: string]: string;
5
- };
6
3
  body?: {
7
4
  [key: string]: any;
8
5
  };
@@ -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
- next(error.headers.get('Location'));
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
- next(error.headers.get('Location'));
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) {
@@ -0,0 +1,2 @@
1
+ declare function isThirdSite(url: string): boolean;
2
+ export default isThirdSite;
@@ -0,0 +1,5 @@
1
+ const THIRD_SITE_REG = /^http(s?)\:\/\//;
2
+ function isThirdSite(url) {
3
+ return THIRD_SITE_REG.test(url);
4
+ }
5
+ export default isThirdSite;
@@ -12,11 +12,11 @@ function ErrorGuard({ children = null }) {
12
12
  return <>{children}</>;
13
13
  }
14
14
  export default function AppContainer({ app, children }) {
15
- return (<ErrorBoundary>
16
- <AppProvider app={app}>
15
+ return (<AppProvider app={app}>
16
+ <ErrorBoundary>
17
17
  <Provider store={app.store}>
18
18
  <ErrorGuard>{children}</ErrorGuard>
19
19
  </Provider>
20
- </AppProvider>
21
- </ErrorBoundary>);
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 { pathname, matches, redirected } = router.current;
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
- return redirect(pathname);
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.getCookieParser = exports.parseBody = exports.apiRouteHandler = void 0;
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
- (0, utils_1.sendHTML)(req, res, textResp.data);
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
- pageHandler = yield api.serverPluginRunner.handlePageRequest(defaultPageHandler);
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) => any;
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").SyncWaterfallHook<IHandlePageRequest, void>;
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.createSyncWaterfallHook)();
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 {};
@@ -1,8 +1,5 @@
1
1
  import { ShuviRequest, ShuviResponse, ShuviRequestHandler } from '@shuvi/service';
2
2
  export interface IApiReq {
3
- cookies: {
4
- [key: string]: string;
5
- };
6
3
  body?: {
7
4
  [key: string]: any;
8
5
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shuvi/platform-web",
3
- "version": "1.0.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.js",
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.0",
76
- "@shuvi/hook": "1.0.0",
77
- "@shuvi/platform-shared": "1.0.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.0",
81
- "@shuvi/router-react": "1.0.0",
82
- "@shuvi/runtime": "1.0.0",
83
- "@shuvi/service": "1.0.0",
84
- "@shuvi/shared": "1.0.0",
85
- "@shuvi/toolpack": "1.0.0",
86
- "@shuvi/utils": "1.0.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.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",