@shopify/react-server
Version:
Utilities for React server-side rendering.
93 lines (92 loc) • 5.61 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var react_1 = tslib_1.__importDefault(require("react"));
var server_1 = require("@shopify/react-html/server");
var server_2 = require("@shopify/react-network/server");
var react_hydrate_1 = require("@shopify/react-hydrate");
var server_3 = require("@shopify/react-effect/server");
var react_async_1 = require("@shopify/react-async");
var react_network_1 = require("@shopify/react-network");
var sewing_kit_koa_1 = require("@shopify/sewing-kit-koa");
var logger_1 = require("../logger");
/**
* Creates a Koa middleware for rendering an `@shopify/react-html` based React application defined by `options.render`.
* @param render
*/
function createRender(render, options) {
if (options === void 0) { options = {}; }
return function renderFunction(ctx) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
function Providers(_a) {
var children = _a.children;
return (react_1.default.createElement(react_async_1.AsyncAssetContext.Provider, { value: asyncAssetManager },
react_1.default.createElement(react_hydrate_1.HydrationContext.Provider, { value: hydrationManager },
react_1.default.createElement(server_2.NetworkContext.Provider, { value: networkManager }, children))));
}
var logger, assets, networkManager, htmlManager, asyncAssetManager, hydrationManager, app, immediateAsyncAssets, _a, styles, scripts, response, error_1, errorMessage;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
logger = logger_1.getLogger(ctx) || console;
assets = sewing_kit_koa_1.getAssets(ctx);
networkManager = new server_2.NetworkManager({
headers: ctx.headers,
cookies: ctx.request.headers.cookie || '',
});
htmlManager = new server_1.HtmlManager();
asyncAssetManager = new react_async_1.AsyncAssetManager();
hydrationManager = new react_hydrate_1.HydrationManager();
_b.label = 1;
case 1:
_b.trys.push([1, 4, , 5]);
app = render(ctx);
return [4 /*yield*/, server_3.extract(app, tslib_1.__assign({ decorate: function (element) {
return (react_1.default.createElement(server_1.HtmlContext.Provider, { value: htmlManager },
react_1.default.createElement(Providers, null, element)));
},
afterEachPass: function (_a) {
var renderDuration = _a.renderDuration, resolveDuration = _a.resolveDuration, index = _a.index, finished = _a.finished;
var pass = "Pass number " + index + " " + (finished ? ' (this was the final pass)' : '');
var rendering = "Rendering took " + renderDuration + "ms";
var resolving = "Resolving promises took " + resolveDuration + "ms";
logger.log(pass);
logger.log(rendering);
logger.log(resolving);
} }, options))];
case 2:
_b.sent();
server_2.applyToContext(ctx, networkManager);
immediateAsyncAssets = asyncAssetManager.used(react_async_1.AssetTiming.Immediate);
return [4 /*yield*/, Promise.all([
assets.styles({ name: 'main', asyncAssets: immediateAsyncAssets }),
assets.scripts({ name: 'main', asyncAssets: immediateAsyncAssets }),
])];
case 3:
_a = tslib_1.__read.apply(void 0, [_b.sent(), 2]), styles = _a[0], scripts = _a[1];
response = server_1.stream(react_1.default.createElement(server_1.Html, { manager: htmlManager, styles: styles, scripts: scripts },
react_1.default.createElement(Providers, null, app)));
ctx.set(react_network_1.Header.ContentType, 'text/html');
ctx.body = response;
return [3 /*break*/, 5];
case 4:
error_1 = _b.sent();
errorMessage = "React server-side rendering error:\n" + (error_1.stack ||
error_1.message);
logger.log(errorMessage);
ctx.status = react_network_1.StatusCode.InternalServerError;
// eslint-disable-next-line no-process-env
if (process.env.NODE_ENV === 'development') {
ctx.body = errorMessage;
}
else {
ctx.throw(react_network_1.StatusCode.InternalServerError, error_1);
}
return [3 /*break*/, 5];
case 5: return [2 /*return*/];
}
});
});
};
}
exports.createRender = createRender;