diff options
author | 2021-04-30 16:33:35 -0500 | |
---|---|---|
committer | 2021-04-30 16:33:35 -0500 | |
commit | 4df1347156cf2632ea2f3475d3a5f8f08d197cc3 (patch) | |
tree | 9d50de89dfe62827c32a8a4046120af4ab61dc0c /src/frontend/render | |
parent | 1d498facc8f78a3ffbfecd05cc6ecd45e8a4a1ae (diff) | |
download | astro-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.ts | 31 | ||||
-rw-r--r-- | src/frontend/render/react.ts | 29 | ||||
-rw-r--r-- | src/frontend/render/renderer.ts | 61 | ||||
-rw-r--r-- | src/frontend/render/svelte.ts | 26 | ||||
-rw-r--r-- | src/frontend/render/utils.ts | 52 | ||||
-rw-r--r-- | src/frontend/render/vue.ts | 65 |
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; |