We are finally able to let you in on a secret: in January we successfully ran the first WebContainer projects on Safari. Today we are excited to announce that
WebContainers run on Safari, iOS, and iPadOS 🥳
Starting with iOS 16.4, you can enjoy the interactive code examples and playgrounds right from an iPhone or iPad.
Safari support is now in beta, and we’d love to extend a warm invitation to you to try running a Node.js app in WebContainers on your iPhone or iPad and let us know what you like, don’t like, and what bugs you find 💙
Building for the stable future
StackBlitz was created with the mission to build the web with the web. This was a futuristic idea and as such, it required tools of the future.
StackBlitz was built to be shockingly fast, and to accomplish this we needed to hack and leverage emerging technologies. Two years ago, we laid Wasm threads at the foundation of WebContainers. Even today, the threads are still yet to become a standard. Similarly, our editors use SharedArrayBuffer
, a modern JavaScript feature which uses multiple JavaScript threads to share the same memory space.
We knew that choosing SharedArrayBuffer
 meant initial limited support for Safari - but we also guesstimated that by the time WebContainers reached stability, SharedArrayBuffer
should ship in Safari. We were quite close - WebContainers became stable in March 2022 and SharedArrayBuffer
officially landed less than a year later.
We had a choice. We knew that we could decide against WebAssembly threads or use a hacky walkaround and make WebContainers work on iOS a long time ago. But we chose to not do that. Instead, we embraced the direction where the web was going. By joining the Bytecode Alliance, we are able to build the web we want to see, more effectively. We wanted to build something that will inspire and lead others towards the things you can do with browsers. The decision couldn’t be more correct in retrospect - millions of developers use WebContainers on a monthly basis. And, because we choose the future, we are trailblazers in spotting bugs like the recent M1 issue, or the one with threads in Firefox. Also, not only did we spot a COEP bug in Safari but our engineer Roberto Vidal debugged it and provided a test case to speed up the resolution:
At this point, we’d love to give a shoutout to Chris Dumez, WebKit contributor at Apple, who helped us with a quick turnaround with the bug. We really appreciate that 💙
Today, the tools that were once deemed “too modern” are already here - and we’ve built and optimized our architecture around them. As a result, WebContainers run in complex projects like Codeflow or SvelteKit’s tutorial, significantly faster than locally.
And we are still optimizing.
StackBlitz is all about building for a sustainable future - and not for the past. We have time and as the web is catching up, we are improving our tools, growing our community, and finding new pathways to support Open Source ecosystem in meaningful ways.
Running Node.js apps on Safari
Besides SharedArrayBuffer
landing in the browser, also other changes and improvements needed to be in place for WebContainers to run on Safari.
Most developers don’t think much about the differences between browsers - not only in terms of the UI but also how they actually work and why. Each browser has its own rendering engine (Blink in Chrome, WebKit in Safari, Gecko in Firefox) responsible for drawing text and images on the screen - in other words, working with HTML and CSS. Each browser also has its own JavaScript engine, which executes JavaScript code. These are: V8 for Chrome (also used in Node.js), JavaScriptCore in Safari, and SpiderMonkey in Firefox. (A fact that may not be commonly known is that every iOS browser “must use the appropriate WebKit framework and WebKit JavaScript”. This means that under the hood every browser used on iOS and iPadOS is effectively a reskinned version of Safari.)
Both the rendering and the JavaScript engines are built in reference to specs, which provide some clarity on what should happen when certain code is executed. However, there are many areas unspecified by a spec, in which case browser vendors interpret it in their own ways and extend it according to their goals. This results in browser incompatibility, which most commonly comes to light when your carefully-designed website is run on a browser different than yours. In our case, we needed to tackle two main discrepancies: stack traces, and memory allocation.
Error stack traces
Let’s start with error stack traces, which is the information provided to you by an Error
instance about which functions were called, in which file and line, and in which order. Given that the Chrome’s stack trace looks like that of Node.js, it may come as a surprise to you that we can’t programmatically rely on and assume that other browsers follow the same format. In fact, they do not. Let’s have a look at stack traces in Safari and Chrome:
In order for any project to work across all browser environments, we needed to make sure that there was a high degree of uniformity, also in stack traces. Sam Verschueren ironed out these differences. He explained the process in the following way:
Chrome enables
prepareStackTrace
, which means that you can access information like line number, column number, file names, method names. You can get it natively out of V8 as a neat object with all the information. However, that’s not the case with SpiderMonkey (Firefox) or WebKit (Safari).
With WebKit and SpiderMonkey one needs to parse the blob of text to get out the line number and file name. Also, you cannot infer all of the information - nor is all of the information there. And because WebKit does not supportsourceMappingURL
, you also can’t rename the generated bundles.
This is not the first time, we had to tackle stack trace discrepancies - a year ago, our engineer Roberto Vidal described the process of bringing WebContainers to Firefox, as well as the bugs we spotted along the way.
Memory allocation limitations
Once we dealt with stack traces and WebContainers ran on desktop Safari, there was another obstacle: the memory constraints on mobile devices. Even though an iPhone has up to 8 GB RAM, not all of this memory can be allocated to running processes inside the browser. In other words, there are strict limitations on how much memory a webpage can use. Dominic Elm took a few hours to investigate the blockers and debug it on his iPhone and iPad to see which solutions offered the best fit. To address the memory limitation hurdle, we restricted the amount of memory WebContainers are allowed to consume on mobile devices and have been enjoying browsing docs that feature StackBlitz playgrounds ever since.
That said, there still is an existing limitation resulting from how Safari handles memory management on mobile devices (and sometimes, also desktop ones), which result in memory leaks when you refresh a page. Dominic Elm explains the problem in the following way:
When WebContainer boots, it allocates a bunch of memory, for example for the file system. With other browsers, when a browser tab or page is reloaded, all resources (including allocated memory) for that tab should be freed so that they can be reused.
However, in Safari on mobile devices if you reload the page, the resources do not always seem to be freed. This means that you may run into “Out Of Memory” issues on a second load.
In the meantime, we have implemented an intermediary workaround - a redirect to another domain when we detect iOS/iPad, and back to the original page, which forcer Safari to free the resources. However, ideally this wouldn’t be necessary so we are monitoring this bug report on WebKit.
WebContainer compatibility today
This means that today, WebContainers are supported on all devices and in all recent desktop browsers, namely:
Desktop browsers
-
Chrome: full support.
-
Other Chromium-based browsers: full support. Some browsers may apply restrictive rules by default, and require specific configuration, like Brave.
-
Firefox: beta support (see details).
-
Safari: beta support since Safari 16.4 (see details).
Mobile browsers
-
Android: beta support for Chrome, Chromium-based browsers and Firefox. Depending on your device, large projects may run into memory limitations.
-
iOS and iPadOS: beta support for Safari since iOS 16.4. Large projects may run into memory limitations because the memory usage for a web page on a mobile device is more constrained. In this case, we recommend switching to a Desktop browser that is less constrained and has more memory.
What’s next?
WebContainer support for Safari is in beta. We dearly invite you to stress-test it and tell us about it. As with any new feature or compatibility, we expect that we haven’t squashed all bugs yet and hope you will join us in this jolly hunt.
Meanwhile, our team members are looking to extend the experience even further:
Jokes aside, we dedicate this year to not only shipping much-requested features but also improving the Developer Experience across all StackBlitz tools.
This quarter alone we will be shipping major improvements, for which we’ll need folks who use StackBlitz and would love to test them:
We love the web and it is our mission to push the it forward - thank you for helping us make this journey exciting.