summaryrefslogtreecommitdiff
path: root/src/frontend/render
diff options
context:
space:
mode:
authorGravatar Nate Moore <natemoo-re@users.noreply.github.com> 2021-04-30 16:33:35 -0500
committerGravatar GitHub <noreply@github.com> 2021-04-30 16:33:35 -0500
commit4df1347156cf2632ea2f3475d3a5f8f08d197cc3 (patch)
tree9d50de89dfe62827c32a8a4046120af4ab61dc0c /src/frontend/render
parent1d498facc8f78a3ffbfecd05cc6ecd45e8a4a1ae (diff)
downloadastro-4df1347156cf2632ea2f3475d3a5f8f08d197cc3.tar.gz
astro-4df1347156cf2632ea2f3475d3a5f8f08d197cc3.tar.zst
astro-4df1347156cf2632ea2f3475d3a5f8f08d197cc3.zip
Migrate to `yarn` monorepo (#157)
* chore: use monorepo * chore: scaffold astro-scripts * chore: move tests inside packages/astro * chore: refactor tests, add scripts * chore: move parser to own module * chore: move runtime to packages/astro * fix: move parser to own package * test: fix prettier-plugin-astro tests * fix: tests * chore: update package-lock * chore: add changesets * fix: cleanup examples * fix: starter example * chore: update changeset config * chore: update changeset config * chore: setup changeset release workflow * chore: bump lockfiles * chore: prism => astro-prism * fix: tsc --emitDeclarationOnly * chore: final cleanup, switch to yarn * chore: add lerna * chore: update workflows to yarn * chore: update workflows * chore: remove lint workflow * chore: add astro-dev script * chore: add symlinked README
Diffstat (limited to 'src/frontend/render')
-rw-r--r--src/frontend/render/preact.ts31
-rw-r--r--src/frontend/render/react.ts29
-rw-r--r--src/frontend/render/renderer.ts61
-rw-r--r--src/frontend/render/svelte.ts26
-rw-r--r--src/frontend/render/utils.ts52
-rw-r--r--src/frontend/render/vue.ts65
6 files changed, 0 insertions, 264 deletions
diff --git a/src/frontend/render/preact.ts b/src/frontend/render/preact.ts
deleted file mode 100644
index 5c50b6fe3..000000000
--- a/src/frontend/render/preact.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { h, render, ComponentType } from 'preact';
-import { renderToString } from 'preact-render-to-string';
-import { childrenToVnodes } from './utils';
-import type { ComponentRenderer } from '../../@types/renderer';
-import { createRenderer } from './renderer';
-
-// This prevents tree-shaking of render.
-Function.prototype(render);
-
-const Preact: ComponentRenderer<ComponentType> = {
- jsxPragma: h,
- jsxPragmaName: 'h',
- renderStatic(Component) {
- return async (props, ...children) => {
- return renderToString(h(Component, props, childrenToVnodes(h, children)));
- };
- },
- imports: {
- preact: ['render', 'Fragment', 'h'],
- },
- render({ Component, root, props, children }) {
- return `render(h(${Component}, ${props}, h(Fragment, null, ...${children})), ${root})`;
- },
-};
-
-const renderer = createRenderer(Preact);
-
-export const __preact_static = renderer.static;
-export const __preact_load = renderer.load;
-export const __preact_idle = renderer.idle;
-export const __preact_visible = renderer.visible;
diff --git a/src/frontend/render/react.ts b/src/frontend/render/react.ts
deleted file mode 100644
index 51c0c9729..000000000
--- a/src/frontend/render/react.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import type { ComponentRenderer } from '../../@types/renderer';
-import React, { ComponentType } from 'react';
-import ReactDOMServer from 'react-dom/server';
-import { createRenderer } from './renderer';
-import { childrenToVnodes } from './utils';
-
-const ReactRenderer: ComponentRenderer<ComponentType> = {
- jsxPragma: React.createElement,
- jsxPragmaName: 'React.createElement',
- renderStatic(Component) {
- return async (props, ...children) => {
- return ReactDOMServer.renderToString(React.createElement(Component, props, childrenToVnodes(React.createElement, children)));
- };
- },
- imports: {
- react: ['default: React'],
- 'react-dom': ['default: ReactDOM'],
- },
- render({ Component, root, children, props }) {
- return `ReactDOM.hydrate(React.createElement(${Component}, ${props}, React.createElement(React.Fragment, null, ...${children})), ${root})`;
- },
-};
-
-const renderer = createRenderer(ReactRenderer);
-
-export const __react_static = renderer.static;
-export const __react_load = renderer.load;
-export const __react_idle = renderer.idle;
-export const __react_visible = renderer.visible;
diff --git a/src/frontend/render/renderer.ts b/src/frontend/render/renderer.ts
deleted file mode 100644
index a5cc9d581..000000000
--- a/src/frontend/render/renderer.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import type { DynamicRenderContext, DynamicRendererGenerator, SupportedComponentRenderer, StaticRendererGenerator } from '../../@types/renderer';
-import { childrenToH } from './utils';
-
-/** Initialize Astro Component renderer for Static and Dynamic components */
-export function createRenderer(renderer: SupportedComponentRenderer) {
- const _static: StaticRendererGenerator = (Component) => renderer.renderStatic(Component);
- const _imports = (context: DynamicRenderContext) => {
- const values = Object.values(renderer.imports ?? {})
- .reduce((acc, v) => {
- return [...acc, `{ ${v.join(', ')} }`];
- }, [])
- .join(', ');
- const libs = Object.keys(renderer.imports ?? {})
- .reduce((acc: string[], lib: string) => {
- return [...acc, `import("${context.frameworkUrls[lib as any]}")`];
- }, [])
- .join(',');
- return `const [{${context.componentExport}: Component}, ${values}] = await Promise.all([import("${context.componentUrl}")${renderer.imports ? ', ' + libs : ''}]);`;
- };
- const serializeProps = ({ children: _, ...props }: Record<string, any>) => JSON.stringify(props);
- const createContext = () => {
- const astroId = `${Math.floor(Math.random() * 1e16)}`;
- return { ['data-astro-id']: astroId, root: `document.querySelector('[data-astro-id="${astroId}"]')`, Component: 'Component' };
- };
- const createDynamicRender: DynamicRendererGenerator = (wrapperStart, wrapperEnd) => (Component, renderContext) => {
- const innerContext = createContext();
- return async (props, ...children) => {
- let value: string;
- try {
- value = await _static(Component)(props, ...children);
- } catch (e) {
- value = '';
- }
- value = `<div data-astro-id="${innerContext['data-astro-id']}" style="display:contents">${value}</div>`;
-
- const script = `
- ${typeof wrapperStart === 'function' ? wrapperStart(innerContext) : wrapperStart}
- ${_imports(renderContext)}
- ${renderer.render({
- ...innerContext,
- props: serializeProps(props),
- children: `[${childrenToH(renderer, children) ?? ''}]`,
- childrenAsString: `\`${children}\``,
- })}
- ${typeof wrapperEnd === 'function' ? wrapperEnd(innerContext) : wrapperEnd}
- `;
-
- return [value, `<script type="module">${script.trim()}</script>`].join('\n');
- };
- };
-
- return {
- static: _static,
- load: createDynamicRender('(async () => {', '})()'),
- idle: createDynamicRender('requestIdleCallback(async () => {', '})'),
- visible: createDynamicRender(
- 'const o = new IntersectionObserver(async ([entry]) => { if (!entry.isIntersecting) { return; } o.disconnect();',
- ({ root }) => `}); Array.from(${root}.children).forEach(child => o.observe(child))`
- ),
- };
-}
diff --git a/src/frontend/render/svelte.ts b/src/frontend/render/svelte.ts
deleted file mode 100644
index 13e2b8f58..000000000
--- a/src/frontend/render/svelte.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import type { ComponentRenderer } from '../../@types/renderer';
-import type { SvelteComponent } from 'svelte';
-import { createRenderer } from './renderer';
-import SvelteWrapper from '../SvelteWrapper.svelte.server';
-
-const SvelteRenderer: ComponentRenderer<SvelteComponent> = {
- renderStatic(Component) {
- return async (props, ...children) => {
- const { html } = SvelteWrapper.render({ __astro_component: Component, __astro_children: children.join('\n'), ...props });
- return html;
- };
- },
- imports: {
- 'svelte-runtime': ['default: render'],
- },
- render({ Component, root, props, childrenAsString }) {
- return `render(${root}, ${Component}, ${props}, ${childrenAsString});`;
- },
-};
-
-const renderer = createRenderer(SvelteRenderer);
-
-export const __svelte_static = renderer.static;
-export const __svelte_load = renderer.load;
-export const __svelte_idle = renderer.idle;
-export const __svelte_visible = renderer.visible;
diff --git a/src/frontend/render/utils.ts b/src/frontend/render/utils.ts
deleted file mode 100644
index 9d55626fe..000000000
--- a/src/frontend/render/utils.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import unified from 'unified';
-import parse from 'rehype-parse';
-import toH from 'hast-to-hyperscript';
-import { ComponentRenderer } from '../../@types/renderer';
-import moize from 'moize';
-
-/** @internal */
-function childrenToTree(children: string[]) {
- return children.map((child) => (unified().use(parse, { fragment: true }).parse(child) as any).children.pop());
-}
-
-/**
- * Converts an HTML fragment string into vnodes for rendering via provided framework
- * @param h framework's `createElement` function
- * @param children the HTML string children
- */
-export const childrenToVnodes = moize.deep(function childrenToVnodes(h: any, children: string[]) {
- const tree = childrenToTree(children);
- const vnodes = tree.map((subtree) => {
- if (subtree.type === 'text') return subtree.value;
- return toH(h, subtree);
- });
- return vnodes;
-});
-
-/**
- * Converts an HTML fragment string into h function calls as a string
- * @param h framework's `createElement` function
- * @param children the HTML string children
- */
-export const childrenToH = moize.deep(function childrenToH(renderer: ComponentRenderer<any>, children: string[]): any {
- if (!renderer.jsxPragma) return;
- const tree = childrenToTree(children);
- const innerH = (name: any, attrs: Record<string, any> | null = null, _children: string[] | null = null) => {
- const vnode = renderer.jsxPragma?.(name, attrs, _children);
- const childStr = _children ? `, [${_children.map((child) => serializeChild(child)).join(',')}]` : '';
- /* fix(react): avoid hard-coding keys into the serialized tree */
- if (attrs && attrs.key) attrs.key = undefined;
- const __SERIALIZED = `${renderer.jsxPragmaName}("${name}", ${attrs ? JSON.stringify(attrs) : 'null'}${childStr})` as string;
- return { ...vnode, __SERIALIZED };
- };
- const serializeChild = (child: unknown) => {
- if (['string', 'number', 'boolean'].includes(typeof child)) return JSON.stringify(child);
- if (child === null) return `null`;
- if ((child as any).__SERIALIZED) return (child as any).__SERIALIZED;
- return innerH(child).__SERIALIZED;
- };
- return tree.map((subtree) => {
- if (subtree.type === 'text') return JSON.stringify(subtree.value);
- return toH(innerH, subtree).__SERIALIZED
- });
-});
diff --git a/src/frontend/render/vue.ts b/src/frontend/render/vue.ts
deleted file mode 100644
index 57c3c8276..000000000
--- a/src/frontend/render/vue.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import type { ComponentRenderer } from '../../@types/renderer';
-import type { Component as VueComponent } from 'vue';
-import { renderToString } from '@vue/server-renderer';
-import { defineComponent, createSSRApp, h as createElement } from 'vue';
-import { createRenderer } from './renderer';
-
-// This prevents tree-shaking of render.
-Function.prototype(renderToString);
-
-/**
- * Users might attempt to use :vueAttribute syntax to pass primitive values.
- * If so, try to JSON.parse them to get the primitives
- */
-function cleanPropsForVue(obj: Record<string, any>) {
- let cleaned = {} as any;
- for (let [key, value] of Object.entries(obj)) {
- if (key.startsWith(':')) {
- key = key.slice(1);
- if (typeof value === 'string') {
- try {
- value = JSON.parse(value);
- } catch (e) {}
- }
- }
- cleaned[key] = value;
- }
- return cleaned;
-}
-
-const Vue: ComponentRenderer<VueComponent> = {
- jsxPragma: createElement,
- jsxPragmaName: 'createElement',
- renderStatic(Component) {
- return async (props, ...children) => {
- const App = defineComponent({
- components: {
- Component,
- },
- data() {
- return { props };
- },
- template: `<Component v-bind="props">${children.join('\n')}</Component>`,
- });
-
- const app = createSSRApp(App);
- const html = await renderToString(app);
- return html;
- };
- },
- imports: {
- vue: ['createApp', 'h: createElement'],
- },
- render({ Component, root, props, children }) {
- const vueProps = cleanPropsForVue(JSON.parse(props));
- return `const App = { render: () => createElement(${Component}, ${JSON.stringify(vueProps)}, { default: () => ${children} }) };
-createApp(App).mount(${root});`;
- },
-};
-
-const renderer = createRenderer(Vue);
-
-export const __vue_static = renderer.static;
-export const __vue_load = renderer.load;
-export const __vue_idle = renderer.idle;
-export const __vue_visible = renderer.visible;