UNPKG

express-tsx-views

Version:

Server-side JSX/TSX rendering for your express or NestJS application 🚀

65 lines • 3.11 kB
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