summaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2021-03-15 13:22:05 -0400
committerGravatar Matthew Phillips <matthew@skypack.dev> 2021-03-15 13:22:05 -0400
commitaf6b029e95e9c98e6fb9c642915d461b8d7f448e (patch)
treed70972e10884de0363e7ce4dd2a0765dafcf3dc8 /src/frontend
downloadastro-af6b029e95e9c98e6fb9c642915d461b8d7f448e.tar.gz
astro-af6b029e95e9c98e6fb9c642915d461b8d7f448e.tar.zst
astro-af6b029e95e9c98e6fb9c642915d461b8d7f448e.zip
initial commit
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/h.ts46
-rw-r--r--src/frontend/render/preact.ts27
-rw-r--r--src/frontend/render/svelte.ts24
-rw-r--r--src/frontend/render/vue.ts39
4 files changed, 136 insertions, 0 deletions
diff --git a/src/frontend/h.ts b/src/frontend/h.ts
new file mode 100644
index 000000000..3d9e62f43
--- /dev/null
+++ b/src/frontend/h.ts
@@ -0,0 +1,46 @@
+export type HProps = Record<string, string> | null | undefined;
+export type HChild = string | undefined | (() => string);
+export type HMXComponent = (props: HProps, ...children: Array<HChild>) => string;
+export type HTag = string | HMXComponent;
+
+function* _h(tag: string, attrs: HProps, children: Array<HChild>) {
+ yield `<${tag}`;
+ if (attrs) {
+ yield ' ';
+ for (let [key, value] of Object.entries(attrs)) {
+ yield `${key}="${value}"`;
+ }
+ }
+ yield '>';
+
+ for (let child of children) {
+ // Special: If a child is a function, call it automatically.
+ // This lets you do {() => ...} without the extra boilerplate
+ // of wrapping it in a function and calling it.
+ if (typeof child === 'function') {
+ yield child();
+ } else if (typeof child === 'string') {
+ yield child;
+ } else if (!child) {
+ // do nothing, safe to ignore falsey values.
+ } else {
+ yield child;
+ }
+ }
+
+ yield `</${tag}>`;
+}
+
+export async function h(tag: HTag, attrs: HProps, ...pChildren: Array<Promise<HChild>>) {
+ const children = await Promise.all(pChildren.flat(Infinity));
+ if (typeof tag === 'function') {
+ // We assume it's an hmx component
+ return tag(attrs, ...children);
+ }
+
+ return Array.from(_h(tag, attrs, children)).join('');
+}
+
+export function Fragment(_: HProps, ...children: Array<string>) {
+ return children.join('');
+}
diff --git a/src/frontend/render/preact.ts b/src/frontend/render/preact.ts
new file mode 100644
index 000000000..eb588209c
--- /dev/null
+++ b/src/frontend/render/preact.ts
@@ -0,0 +1,27 @@
+import render from 'preact-render-to-string';
+import { h } from 'preact';
+import type { Component } from 'preact';
+
+export function __preact_static(PreactComponent: Component) {
+ return (attrs: Record<string, any>, ...children: any): string => {
+ let html = render(
+ h(
+ PreactComponent as any, // Preact's types seem wrong...
+ attrs,
+ children
+ )
+ );
+ return html;
+ };
+}
+
+export function __preact_dynamic(PreactComponent: Component, importUrl: string, preactUrl: string) {
+ const placeholderId = `placeholder_${String(Math.random())}`;
+ return (attrs: Record<string, string>, ...children: any) => {
+ return `<div id="${placeholderId}"></div><script type="module">
+ import {h, render} from '${preactUrl}';
+ import Component from '${importUrl}';
+ render(h(Component, ${JSON.stringify(attrs)}), document.getElementById('${placeholderId}'));
+ </script>`;
+ };
+}
diff --git a/src/frontend/render/svelte.ts b/src/frontend/render/svelte.ts
new file mode 100644
index 000000000..ffdf70254
--- /dev/null
+++ b/src/frontend/render/svelte.ts
@@ -0,0 +1,24 @@
+import { SvelteComponent as Component } from 'svelte';
+
+export function __svelte_static(SvelteComponent: Component) {
+ return (attrs: Record<string, any>, ...children: any): string => {
+ // TODO include head and css stuff too...
+ const { html } = SvelteComponent.render(attrs);
+
+ return html;
+ };
+}
+
+export function __svelte_dynamic(SvelteComponent: Component, importUrl: string) {
+ const placeholderId = `placeholder_${String(Math.random())}`;
+ return (attrs: Record<string, string>, ...children: any) => {
+ return `<div id="${placeholderId}"></div><script type="module">
+ import Component from '${importUrl}';
+
+ new Component({
+ target: document.getElementById('${placeholderId}'),
+ props: ${JSON.stringify(attrs)}
+ });
+ </script>`;
+ };
+}
diff --git a/src/frontend/render/vue.ts b/src/frontend/render/vue.ts
new file mode 100644
index 000000000..f83c1665a
--- /dev/null
+++ b/src/frontend/render/vue.ts
@@ -0,0 +1,39 @@
+import type { Component } from 'vue';
+
+import { renderToString } from '@vue/server-renderer';
+import { createSSRApp, h as createElement } from 'vue';
+
+export function __vue_static(VueComponent: Component) {
+ return async (attrs: Record<string, any>, ...children: any): Promise<string> => {
+ const app = createSSRApp({
+ components: {
+ VueComponent
+ },
+ render() {
+ return createElement(VueComponent as any, attrs);
+ }
+ });
+
+ const html = await renderToString(app);
+
+ return html;
+ };
+}
+
+export function __vue_dynamic(VueComponent: Component, importUrl: string, vueUrl: string) {
+ const placeholderId = `placeholder_${String(Math.random())}`;
+ return (attrs: Record<string, string>, ...children: any) => {
+ return `<div id="${placeholderId}"></div><script type="module">
+ import Component from '${importUrl}';
+ import {createApp, h as createElement} from '${vueUrl}';
+
+ const App = {
+ render() {
+ return createElement(Component, ${JSON.stringify(attrs)});
+ }
+ };
+
+ createApp(App).mount(document.getElementById('${placeholderId}'));
+ </script>`;
+ };
+} \ No newline at end of file