# Fastmail: Announcing Squire 2.0

Squire is our rich text editor that powers the mail composer in Fastmail, providing support for formatting and WYSIWYG text editing in all modern browsers.


Now, there are a good number of rich text editors. However, most have the luxury of strongly limiting what the person can enter to ensure the data model doesn’t break. We can’t use those because we must be able to handle arbitrary HTML because it may be used to forward or quote emails from third parties and must be able to preserve their HTML without breaking the formatting. This is Squire’s advantage.

# Speeding up the JavaScript ecosystem – eslint

In today’s world for-of loops are supported everywhere, so I patched the package again and swapped out the function implementation with the original one in the source. This one single change saves about 400ms. I’m always impressed by how much CPU time we burn on wasteful polyfills or outdated downtranspilation.

So many libraries in our ecosystem suffer from this issue. I really wish there was a way to update them all with one click. Maybe we need a reverse transpiler which detects down transpilation patterns and converts it back to modern code again.

Top-level await in JavaScript REPLs is a hack

Today I learned that top-level await in JavaScript REPLs, such as Chrome’s Developer Tools console and Node.js REPL, is a BIG HACK!

Top-level await is a feature of JavaScript that allows you to use await outside of an async function, for example:

await Promise.resolve("cool")

Before it was added, the only way to use await was to wrap it in async function:

(async () => await Promise.resolve("cool"))()

However, top-level await only works within modules. This is a problem for REPLs, since they don’t make a module for every expression that you type. They basically use eval() on it, running in the global scope: if you type x = 1 or var x = 1, you expect x to be a global variable.

So, await wouldn’t work. But it does work! How? I initially thought they implemented some kind of a special eval-level await V8. Nope!

Turns out REPLs parse your expression and rewrite it into the async function! Both Node and Chrome use the acorn.js parser for that 🤯

If you type

await Promise.resolve('cool')

they turn it into

(async () => {return (await Promise.resolve('cool'));})()

What about global variables though? If you type var x = 1. and wrap it in a function, the var will be local to the function. But we want it to be global.

Here’s the trick — they also rewrite variable definitions:

var x = 1; await Promise.resolve('ok');

turns into:

(async () => {void (x = 1); return (await Promise.resolve('ok'));})()

They strip var/let/const from what now are function-scoped variables and just assign values to the global. Notice that your const will not actually be a const, but that’s fine, since REPLs allow redeclaring and reassigning top-level const and let anyway.

One funny thing: before running this whole parser stuff, Chrome dev tools check if rewriting is needed at all by looking for “async” in your code. So, if you type console.log("async work"), it will execute a tiny bit slower than console.log("meetings") 😜

If you want more details, read this processTopLevelAwait function in Node.

# Announcing SvelteKit 1.0

After two years in development, SvelteKit has finally reached 1.0. As of today, it’s the recommended way to build Svelte apps of all shapes and sizes.

SvelteKit is a framework for building web apps with Svelte, similar to Next/Nuxt. It replaces Sapper from the previous version of Svelte.