A while ago I googled "run code snippets on my blog" but did not find a simple lib to do that.

How about embedding from a specialized website ? All those bytes loaded to run 3 lines of code is way too much.

This helloworld snippet embed loads 66k with JSFiddle, 243k with Codepen, and 191k with js-code-runner. JSBin embeds are only available for pro users.

<!-- {"name": "hello html", "type": ""} -->
<span class="hello">hello world</span>
/* {"name": "hello css", "type": ""} */
.hello { color: #0000FF; }
// {"name": "hello js", "link": ["hello html", "hello css"], "height": 5}
console.log("hello world");

So how can I run that damn snippet right now like it's done on StackOverflow ?

After a few dangerous experiments, lots of reading, thinking and coding, I wrote a Snippet class with the following features :

  • Clear UI, mobile-friendly
  • Run HTML, CSS and VanillaJS codes snippets
  • Handle async / await
  • Inject output and console below code
  • Link blocks (avoid code duplication)
  • Pipe console calls to main window
  • Catch errors
  • Load external JS and CSS files
  • Reload snippet
  • Performance test
  • Load alongside syntax highlighters
  • No dependencies
  • No eval or function constructor
  • 5k JS + 1k CSS 🤪

Snippets are running in sandboxed iframes, with allow-scripts restriction lifted.

allow-same-origin is highly discouraged and not enabled, therefore snippets should not be able to read sensitive data from the browser.

Console calls are redirected via postMessage to the main window. These messages cannot be trusted since event.origin is always "null". I found an other solution to validate messages : run Array.find on global snippets list and triple check against event.source (iframe contentWindow).

// {"name": "origin", "body": false, "height": 2}
console.log("location.origin", window.location.origin);
console.log("location.href", window.location.href);

A <meta> CSP tag should be added in page <head> to prevent snippets from loading untrusted content or navigate to other pages.

Still reading things about iframe security :

owasp / mdn / html5rocks

Notes :

  • error messages are not the same in all browsers
  • maybe fallback to blob & iframe src attribute for old browsers
  • experimental iframe.csp attribute
  • Safari MacOs & iOs doesn't throw error when accessing document.cookie
  • WeChat embeded browser only accepts src="{url}", no src blob, no srcdoc, must generate html file fallback for all snippets.
  • getUserMedia throws an error because origin is not trusted

How to :

  • copy & paste script and stylesheet
<script src="snippet.min.js" integrity="sha384-THhgUEZp+PMd/zlx4BMEuqkbwZOJajJFyNCA0n445itJX9r4YSERtFMDja9gKjn/"></script>
<link rel="stylesheet" href="snippet.min.css" />
  • add class "language-html", "language-css", or "language-js" to your codes
  • configure options, comment line JSON inserted at the beginning of each code you want to run or link
<!-- {"name": "HTML snippet", "type":""} -->
/* {"name": "CSS snippet", "type":""} */
// {"name": "JS snippet", "type":""}
  • or <code> data-snip attribute, URI-encoded JSON
<code class="language-js" data-snippet="%7B%22name%22:%20%22my%20snippet%22%7D">
  • configure options (must be valid JSON)
option type description default
name string snippet name ""
type string "run", "perf", "pre", "post", "" (no run) "run"
body boolean enable/disable iframe true
console boolean enable/disable console true
link array<string> snippet names to link []
js array<string> scripts urls to load []
css array<string> stylesheets urls to load []
insert boolean insert snippet frame and console true
height string snippet height "200px"
  • load snippets with the following code
document.querySelectorAll("code[class^=language-]").forEach(code => new Snippet(code));

Performance :

To run performance test on a snippet, simply set "perf" type :

// {"name": "perf test", "type": "perf", "body": false}
for(let i = 0; i < 3; i++) {}

Read this great article by the author of Benchmark.js, and a short explanation on StackOverflow

Performance test is very simple and inefficient for now.

Steps :

  • remove all console calls
  • run pre code
  • wild loop snippet code for one second
  • count iterations over time
  • run post code
  • reload iframe
  • repeat 9 times
  • compute average & median

Examples :

Simple HTML example

<!-- {"name": "html example", "console": false} -->
<h1>some title</h1>
<span>some span</span>

Linked HTML & CSS

<!-- {"name": "html and css example", "type":""} -->
<div class="square red"></div>
<div class="square green"></div>
<div class="square blue"></div>
/* {"name": "css example", "link": "html and css example", "console": false} */
.square {
	display: inline-block;
	width: 30px;
	height: 30px;
}

.red { background-color: #FF0000; }
.green { background-color: #00FF00; }
.blue { background-color: #0000FF; }

HTML & JS Video

<!-- {"name": "video html", "type":""} -->
<video controls muted autoplay playsinline>
    <source src="https://blog.ilusio.dev/videos/bbb.mp4" type="video/mp4">
    <source src="https://blog.ilusio.dev/videos/bbb.webm" type="video/webm">
    Your browser does not support the video tag.
</video>
<!-- {"name": "video css", "type":""} -->
body {
    margin: 0;
}

video {
	width: 100vw;
    max-width: 100%;
    height: 100vh;
    outline: none;
}
// {"name": "video js", "link": ["video html", "video css"]}
let video = document.querySelector("video");
console.log(video);
video.addEventListener("play", event => console.log("play"));
video.addEventListener("pause", event => console.log("pause"));
video.addEventListener("ended", event => console.log("end"));

More examples here.

Packaging

A lot of messing around with Closure Compiler to reach 4.65k minified JS code, I will write about that later.

CSS is minified with Closure Stylesheets. // now SASS

Download

This is the very first version, testing purpose only, not ready for production.

No guarantees, no support, no responsibility.

Use at your own risks 💣

Enjoy 🌈

https://github.com/nicopowa/snippet

Run HTML, CSS and JavaScript code snippets

Lightweight code to run HTML CSS JS on your website in minutes