Improve renderer types (#69)

* Improve renderer types

Looking at the render code I noticed that the Component rendering is not typed. This adds that, might help prevent a bug in the future.

* Create the supported renderer type
This commit is contained in:
Matthew Phillips 2021-04-09 13:03:27 -04:00 committed by GitHub
parent 4ccf4196e3
commit 185a267133
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 20 additions and 10 deletions

View file

@ -1,11 +1,16 @@
import type { Component as VueComponent } from 'vue';
import type { ComponentType as PreactComponent } from 'preact';
import type { ComponentType as ReactComponent } from 'react';
import type { SvelteComponent } from 'svelte';
export interface DynamicRenderContext { export interface DynamicRenderContext {
componentUrl: string; componentUrl: string;
componentExport: string; componentExport: string;
frameworkUrls: string; frameworkUrls: string;
} }
export interface ComponentRenderer { export interface ComponentRenderer<T> {
renderStatic: StaticRendererGenerator; renderStatic: StaticRendererGenerator<T>;
render(context: { root: string; Component: string; props: string; [key: string]: string }): string; render(context: { root: string; Component: string; props: string; [key: string]: string }): string;
imports?: Record<string, string[]>; imports?: Record<string, string[]>;
} }
@ -15,6 +20,9 @@ export interface ComponentContext {
root: string; root: string;
} }
export type SupportedComponentRenderer = ComponentRenderer<VueComponent> |
ComponentRenderer<PreactComponent> | ComponentRenderer<ReactComponent> |
ComponentRenderer<SvelteComponent>;
export type StaticRenderer = (props: Record<string, any>, ...children: any[]) => Promise<string>; export type StaticRenderer = (props: Record<string, any>, ...children: any[]) => Promise<string>;
export type StaticRendererGenerator<T = any> = (Component: T) => StaticRenderer; export type StaticRendererGenerator<T = any> = (Component: T) => StaticRenderer;
export type DynamicRenderer = (props: Record<string, any>, ...children: any[]) => Promise<string>; export type DynamicRenderer = (props: Record<string, any>, ...children: any[]) => Promise<string>;

View file

@ -1,4 +1,4 @@
import { h, render } from 'preact'; import { h, render, ComponentType } from 'preact';
import { renderToString } from 'preact-render-to-string'; import { renderToString } from 'preact-render-to-string';
import type { ComponentRenderer } from '../../@types/renderer'; import type { ComponentRenderer } from '../../@types/renderer';
import { createRenderer } from './renderer'; import { createRenderer } from './renderer';
@ -6,7 +6,7 @@ import { createRenderer } from './renderer';
// This prevents tree-shaking of render. // This prevents tree-shaking of render.
Function.prototype(render); Function.prototype(render);
const Preact: ComponentRenderer = { const Preact: ComponentRenderer<ComponentType> = {
renderStatic(Component) { renderStatic(Component) {
return async (props, ...children) => renderToString(h(Component, props, ...children)); return async (props, ...children) => renderToString(h(Component, props, ...children));
}, },

View file

@ -1,9 +1,9 @@
import type { ComponentRenderer } from '../../@types/renderer'; import type { ComponentRenderer } from '../../@types/renderer';
import React from 'react'; import React, { ComponentType } from 'react';
import ReactDOMServer from 'react-dom/server'; import ReactDOMServer from 'react-dom/server';
import { createRenderer } from './renderer'; import { createRenderer } from './renderer';
const ReactRenderer: ComponentRenderer = { const ReactRenderer: ComponentRenderer<ComponentType> = {
renderStatic(Component) { renderStatic(Component) {
return async (props, ...children) => ReactDOMServer.renderToString(React.createElement(Component, props, children)); return async (props, ...children) => ReactDOMServer.renderToString(React.createElement(Component, props, children));
}, },

View file

@ -1,7 +1,7 @@
import type { ComponentRenderer, DynamicRenderContext, DynamicRendererGenerator, StaticRendererGenerator } from '../../@types/renderer'; import type { DynamicRenderContext, DynamicRendererGenerator, SupportedComponentRenderer, StaticRendererGenerator } from '../../@types/renderer';
/** Initialize Astro Component renderer for Static and Dynamic components */ /** Initialize Astro Component renderer for Static and Dynamic components */
export function createRenderer(renderer: ComponentRenderer) { export function createRenderer(renderer: SupportedComponentRenderer) {
const _static: StaticRendererGenerator = (Component) => renderer.renderStatic(Component); const _static: StaticRendererGenerator = (Component) => renderer.renderStatic(Component);
const _imports = (context: DynamicRenderContext) => { const _imports = (context: DynamicRenderContext) => {
const values = Object.values(renderer.imports ?? {}) const values = Object.values(renderer.imports ?? {})

View file

@ -1,7 +1,8 @@
import type { ComponentRenderer } from '../../@types/renderer'; import type { ComponentRenderer } from '../../@types/renderer';
import type { SvelteComponent } from 'svelte';
import { createRenderer } from './renderer'; import { createRenderer } from './renderer';
const SvelteRenderer: ComponentRenderer = { const SvelteRenderer: ComponentRenderer<SvelteComponent> = {
renderStatic(Component) { renderStatic(Component) {
return async (props, ...children) => { return async (props, ...children) => {
const { html } = Component.render(props); const { html } = Component.render(props);

View file

@ -1,9 +1,10 @@
import type { ComponentRenderer } from '../../@types/renderer'; import type { ComponentRenderer } from '../../@types/renderer';
import type { Component as VueComponent } from 'vue';
import { renderToString } from '@vue/server-renderer'; import { renderToString } from '@vue/server-renderer';
import { createSSRApp, h as createElement } from 'vue'; import { createSSRApp, h as createElement } from 'vue';
import { createRenderer } from './renderer'; import { createRenderer } from './renderer';
const Vue: ComponentRenderer = { const Vue: ComponentRenderer<VueComponent> = {
renderStatic(Component) { renderStatic(Component) {
return async (props, ...children) => { return async (props, ...children) => {
const app = createSSRApp({ const app = createSSRApp({