summaryrefslogtreecommitdiff
path: root/packages/integrations
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2022-08-10 15:10:31 -0400
committerGravatar GitHub <noreply@github.com> 2022-08-10 15:10:31 -0400
commit0af5aa7a3b2a858c6b6cdbeda46bc3d90be1250f (patch)
treeb4f9dc145005c31c0d0f4cce66a30130908f650c /packages/integrations
parent58941e93c396bf35becc7431e1743afbaad6dd69 (diff)
downloadastro-0af5aa7a3b2a858c6b6cdbeda46bc3d90be1250f.tar.gz
astro-0af5aa7a3b2a858c6b6cdbeda46bc3d90be1250f.tar.zst
astro-0af5aa7a3b2a858c6b6cdbeda46bc3d90be1250f.zip
Fix solid recursion bug (#4215)
* Fix solid recursion bug * Fix types * Remove debug code * Remove logging from e2e test
Diffstat (limited to 'packages/integrations')
-rw-r--r--packages/integrations/solid/package.json4
-rw-r--r--packages/integrations/solid/server.js31
-rw-r--r--packages/integrations/solid/src/client.ts (renamed from packages/integrations/solid/client.js)16
-rw-r--r--packages/integrations/solid/src/context.ts28
-rw-r--r--packages/integrations/solid/src/server.ts45
-rw-r--r--packages/integrations/solid/src/types.ts4
6 files changed, 89 insertions, 39 deletions
diff --git a/packages/integrations/solid/package.json b/packages/integrations/solid/package.json
index b69175007..8ca3b8df6 100644
--- a/packages/integrations/solid/package.json
+++ b/packages/integrations/solid/package.json
@@ -22,8 +22,8 @@
"exports": {
".": "./dist/index.js",
"./*": "./*",
- "./client.js": "./client.js",
- "./server.js": "./server.js",
+ "./client.js": "./dist/client.js",
+ "./server.js": "./dist/server.js",
"./package.json": "./package.json"
},
"scripts": {
diff --git a/packages/integrations/solid/server.js b/packages/integrations/solid/server.js
deleted file mode 100644
index 2398ec317..000000000
--- a/packages/integrations/solid/server.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { renderToString, ssr, createComponent } from 'solid-js/web';
-
-const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
-
-function check(Component, props, children) {
- if (typeof Component !== 'function') return false;
- const { html } = renderToStaticMarkup(Component, props, children);
- return typeof html === 'string';
-}
-
-function renderToStaticMarkup(Component, props, { default: children, ...slotted }) {
- const slots = {};
- for (const [key, value] of Object.entries(slotted)) {
- const name = slotName(key);
- slots[name] = ssr(`<astro-slot name="${name}">${value}</astro-slot>`);
- }
- // Note: create newProps to avoid mutating `props` before they are serialized
- const newProps = {
- ...props,
- ...slots,
- // In Solid SSR mode, `ssr` creates the expected structure for `children`.
- children: children != null ? ssr(`<astro-slot>${children}</astro-slot>`) : children,
- };
- const html = renderToString(() => createComponent(Component, newProps));
- return { html };
-}
-
-export default {
- check,
- renderToStaticMarkup,
-};
diff --git a/packages/integrations/solid/client.js b/packages/integrations/solid/src/client.ts
index fa8cabcc0..b58bdd0b8 100644
--- a/packages/integrations/solid/client.js
+++ b/packages/integrations/solid/src/client.ts
@@ -1,17 +1,17 @@
import { sharedConfig } from 'solid-js';
import { hydrate, render, createComponent } from 'solid-js/web';
-export default (element) =>
- (Component, props, slotted, { client }) => {
+export default (element: HTMLElement) =>
+ (Component: any, props: any, slotted: any, { client }: { client: string }) => {
// Prepare global object expected by Solid's hydration logic
- if (!window._$HY) {
- window._$HY = { events: [], completed: new WeakSet(), r: {} };
+ if (!(window as any)._$HY) {
+ (window as any)._$HY = { events: [], completed: new WeakSet(), r: {} };
}
if (!element.hasAttribute('ssr')) return;
const fn = client === 'only' ? render : hydrate;
- let _slots = {};
+ let _slots: Record<string, any> = {};
if (Object.keys(slotted).length > 0) {
// hydrating
if (sharedConfig.context) {
@@ -28,6 +28,7 @@ export default (element) =>
}
const { default: children, ...slots } = _slots;
+ const renderId = element.dataset.solidRenderId;
fn(
() =>
@@ -36,6 +37,9 @@ export default (element) =>
...slots,
children,
}),
- element
+ element,
+ {
+ renderId
+ }
);
};
diff --git a/packages/integrations/solid/src/context.ts b/packages/integrations/solid/src/context.ts
new file mode 100644
index 000000000..c7b6cc392
--- /dev/null
+++ b/packages/integrations/solid/src/context.ts
@@ -0,0 +1,28 @@
+import type { RendererContext } from './types';
+
+type Context = {
+ id: string;
+ c: number;
+}
+
+const contexts = new WeakMap<RendererContext['result'], Context>();
+
+export function getContext(result: RendererContext['result']): Context {
+ if(contexts.has(result)) {
+ return contexts.get(result)!;
+ }
+ let ctx = {
+ c: 0,
+ get id() {
+ return 's' + this.c.toString();
+ }
+ };
+ contexts.set(result, ctx);
+ return ctx;
+}
+
+export function incrementId(ctx: Context): string {
+ let id = ctx.id;
+ ctx.c++;
+ return id;
+}
diff --git a/packages/integrations/solid/src/server.ts b/packages/integrations/solid/src/server.ts
new file mode 100644
index 000000000..bd50d8d77
--- /dev/null
+++ b/packages/integrations/solid/src/server.ts
@@ -0,0 +1,45 @@
+import type { RendererContext } from './types';
+import { renderToString, ssr, createComponent } from 'solid-js/web';
+import { getContext, incrementId } from './context.js';
+
+const slotName = (str: string) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
+
+function check(this: RendererContext, Component: any, props: Record<string, any>, children: any) {
+ if (typeof Component !== 'function') return false;
+ const { html } = renderToStaticMarkup.call(this, Component, props, children);
+ return typeof html === 'string';
+}
+
+function renderToStaticMarkup(this: RendererContext, Component: any, props: Record<string, any>, { default: children, ...slotted }: any, metadata?: undefined | Record<string, any>) {
+ const renderId = metadata?.hydrate ? incrementId(getContext(this.result)) : '';
+
+ const html = renderToString(() => {
+ const slots: Record<string, any> = {};
+ for (const [key, value] of Object.entries(slotted)) {
+ const name = slotName(key);
+ slots[name] = ssr(`<astro-slot name="${name}">${value}</astro-slot>`);
+ }
+ // Note: create newProps to avoid mutating `props` before they are serialized
+ const newProps = {
+ ...props,
+ ...slots,
+ // In Solid SSR mode, `ssr` creates the expected structure for `children`.
+ children: children != null ? ssr(`<astro-slot>${children}</astro-slot>`) : children,
+ };
+
+ return createComponent(Component, newProps);
+ }, {
+ renderId
+ });
+ return {
+ attrs: {
+ 'data-solid-render-id': renderId
+ },
+ html
+ };
+}
+
+export default {
+ check,
+ renderToStaticMarkup,
+};
diff --git a/packages/integrations/solid/src/types.ts b/packages/integrations/solid/src/types.ts
new file mode 100644
index 000000000..5dff5b0b4
--- /dev/null
+++ b/packages/integrations/solid/src/types.ts
@@ -0,0 +1,4 @@
+import type { SSRResult } from 'astro';
+export type RendererContext = {
+ result: SSRResult;
+};