Previously on stupid mini tools, we built Hen and if you were one of the people who went through the source code and commits, You might have noticed that I tried 2 approaches to get the preview working.
- Created an in-code sandbox and run the component there
- Created an iframe and gave it access to all the resources it needed.
Now obviously the Iframe way is a lot more simpler and easier to go about and creates a perfect sandbox where the code inside doesn't impact the whole application.
But I did that because I had to publicly let hen be used.
And had the assumption that other providers of the Live playground, like BaseWeb or Vercel's Geist Design were also setting up iframe's for the previews but much to my surprise they had the in-code sandbox.
So, I started thinking about it again and instead of messing with the original code of hen, I started a experimental project where I'd test the security vulnerabilities of this approach and try to fix/block them as much as I can.
We'll go through the base of the approach on how you should be going through to create an in-code code sandbox. This is specific to react but you can obviously extend and modify as needed. I'm only going to layout the Algorithm for you and you can go ahead from there. As for people who really need to check for the source code, you can head over to the github link at the end.
- Transform JS/JSX to JS and Parse an AST
- Get hold of the React Node and Convert it back to JS.
- Create a wrapper component of the react node
- Pass down package dependencies
- Render it into a container.
Let me go through the points in a little more detail.
You take in the code and now convert it into an AST using something like
acorn, an AST or Abstract Syntax Tree is a structure of the source code in a tree format. Basically, it creates a nested object of objects and array that represent the code you provide it with and then you can use that information or tree to covert the input to other languages etc. In our case, this is the react code that we type and it's compiled into
React.createElementusing Babel(@babel /standalone) in the browser and then we pass it to acorn to get the AST.
We browse through this AST to pull out only the React node
Then create a wrapper for it but before creating the wrapper we use something like
escodegento regenerate the JS code from the AST node.
The above generated string is passed to
new Function([args],generateCode)to give us a function with the component definition.
We basically store the above component generation code into a variable and then render it onto the dom like any other React component
Now if all of that went above your head and going through the source code would help you better.