This is the sandbox used by the CodeSandbox site, and whilst it did look promising the whole system appears to be built around React components. After a bit of experimenting I realised that the sandpack-client library is only the front end of the system, you need to host a backend bundler to get everything working and that needs to be hosted.Hosting code examples on a third party site also comes with some risk as if that site went offline then all of the code examples on my site would stop working. By self hosting I can make the editing experience better and also ensure that everything works correctly.This works very well, in fact I was able to edit the code in the sandbox to add in a canvas element that displays random flowers on a green background.This system works very well. Here is an example of an embedded paragraph that has Flems support. The code example shows how the different points of the bezier curve in the canvas API are placed. You can fiddle with some of the parameters in the JavaScript file to see them update in the output, which is updated every second.Whilst possible, I want to try to avoid this approach since it would mean creating a system that could potentially lead to security problems, and embedding that into the site. I would much rather pick a pre-existing package, draw attention it how good it is, and maybe even contribute to it.This project initially looked like hosted product, but is actually a decent system that is self contained in a small set of JavaScript files. It doesn’t need complex build steps or a back end server to run as it can all run inside the browser. The only downside is that does connect to the livecodes.io domain when embedding, which contains a couple of cheeky analytics cookies that can’t be disabled. Due to the way the app is created that isn’t easy to turn off either.A (by no means comprehensive) analysis of code sandboxes that allow (or at least say they allow) some form of self hosted solution. This took quite a few hours of digging through search results and finding examples.
A Quick Analysis Of Code Sandboxes
You can see the controller in action on the page https://www.hashbangcode.com/code-sandbox-test-page, which I have changed since writing the above code to show more of the tool in action. The script above doesn’t quite respect the white space of the original code, but it gets the central ideas across. Feel free to give it a go!
Playground Elements
I know that it’s possible to embed Codepen examples into a page, but not only does that require a premium subscription, it also creates a disconnect between the code and the content on the site. I wanted a solution that would allow me to write the article and the code examples all within the back end of the Drupal site.Link: https://codapi.orgAfter digging through a few entity embed modules I decided that the best course of action is to use the Paragraphs Entity Embed module. This is an implementation of the Entity Embed module that allows Paragraphs to be injected into CKEditor fields. Using this system solves many of the issues I would have otherwise encountered if I had attempted to develop this system from scratch, including making the CKEditor dialog for the entity to be managed.If you know of any other self hosted code sandboxes that fit the model I was looking for then please let me know.
Sandpack Client
{% set jsValue = paragraph.field_javascript.0.value|replace({'`': '`'}) %}
{% set htmlValue = paragraph.field_html.0.value|replace({'`': '`'}) %}
{% set cssValue = paragraph.field_css.0.value|replace({'`': '`'}) %}
<div id="container-{{ paragraph.id() }}" class="flems-container"></div>
{% set selected = (paragraph.field_selected_file.0.value|raw == 'html') ? 'index.html' : (paragraph.field_selected_file.0.value|raw == 'css') ? 'styles.css' : '.js' %}
<script>
const container{{ paragraph.id() }} = document.getElementById("container-{{ paragraph.id() }}");
const flems{{ paragraph.id() }} = Flems(container{{ paragraph.id() }}, {
files: [
{% if jsValue %}
name: 'app.js',
type: 'script',
content: `{{ jsValue|raw }}`,
},
{% endif %}
{% if htmlValue %}
{
name: 'index.html',
type: 'document',
content: `{{ htmlValue|raw }}`,
},
{% endif %}
{% if cssValue %}
{
name: 'styles.css',
type: 'style',
content: `{{ cssValue|raw }}`,
},
{% endif %}
],
middle: 50,
selected: '{{ selected }}',
color: 'rgb(60, 60, 60)',
theme: 'material',
shareButton: false,
autoReloadDelay: 1000,
});
</script>
The first step in this was making a *.libraries.yml file so that we can inject the flems.html file.Now I have confirmed that this was all working correctly I needed to update Drupal to accept the user input and generate the needed output for the page.
Codeapi
$flemsScript = <<<'EOD'
<div id="container" class="flems-container"></div>
<script>
const container = document.getElementById("container");
const flems = Flems(container, {
files: [{
name: 'app.js',
type: 'script',
content: `console.log(`Hello from JS!`);`,
},
{
name: 'index.html',
type: 'document',
content: '<p>Test</p>',
},
{
name: 'styles.css',
type: 'style',
content: 'p {color: blue; font-size: 30px}',
},
],
middle : 50,
selected : 'app.js',
color : 'rgb(60, 60, 60)',
theme : 'material', // Can be material, none or default.
resizeable : true,
editable : true,
toolbar : true,
fileTabs : true,
linkTabs : true,
shareButton : false,
reloadButton : true,
console : true,
autoReload : true,
autoReloadDelay : 1000,
autoHeight : false,
});
</script>
EOD;
$build['flems'] = [
'#markup' => $flemsScript,
'#allowed_tags' => ['script', 'div', 'p'],
];
In this article I will look at a few code sandboxes and how they might be integrated into Drupal. I’ll then look at one code sandbox in particular and allow this to be embedded into article content.The fact that it essentially “phones home” to gather most of it’s assets (and doesn’t respect my sites cookie policy) put me off the tool quite a bit.
LiveCodes
What I needed for the site now was some form of code sandbox that could be used to demonstrate simple JavaScript and CSS code without being tied to a third party supplier. I therefore did some searching around to find a suitable container for the code.Being created by Google I did have some high hopes for this sandbox, and appears to have a lot of the features I was looking for. The package states that code written in a number of different languages can be run directly in the browser, all without the need for a back end server.What I wanted to do was set up a quick proof of concept before jumping into configuring an entity to allow user content to be added through the Drupal CMS. To that end I created a small module with a single controller so that I could add the needed HTML required for Flems to work.The embedded code examples need to exist alongside the current <code> tags, which are useful in themselves for presenting code and breaking down how things work, rather than always having a full code sandbox.Another solution is to build something custom involving an iframe, which is the technology used in most of the above systems. HTML5 introduced the sandbox attribute, which provides additional restrictions to further enhance the security of iframe sandboxing and is perfect for this purpose.
Flems
There are some details I haven’t included here, especially around permissions, but this shows the basic usage of the template. With regards to permissions, I currently only allow site administrators access to this embed feature. I certainly don’t intend for anonymous users to embed sandboxes since it does lack security and infinite loop detection.I make use of sites like Codepen and JSFiddle quite a bit, and often link to those sites to show examples of the code in use. Those sites got me thinking about the static nature of the code examples on this site. I have been writing more front end code recently, but static code examples aren’t the best way of showing these features in action. I can (and have) uploaded images and gifs of the feature in action, but those images are many times the size of the code examples in question and serve only to bloat the page.In the end I went with Flems as the solution to embedding code sandbox in Drupal. It is a little out of date but the system does exactly what I want and I can always fork and modify it as needed (which I have done). I have also created PRs to contribute those changes back to the original package.I have just touched the service of Flems in this article as package can be pushed quite far. It already has support for TypeScript, but it is possible to inject third party packages into the output to extend what it can do. There are examples of injecting Mithril.js into the script to create single page applications, so I can see adding things like Three.js or GSAP to create fully featured demos.The paragraph template file first sets up the content of the tabs in the code sandbox, injects them into the template as a files array, and sets up the selected tab. As the files are always called app.js, index.html, and styles.css and so we can set up the file as a default.The instructions that come with Flems are pretty bare bones, but they get the job done. All we need to do is include a single HTML file as a JavaScript include and then we can run the Flems system from within the page. Several configuration options exist for the tool to be customised in different ways, including files, links, colours, tabs, and read only modes.The module and associated config isn’t tightly coupled to Flems, so it should be possible to swap out for a similarly functioning package. As long as the concept of three different files exists (ie, js, html, css) then the JavaScript component could be converted into a plugin.
Custom Build?
The Drupal integration took a little bit of time and I had some interesting technical challenges to overcome. The module I created is as generic as possible so that it isn’t tied into this site and could potentially become a contributed module. I haven’t tied the module to Flems in order to allow a different code sandbox mechanism to be plugged in further down the line. If I get enough interest in creating a contributed module then I’d be happy to spend some time doing just that.Using this system, it is possible to inject multiple code sandboxes into the page via the CKEditor field. As I have used the Paragraphs Entity Embed module I can also share code sandboxes between pages once they have been created.
Integrating Flems Into Drupal
The package also comes with the ability to run TypeScript and LiveScript files (which are compiled at runtime) so that’s also a plus. The editor uses CodeMirror, which means that it has good browser support as CodeMirror is quite a nice little JavaScript code editor.I wasn’t looking for a system that required a backend system to work (I mean outside of Drupal) and so this seemed a little too complex for what I was looking for.I will keep this test page in place as a quick way to make sure that the plugin works in a testing environment.I thought a bit about how to add the needed data into Drupal to allow the code examples to be embedded correctly inside content. What I needed was a mechanism that would allow me to add code examples into CKEditor fields in the same way that code blocks or images would be added.After a little bit of tinkering I managed to get the LiveCodes system working in Drupal; with the code being injected into a LiveCodes include and presenting the code. This package is almost ideal for this purpose and can be configured quite a lot using a pretty simple JSON array. Also, it has a dark mode, which means it wouldn’t be out of place on this site.The variable created by the script to the render array for the controller using the markup Drupal formatter. We also pass in some allowed HTML tags so that the tags we include in the nowdoc do not get stripped out when rendered.Link: https://livecodes.ioWhen we load the controller we now see the following.The addition of the Paragraphs module allows me to easily create the entity I need and inject the code into without necessarily needing to create any custom field or complex formatters. What I needed is a set of fields for the needed JavaScript, HTML, and CSS “files” that we can then render into the editor. I also needed a select field to inject a value into the selected configuration item.Although Playground Elements professes that it is easy to install, I had lots of trouble getting this to do anything at all. Not only that, but all of the examples I found of the system apparently in action don’t seem to work either. I spend an hour or so trying to get this running in Drupal, but gave up and I can only assume that it doesn’t work at all since I’ve not seen any examples of it functioning.
flems.html file as a JavaScript include, which seems a little strange, but it all works. What’s more, it doesn’t call out to third party websites to download random files.Link: https://github.com/google/playground-elements
Configuring Drupal Entities
I can probably do without another Google integration in my life, and since the package doesn’t appear to work I decided not to use it. My guess is that Google has just stopped supporting it and let it die.To integrate Flems into Drupal I downloaded the latest version of the package from the git repository and then built the core flems.html file. To do this I just used the npm install command, followed by npm run build within the Flems directory. This generates a dist directory, which is where the all important flems.html file lives.flems:
header: true
js:
js/flems/dist/flems.html: { attributes: { type : 'text/javascript', charset : 'utf-8' } }
Flems has a full example site at https://flems.io that might be worth a look if you are interested in seeing the full potential of the package.Here is the relevant section from the paragraph file.
Conclusion
Here is the paragraph fields created.An interesting project that contains lots of different playgrounds to run various different languages, with JavaScript being bundled with the system. Other languages need a backend system to process correctly.I’ve been running this site for about 18 years now and the code I post has been in much the same format since it was started. The code is rendered onto the page using a <code> element and (mostly) syntax highlighted using a JavaScript plugin.The system is built around JavaScript, CSS, and HTML files with extensions to systems like React and Vue. LiveCodes does have a stand alone desktop app that can be used for quick prototyping of applications. The documentation of the system is quite good (with a couple of gaps here and there) and describes all of the options in detail, with examples.In fact, the only real problem with Flems is that it hasn’t been updated for a few years. The packages have been bumped in recent years to cover security issues, but the last real update was done in 2022. Not a massive issue, but something to be aware of.The downloaded flems.html file is around 140KB, which is sort of on the large side, but that is for the JavaScript, HTML, and CSS for the plugin. There are no other files downloaded for Flems to work, it just needs the in page script to initialise it.This project took a while to put together. Finding a decent JavaScript library that would work (and behave correctly) was a real challenge and took a number of hours to find a good fit to what I wanted. Flems isn’t perfect, but I have already made a couple of contributions to the project to allow it to work with Drupal. My main issue with it currently is that it isn’t very accessible, but I am also looking into what is needed to correct that. I’m sure that the file size can also be reduced if some of the options are removed from the final build.Link: https://sandpack.codesandbox.io/docs/advanced-usage/client Whilst the system works quite nicely I was looking for something to show off CSS rules in action, and this editor doesn’t do that quite yet. It’s a good little tool when you want to run any sort of code in a browser and I may look into it for other languages on the site.



