Skip to content

Commit

Permalink
#38
Browse files Browse the repository at this point in the history
- deps: добавлен accepts (patch)
- preset/server: перенесена часть провайдеров из preset/node (patch)
- preset/server: добавлен провайдер функции рендера jsx в строку (patch)
- preset/server: добавлен провайдер обьекта событий ответа (patch)
- preset/server: добавлен провайдер формформаттера ответа на запрос страницы (patch)
- preset/node-handler: добавлен провайдер событий ответа (patch)
- preset/node-handler: провайдер main декомпозирован (patch)
- preset/bun-handler: добавлен провайдер событий ответа (patch)
- preset/bun-handler: провайдер main декомпозирован (patch)
  • Loading branch information
krutoo committed Mar 21, 2024
1 parent f2d9e98 commit 3fd96ef
Show file tree
Hide file tree
Showing 21 changed files with 253 additions and 191 deletions.
22 changes: 21 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"author": "www.sima-land.ru team",
"license": "Apache-2.0",
"engines": {
"node": ">=16.15.1"
"node": ">=18.0.0"
},
"scripts": {
"prepare": "husky install",
Expand All @@ -27,6 +27,7 @@
"@babel/preset-typescript": "^7.22.5",
"@sima-land/linters": "^4.0.0",
"@testing-library/react": "^14.0.0",
"@types/accepts": "^1.3.7",
"@types/express": "^4.17.17",
"@types/jest": "^28.1.7",
"@types/jsesc": "^3.0.1",
Expand Down Expand Up @@ -59,6 +60,7 @@
"@sentry/browser": "^7.81.0",
"@sentry/bun": "^7.81.0",
"@sentry/node": "^7.81.0",
"accepts": "^1.3.8",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"jsesc": "^3.0.2",
Expand Down
14 changes: 11 additions & 3 deletions src/preset/bun-handler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import { PresetTuner } from '../isomorphic';
import { provideAbortController } from '../isomorphic/providers/abort-controller';
import { provideFetch } from '../isomorphic/providers/fetch';
import { provideReduxMiddlewareSaga } from '../isomorphic/providers/redux-middleware-saga';
import { providePageRender } from '../node-handler/providers/page-render';
import { provideFetchLogHandler } from './providers/fetch-log-handler';
import { providePageRender } from '../server/providers/page-render';
import { provideFetchLogHandler } from '../server/providers/fetch-log-handler';
import { provideFetchMiddleware } from './providers/fetch-middleware';
import { provideHandlerMain } from './providers/handler-main';
import { providePageHelmet } from './providers/page-helmet';
import { providePageHelmet } from '../server/providers/page-helmet';
import { provideSpecificParams } from './providers/specific-params';
import { provideCookieStore } from './providers/cookie-store';
import { SpecificExtras } from '../server/utils/specific-extras';
import { provideElementToString } from '../server/providers/element-to-string';
import { provideFormatPageResponse } from '../server/providers/format-page-response';
import { provideAcceptType } from './providers/accept-type';
import { provideResponseEvents } from '../server/providers/response-events';

/**
* Возвращает preset с зависимостями для формирования обработчика входящего http-запроса.
Expand All @@ -32,11 +36,15 @@ export function PresetBunHandler(customize?: PresetTuner) {

// handler
preset.set(KnownToken.Http.Handler.main, provideHandlerMain);
preset.set(KnownToken.Http.Handler.Request.acceptType, provideAcceptType);
preset.set(KnownToken.Http.Handler.Request.specificParams, provideSpecificParams);
preset.set(KnownToken.Http.Handler.Response.events, provideResponseEvents);
preset.set(KnownToken.Http.Handler.Response.specificExtras, () => new SpecificExtras());
preset.set(KnownToken.Http.Handler.Page.assets, () => ({ js: '', css: '' }));
preset.set(KnownToken.Http.Handler.Page.helmet, providePageHelmet);
preset.set(KnownToken.Http.Handler.Page.render, providePageRender);
preset.set(KnownToken.Http.Handler.Page.elementToString, provideElementToString);
preset.set(KnownToken.Http.Handler.Page.formatResponse, provideFormatPageResponse);

// redux saga
preset.set(KnownToken.Redux.Middleware.saga, provideReduxMiddlewareSaga);
Expand Down
19 changes: 19 additions & 0 deletions src/preset/bun-handler/providers/accept-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Resolve } from '../../../di';
import { KnownToken } from '../../../tokens';
import accepts from 'accepts';

/**
* Провайдер функции, которая определяет возможные типы ответа и их приоритет.
* @param resolve Resolve.
* @return Функция.
*/
export function provideAcceptType(resolve: Resolve) {
const context = resolve(KnownToken.Http.Handler.context);

// @todo опасное место, будем решать как исправлять по итогам https://github.com/jshttp/accepts/issues/30
const accept = accepts({
headers: Object.fromEntries(context.request.headers.entries()),
} as any);

return accept.type.bind(accept);
}
22 changes: 0 additions & 22 deletions src/preset/bun-handler/providers/fetch-log-handler.ts

This file was deleted.

101 changes: 25 additions & 76 deletions src/preset/bun-handler/providers/handler-main.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
/* eslint-disable require-jsdoc, jsdoc/require-jsdoc */
import { renderToString } from 'react-dom/server';
import { Resolve } from '../../../di';
import { KnownToken } from '../../../tokens';
import { ResponseError, applyMiddleware } from '../../../http';
import { PageAssets } from '../../isomorphic/types';
import { PAGE_HANDLER_EVENT_TYPE } from '../../server/constants';
import { getPageResponseFormat } from '../../server/utils/get-page-response-format';
import { HelmetContext } from '../../server/utils/regular-helmet';
import { LogLevel } from '../../../log';

export function provideHandlerMain(resolve: Resolve) {
const config = resolve(KnownToken.Config.base);
Expand All @@ -16,7 +13,7 @@ export function provideHandlerMain(resolve: Resolve) {
const extras = resolve(KnownToken.Http.Handler.Response.specificExtras);
const Helmet = resolve(KnownToken.Http.Handler.Page.helmet);
const abortController = resolve(KnownToken.Http.Fetch.abortController);
const context = resolve(KnownToken.Http.Handler.context);
const formatResponse = resolve(KnownToken.Http.Handler.Page.formatResponse);

// @todo https://github.com/sima-land/isomorph/issues/69
// const cookieStore = resolve(KnownToken.Http.Fetch.cookieStore);
Expand All @@ -27,65 +24,7 @@ export function provideHandlerMain(resolve: Resolve) {

const getAssets = typeof assetsInit === 'function' ? assetsInit : () => assetsInit;

const elementToString = (element: JSX.Element) => {
context.events.dispatchEvent(new Event(PAGE_HANDLER_EVENT_TYPE.renderStart));
const result = renderToString(element);
context.events.dispatchEvent(new Event(PAGE_HANDLER_EVENT_TYPE.renderFinish));

return result;
};

const getResponseHTML = (jsx: React.JSX.Element, assets: PageAssets, meta: unknown) => {
const headers = new Headers();

headers.set('content-type', 'text/html');
headers.set('simaland-bundle-js', assets.js);
headers.set('simaland-bundle-css', assets.css);

if (assets.criticalJs) {
headers.set('simaland-critical-js', assets.criticalJs);
}

if (assets.criticalCss) {
headers.set('simaland-critical-css', assets.criticalCss);
}

if (meta) {
headers.set('simaland-meta', JSON.stringify(meta));
}

// ВАЖНО: DOCTYPE обязательно нужен так как влияет на то как браузер будет парсить html/css
// ВАЖНО: DOCTYPE нужен только когда отдаем полноценную страницу
if (config.env === 'development') {
return new Response(`<!DOCTYPE html>${elementToString(jsx)}`, {
headers,
});
} else {
return new Response(elementToString(jsx), {
headers,
});
}
};

const getResponseJSON = (jsx: React.JSX.Element, assets: PageAssets, meta: unknown) => {
const headers = new Headers();

headers.set('content-type', 'application/json');

return new Response(
JSON.stringify({
markup: elementToString(jsx),
bundle_js: assets.js,
bundle_css: assets.css,
critical_js: assets.criticalJs,
critical_css: assets.criticalCss,
meta,
}),
{ headers },
);
};

const handler = async (request: Request): Promise<Response> => {
const handler = async (): Promise<Response> => {
try {
const assets = await getAssets();
const meta = extras.getMeta();
Expand All @@ -96,33 +35,43 @@ export function provideHandlerMain(resolve: Resolve) {
</HelmetContext.Provider>
);

switch (getPageResponseFormat(request)) {
case 'html': {
return getResponseHTML(jsx, assets, meta);
}
case 'json': {
return getResponseJSON(jsx, assets, meta);
}
}
const { body, headers } = await formatResponse(jsx, assets, meta);

return new Response(body, { headers });
} catch (error) {
let logLevel: LogLevel | null = 'error';
let message: string;
let statusCode = 500; // по умолчанию, если на этапе подготовки страницы что-то не так, отдаем 500
let redirectLocation: string | null = null;

if (error instanceof Error) {
message = error.message;

if (error instanceof ResponseError) {
statusCode = error.statusCode;
redirectLocation = error.redirectLocation;
logLevel = error.logLevel;
}
} else {
message = String(error);
}

logger.error(error);
if (logLevel && logger[logLevel]) {
logger[logLevel](error);
}

return new Response(message, {
status: statusCode,
});
if (statusCode > 299 && statusCode < 400 && redirectLocation) {
return new Response(null, {
status: statusCode,
headers: {
Location: redirectLocation,
},
});
} else {
return new Response(message, {
status: statusCode,
});
}
}
};

Expand Down
15 changes: 0 additions & 15 deletions src/preset/bun-handler/providers/page-helmet.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/preset/bun/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { KnownToken } from '../../tokens';
import { PresetTuner } from '../isomorphic';
import { provideBaseConfig } from '../isomorphic/providers/base-config';
import { provideFetch } from '../isomorphic/providers/fetch';
import { provideKnownHttpApiHosts } from '../node/providers/known-http-api-hosts';
import { provideSsrBridgeServerSide } from '../node/providers/ssr-bridge-server-side';
import { provideKnownHttpApiHosts } from '../server/providers/known-http-api-hosts';
import { provideSsrBridgeServerSide } from '../server/providers/ssr-bridge-server-side';
import { provideConfigSource } from './providers/config-source';
import { provideLogger } from './providers/logger';
import { provideServe } from './providers/serve';
Expand Down
14 changes: 11 additions & 3 deletions src/preset/node-handler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ import { provideReduxMiddlewareSaga } from '../isomorphic/providers/redux-middle
import { provideFetch } from '../isomorphic/providers/fetch';
import { provideAbortController } from '../isomorphic/providers/abort-controller';
import { PresetTuner } from '../isomorphic/types';
import { provideFormatPageResponse } from '../server/providers/format-page-response';
import { provideElementToString } from '../server/providers/element-to-string';
import { provideAxiosMiddleware } from './providers/axios-middleware';
import { provideAxiosLogHandler } from './providers/axios-log-handler';
import { provideHandlerMain } from './providers/handler-main';
import { provideSpecificParams } from './providers/specific-params';
import { providePageHelmet } from './providers/page-helmet';
import { providePageRender } from './providers/page-render';
import { providePageHelmet } from '../server/providers/page-helmet';
import { providePageRender } from '../server/providers/page-render';
import { provideFetchMiddleware } from './providers/fetch-middleware';
import { provideFetchLogHandler } from './providers/fetch-log-handler';
import { provideFetchLogHandler } from '../server/providers/fetch-log-handler';
import { provideCookieStore } from './providers/cookie-store';
import { SpecificExtras } from '../server/utils/specific-extras';
import { provideAcceptType } from './providers/accepts-type';
import { provideResponseEvents } from './providers/response-events';

/**
* Возвращает preset с зависимостями по умолчанию для работы в рамках ответа на http-запрос.
Expand Down Expand Up @@ -43,11 +47,15 @@ export function PresetHandler(customize?: PresetTuner): Preset {
preset.set(KnownToken.ExpressHandler.main, provideHandlerMain);

// http handler
preset.set(KnownToken.Http.Handler.Request.acceptType, provideAcceptType);
preset.set(KnownToken.Http.Handler.Request.specificParams, provideSpecificParams);
preset.set(KnownToken.Http.Handler.Response.specificExtras, () => new SpecificExtras());
preset.set(KnownToken.Http.Handler.Response.events, provideResponseEvents);
preset.set(KnownToken.Http.Handler.Page.assets, () => ({ js: '', css: '' }));
preset.set(KnownToken.Http.Handler.Page.helmet, providePageHelmet);
preset.set(KnownToken.Http.Handler.Page.render, providePageRender);
preset.set(KnownToken.Http.Handler.Page.elementToString, provideElementToString);
preset.set(KnownToken.Http.Handler.Page.formatResponse, provideFormatPageResponse);

if (customize) {
customize({ override: preset.set.bind(preset) });
Expand Down
13 changes: 13 additions & 0 deletions src/preset/node-handler/providers/accepts-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Resolve } from '../../../di';
import { KnownToken } from '../../../tokens';

/**
* Провайдер функции, которая определяет возможные типы ответа и их приоритет.
* @param resolve Resolve.
* @return Функция.
*/
export function provideAcceptType(resolve: Resolve) {
const context = resolve(KnownToken.ExpressHandler.context);

return context.req.accepts.bind(context.req);
}
Loading

0 comments on commit 3fd96ef

Please sign in to comment.