You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Alakazam Live Components should generate components (in Kaz AST format) that will fetch the component, and then transform the component to targets (using Kazam).
Tasks
Create the Preact+htm transformer Use it to render the component at client side because it is very lightweight (3kb + 0.5kb).
Implement an alakazam option in the transformer service that will allow to download the "Alakazam Live Component"
Create the Alakazam Live Component API endpoints It is in charge to return a script that will render the component at client-side.
Add a button to download the Alakazam Live Components
EDIT
Create the service worker
Convert the get-live-component endpoint to GET to allow caching
Use two fetch in the Alakazam Client component (the first one with cache: "force-cache" (awaited) and the second one with cache: "reload" (not awaited))
Evaluate if it is better to use esbuild with the HTTP plugin (https://esbuild.github.io/plugins/#http-plugin) to prebuild Preact and HTM, instead of making additional requests but cached
EDIT 2
Currently, the returned Alakazam client component for React is something like this:
import*asReactfrom"react";import{useEffect}from"react";exportdefault()=>{React.useLayoutEffect(()=>{constcomponentSelector=`alakazam-component#_ymuy8OGnN1ax5eDEYjW4r8ASnnQDsqXfZwurTqbiuu8`;constcomponent=document.querySelector(componentSelector);if(component===null){thrownewError(`Alakazam component with ID "_ymuy8OGnN1ax5eDEYjW4r8ASnnQDsqXfZwurTqbiuu8" not found`);}constALAKAZAM_PROPS_KEY="_alakazamProps";window[ALAKAZAM_PROPS_KEY]??=[];window[ALAKAZAM_PROPS_KEY]["_ymuy8OGnN1ax5eDEYjW4r8ASnnQDsqXfZwurTqbiuu8"]={};constfetchComponent=async(componentKey: string,propsAccessor: string,selector: string,signal: AbortSignal)=>{constcomponentUrl=newURL("http://localhost:3000");componentUrl.pathname="/api/get-live-component";componentUrl.searchParams.set("componentKey",componentKey);componentUrl.searchParams.set("propsAccessor",propsAccessor);componentUrl.searchParams.set("selector",selector);constfetchParams={priority: "high",method: "GET",
signal,headers: {"Content-Type": "application/json",},};constresponse=awaitfetch(componentUrl.toString(),{
...fetchParams,cache: "force-cache"});fetch(componentUrl.toString(),{
...fetchParams,cache: "reload"});returnawaitresponse.text();};// TODO: use AbortController to abort fetch if component is unmountedconstabortController=newAbortController();fetchComponent("eyJjb21wb25lbnRQYXRoIjoiL2NvbXBvbmVudHMvSW5wdXQua2F6IiwicHJvamVjdElkIjoiNWQwMTQ2OWMtYTQ1Mi0xMWVlLTkwNmYtNjMyMGYxNmJiODYyIn0=",`window[${JSON.stringify(ALAKAZAM_PROPS_KEY)}]["_ymuy8OGnN1ax5eDEYjW4r8ASnnQDsqXfZwurTqbiuu8"]`,componentSelector,abortController.signal).then((preactSource)=>{constscript=document.createElement("script");script.type="module";script.innerHTML=preactSource;component.appendChild(script);});},[]);return(<><alakazam-componentstyle={{cssText: "display: contents"}}id="_ymuy8OGnN1ax5eDEYjW4r8ASnnQDsqXfZwurTqbiuu8"></alakazam-component></>);};
We can optimize it by transforming it to something like this:
Create on:created argument (not instruction), allowing to use ref in React
Create const instruction which allow to define variables outside of the component
Use the const instruction to fetch the Alakazam component
Use the on:created argument to add the Alakazam component
EDIT 3
We may want to evaluate a function that takes a DOM element as parameter to use to render, instead of creating a script, adding this script to the DOM, search for an element with the corresponding id, etc.
Remove the script.type = "module"; to make the script priority higher (reference) (the component blinks 9 times over 10 with module, 2 times over 10 without)
This is the component generated by Alakazam Live Component:
importReact,{useRef,useEffect}from'react'constComponent=({ text }: {text: string})=>{constelementRef=useRef<HTMLDivElement>(null)useEffect(()=>{if(!elementRef.current){return}constabortController=newAbortController()awaitfetch(`https://alakazam.io/project-id/component-id?${newURLSearchParams({ text })}`,{ signal },).then((response)=>response.text()).then((liveComponentSource)=>{constliveComponent=newDOMParser().parseFromString(liveComponentSource,"text/html").body.firstChildasHTMLDivElement;elementRef.current.replaceWith(liveComponent);// Force running scriptsliveComponent.querySelectorAll("script").forEach((script)=>{constnewScript=document.createElement("script");script.getAttributeNames().forEach((name)=>{newScript.setAttribute(name,script.getAttribute(name)!);});newScript.innerHTML=script.innerHTML;liveComponent.removeChild(script);liveComponent.appendChild(newScript);});})return()=>{abortController.abort()}},[elementRef])return<alakazam-componentref={elementRef}/>}
This is a PoC of an implementation of the API endpoint:
exportdefaultasyncfunction(parameters: Record<string,string>)=>{constid=Math.random().toString(36).substring(2,9);// TODO: replace `const Component = ...` by the component generated by Kazam (with the `Preact`+`htm` transformer)return` <alakazam-component style="display: contents;" uid="${id}"> <script type="module"> import { h, render } from 'https://esm.sh/preact'; import { useState, useCallback } from 'https://esm.sh/preact/hooks'; import htm from 'https://esm.sh/htm/mini'; // Initialize htm with Preact const html = htm.bind(h); const Component = (props) => { const [state, setState] = useState(0); const increment = useCallback(() => { console.log('increment') setState((state) => state + 1) }, [setState]); const decrement = useCallback(() => { setState((state) => state - 1) }, [setState]); return html\`<h1> \${props.text} \${state} <button onClick=\${increment}>+</button> <button onClick=\${decrement}>-</button> </h1>\`; } render(h(() => Component(${JSON.stringify(parameters)})), document.querySelector('alakazam-component[uid="${id}"]')); </script> </alakazam-component> `;}
This version may be the most stable version, as it does not send the props via the fetch function. The props stay in a global variable, and this global variable is accessed locally by the component to render.
The text was updated successfully, but these errors were encountered:
Description
Alakazam Live Components should generate components (in Kaz AST format) that will fetch the component, and then transform the component to targets (using Kazam).
Tasks
Preact
+htm
transformerUse it to render the component at client side because it is very lightweight (3kb + 0.5kb).
alakazam
option in the transformer service that will allow to download the "Alakazam Live Component"It is in charge to return a script that will render the component at client-side.
EDIT
Create the service workerget-live-component
endpoint toGET
to allow cachingfetch
in the Alakazam Client component (the first one withcache: "force-cache"
(awaited) and the second one withcache: "reload"
(not awaited))EDIT 2
Currently, the returned Alakazam client component for React is something like this:
We can optimize it by transforming it to something like this:
To do that, we need to:
on:created
argument (not instruction), allowing to useref
in Reactconst
instruction which allow to define variables outside of the componentconst
instruction to fetch the Alakazam componenton:created
argument to add the Alakazam componentEDIT 3
script.type = "module";
to make the script priority higher (reference) (the component blinks 9 times over 10 with module, 2 times over 10 without)Examples
Example 1
(see the PoC working on Glitch: https://glitch.com/edit/#!/jagged-magic-cheetah)
This is the component generated by Alakazam Live Component:
This is a PoC of an implementation of the API endpoint:
Example 2
(see the PoC working on Glitch: https://glitch.com/edit/#!/ebony-remarkable-cymbal)
This version returns only a script as string.
Example 3
(see the PoC working on Glitch: https://glitch.com/edit/#!/catnip-fossil-geometry)
This version may be the most stable version, as it does not send the props via the fetch function. The props stay in a global variable, and this global variable is accessed locally by the component to render.
The text was updated successfully, but these errors were encountered: