diff --git a/src/@types/renderer.ts b/src/@types/renderer.ts new file mode 100644 index 0000000000..488a91130e --- /dev/null +++ b/src/@types/renderer.ts @@ -0,0 +1,25 @@ +export interface DynamicRenderContext { + componentUrl: string; + componentExport: string; + frameworkUrls: string; +} + +export interface ComponentRenderer { + renderStatic: StaticRendererGenerator; + render(context: { root: string; Component: string; props: string; [key: string]: string }): string; + imports?: Record; +} + +export interface ComponentContext { + 'data-astro-id': string; + root: string; +} + +export type StaticRenderer = (props: Record, ...children: any[]) => Promise; +export type StaticRendererGenerator = (Component: T) => StaticRenderer; +export type DynamicRenderer = (props: Record, ...children: any[]) => Promise; +export type DynamicRendererContext = (Component: T, renderContext: DynamicRenderContext) => DynamicRenderer; +export type DynamicRendererGenerator = ( + wrapperStart: string | ((context: ComponentContext) => string), + wrapperEnd: string | ((context: ComponentContext) => string) +) => DynamicRendererContext; diff --git a/src/frontend/render/preact.ts b/src/frontend/render/preact.ts index 8705c5504d..3bc2667352 100644 --- a/src/frontend/render/preact.ts +++ b/src/frontend/render/preact.ts @@ -1,11 +1,12 @@ -import { Renderer, createRenderer } from './renderer'; import { h, render } from 'preact'; import { renderToString } from 'preact-render-to-string'; +import type { ComponentRenderer } from '../../@types/renderer'; +import { createRenderer } from './renderer'; // This prevents tree-shaking of render. Function.prototype(render); -const Preact: Renderer = { +const Preact: ComponentRenderer = { renderStatic(Component) { return async (props, ...children) => renderToString(h(Component, props, ...children)); }, diff --git a/src/frontend/render/react.ts b/src/frontend/render/react.ts index bab1d582ce..b9e55f1c9c 100644 --- a/src/frontend/render/react.ts +++ b/src/frontend/render/react.ts @@ -1,8 +1,9 @@ -import { Renderer, createRenderer } from './renderer'; +import type { ComponentRenderer } from '../../@types/renderer'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; +import { createRenderer } from './renderer'; -const ReactRenderer: Renderer = { +const ReactRenderer: ComponentRenderer = { renderStatic(Component) { return async (props, ...children) => ReactDOMServer.renderToString(React.createElement(Component, props, children)); }, diff --git a/src/frontend/render/renderer.ts b/src/frontend/render/renderer.ts index cff82eea52..f005698279 100644 --- a/src/frontend/render/renderer.ts +++ b/src/frontend/render/renderer.ts @@ -1,18 +1,8 @@ -interface DynamicRenderContext { - componentUrl: string; - componentExport: string; - frameworkUrls: string; -} - -export interface Renderer { - renderStatic(Component: any): (props: Record, ...children: any[]) => Promise; - render(context: { root: string; Component: string; props: string; [key: string]: string }): string; - imports?: Record; -} +import type { ComponentRenderer, DynamicRenderContext, DynamicRendererGenerator, StaticRendererGenerator } from '../../@types/renderer'; /** Initialize Astro Component renderer for Static and Dynamic components */ -export function createRenderer(renderer: Renderer) { - const _static: Renderer['renderStatic'] = (Component: any) => renderer.renderStatic(Component); +export function createRenderer(renderer: ComponentRenderer) { + const _static: StaticRendererGenerator = (Component) => renderer.renderStatic(Component); const _imports = (context: DynamicRenderContext) => { const values = Object.values(renderer.imports ?? {}) .reduce((acc, v) => { @@ -31,12 +21,9 @@ export function createRenderer(renderer: Renderer) { const astroId = `${Math.floor(Math.random() * 1e16)}`; return { ['data-astro-id']: astroId, root: `document.querySelector('[data-astro-id="${astroId}"]')`, Component: 'Component' }; }; - const createDynamicRender = ( - wrapperStart: string | ((context: ReturnType) => string), - wrapperEnd: string | ((context: ReturnType) => string) - ) => (Component: any, renderContext: DynamicRenderContext) => { + const createDynamicRender: DynamicRendererGenerator = (wrapperStart, wrapperEnd) => (Component, renderContext) => { const innerContext = createContext(); - return async (props: Record, ...children: any[]) => { + return async (props, ...children) => { let value: string; try { value = await _static(Component)(props, ...children); diff --git a/src/frontend/render/svelte.ts b/src/frontend/render/svelte.ts index 2f67eb79f3..6549d1dde2 100644 --- a/src/frontend/render/svelte.ts +++ b/src/frontend/render/svelte.ts @@ -1,6 +1,7 @@ -import { Renderer, createRenderer } from './renderer'; +import type { ComponentRenderer } from '../../@types/renderer'; +import { createRenderer } from './renderer'; -const SvelteRenderer: Renderer = { +const SvelteRenderer: ComponentRenderer = { renderStatic(Component) { return async (props, ...children) => { const { html } = Component.render(props); diff --git a/src/frontend/render/vue.ts b/src/frontend/render/vue.ts index 69c00e570b..e287295427 100644 --- a/src/frontend/render/vue.ts +++ b/src/frontend/render/vue.ts @@ -1,8 +1,9 @@ +import type { ComponentRenderer } from '../../@types/renderer'; import { renderToString } from '@vue/server-renderer'; import { createSSRApp, h as createElement } from 'vue'; -import { Renderer, createRenderer } from './renderer'; +import { createRenderer } from './renderer'; -const Vue: Renderer = { +const Vue: ComponentRenderer = { renderStatic(Component) { return async (props, ...children) => { const app = createSSRApp({ diff --git a/tsconfig.json b/tsconfig.json index 1e417f9e65..5144b008b2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,13 +5,13 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "es2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "ES2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "ES2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ + "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ @@ -44,7 +44,7 @@ // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ /* Module Resolution Options */ - "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */