express-tsx-views
Version:
Server-side JSX/TSX rendering for your express or NestJS application 🚀
65 lines • 3.11 kB
JavaScript
import { CreateReactContextRenderMiddleware, DefaultTsxRenderMiddleware, TsxRenderContext, } from './handler/index.js';
import { PrettifyRenderMiddleware } from './handler/middleware/prettify-render.middleware.js';
export function isTranspiled() {
return process.argv[1].endsWith('.js');
}
export function setupReactViews(app, options) {
if (!options.viewsDirectory) {
throw new Error('viewsDirectory missing');
}
const extension = isTranspiled() ? 'js' : 'tsx';
// eslint-disable-next-line @typescript-eslint/no-misused-promises
app.engine(extension, reactViews(options));
app.set('view engine', extension);
app.set('views', options.viewsDirectory);
}
export function addReactContext(res, context, value) {
const locals = res.locals;
locals.contexts ??= [];
locals.contexts.unshift([context, value]);
}
export function reactViews(reactViewOptions) {
// eslint-disable-next-line complexity, sonarjs/cognitive-complexity
return async function renderFile(...[filename, options, next]) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { settings, _locals, cache, contexts, ...vars } = options;
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const Component = (await import(filename)).default;
if (!Component) {
throw new Error(`Module ${filename} does not have a default export`);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
let context = new TsxRenderContext(Component, vars);
const defaultRenderer = new DefaultTsxRenderMiddleware();
const middlewares = reactViewOptions.middlewares ?? [];
contexts?.forEach(([Context, props]) => {
middlewares.push(new CreateReactContextRenderMiddleware(Context, props));
});
if (reactViewOptions.prettify ?? false) {
middlewares.push(new PrettifyRenderMiddleware());
}
// eslint-disable-next-line sonarjs/no-ignored-return, unicorn/no-array-reduce
middlewares.reduce((prev, next) => {
prev.setNext(next);
return next;
}, defaultRenderer);
context = defaultRenderer.createElement(context);
if (!context.hasElement()) {
throw new Error('element was not created');
}
context = await defaultRenderer.render(context);
if (!context.isRendered) {
throw new Error('element was not rendered');
}
const doctype = reactViewOptions.doctype ?? '<!DOCTYPE html>\n';
const transform = reactViewOptions.transform || ((html) => html);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
next(null, await transform(doctype + context.html));
}
catch (error) {
next(error);
}
};
}
//# sourceMappingURL=react-view-engine.js.map