Skip to content

Instantly share code, notes, and snippets.

@lutfi-haslab
Created May 14, 2025 05:11
Show Gist options
  • Save lutfi-haslab/27652da5b9fc1cd31bec1ddad5ea7973 to your computer and use it in GitHub Desktop.
Save lutfi-haslab/27652da5b9fc1cd31bec1ddad5ea7973 to your computer and use it in GitHub Desktop.
babel react compiler to html
import { availablePresets, registerPreset, transform } from "@babel/standalone";
import {
type TailwindConfig,
createTailwindcss,
} from "@mhsdesign/jit-browser-tailwindcss";
registerPreset("tsx", {
presets: [
[availablePresets["typescript"], { allExtensions: true, isTSX: true }],
],
});
export const compileTypescript = async (code: string) => {
const compiledComponent: any = babelCompile(code, `Section.tsx`);
const app = `
import React, { useEffect } from 'react';
import { createRoot } from 'react-dom';
import Section from './Section.tsx';
const App = () => {
return (
<>
<Section />
</>
)
}
createRoot(document.querySelector("#root")).render(<App />)
`;
// Transform the code from TSX to JS
const output = babelCompile(app, "index.tsx");
// Have CSS generated from Tailwind
const tailwindConfig: TailwindConfig = {
theme: {
extend: {
colors: {},
},
},
// plugins: [typography]
};
const tailwindCss = createTailwindcss({ tailwindConfig });
const css = await tailwindCss.generateStylesFromContent(
`
@tailwind base;
@tailwind components;
@tailwind utilities;
`,
[compiledComponent.code, output.code],
);
const html = `<!DOCTYPE html>
<html lang="en">
<head>
<style>${css}</style>
</head>
<body style="background-color:#fff">
<div id="root"></div>
<script crossorigin defer src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script crossorigin defer src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
<script defer>window.addEventListener("DOMContentLoaded", () => {${[
compiledComponent.code,
output.code,
].join("\n")}});</script>
</body>
</html>
`;
return html;
};
// Transforms the TSX code to JS
const babelCompile = (code: string, filename: string) =>
transform(code, {
filename: filename,
plugins: [
[
"transform-modules-umd",
{
globals: { react: "React", "react-dom": "ReactDOM" },
},
],
],
presets: ["tsx", "react"],
});
import { useEffect, useRef, useState } from "react";
import { compileTypescript } from "~/utils/compiler";
interface MyProps extends React.HTMLAttributes<HTMLDivElement> {
code: string;
}
export const PageEditor = ({ code }: MyProps) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
const [dom, setDom] = useState<string | undefined>(undefined);
const svgRef = useRef<SVGSVGElement>(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
// Compile and render the page
const compileCode = async () => {
const compiledCode = await compileTypescript(code);
setDom(compiledCode);
};
// We resize the canvas to fit the screen. This is not ideal, but it works for now.
const handleResize = () => {
const iframe = iframeRef.current;
if (!iframe) return;
const { contentWindow } = iframeRef.current;
if (contentWindow) {
const { documentElement } = contentWindow.document;
const width = documentElement.clientWidth;
const height = documentElement.clientHeight;
setDimensions({ width, height });
}
};
handleResize();
window.addEventListener("resize", handleResize);
// Compile the code
compileCode();
return () => {
window.removeEventListener("resize", handleResize);
};
}, [code]);
const handleScroll = (event: React.WheelEvent) => {
if (!iframeRef.current) return;
if (!iframeRef.current.contentWindow) return;
iframeRef.current.contentWindow.scrollBy(0, event.deltaY);
// scrollTop = iframeRef.current.scrollTop + event.deltaY;
};
return (
<div className="absolute inset-0 flex justify-center">
<div
className="absolute inset-0 overflow-hidden rounded-b-lg"
onWheel={handleScroll}
>
<iframe
width="100%"
height="100%"
tabIndex={-1}
title="The editor's rendered HTML document"
srcDoc={dom}
ref={iframeRef}
className="pointer-events-none mx-auto my-0 block w-full min-w-[769] overflow-hidden border-0"
/>
<div className="pointer-events-none absolute inset-y-0 flex max-w-full">
<svg
id="SVGOverlay"
className="overflow-visible"
width={dimensions.width}
height={dimensions.height}
ref={svgRef}
// style="transform: translate3d(0px, 0px, 0px);"
>
<rect id="SVGSelection"></rect>
<rect id="SVGHover"></rect>
</svg>
</div>
</div>
</div>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment