BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News REPLicant, a Super Simple Svelte REPL - Peter Allen at Svelte Summit 2020

REPLicant, a Super Simple Svelte REPL - Peter Allen at Svelte Summit 2020

This item in japanese

Bookmarks

Peter Allen recently gave a talk at Svelte Summit 2020 in which he explained the benefits of REPL (Read-Print-Eval-Loop) playgrounds. While the Svelte REPL is complex due to the handling of many edge cases, the principles underlying code playground implementations are simple. Allen progressively led the viewer into the implementation of the simplest possible version of the Svelte REPL.

Allen started by emphasizing the importance of online playgrounds to put a piece of technology in the hand of its target users. This may be especially valuable for innovative technologies to progress from the awareness stage to the evaluation stage of the marketing funnel. Allen credited the MDsveX playground for the sustained interest in MDsveX:

About 18 months ago, I published [MDsveX (MDX for Svelte)], a library [that allows using Svelte component in Markdown documents]. Honestly, nobody was interested […] Then one day, a friend was talking to me about how they wished they could write some combination of Markdown and Svelte.
It sounded like they needed MDsveX but they had no idea what it was. The README wasn’t helpful and neither was my explanation. […] I decided to spend a few evenings putting together an example site and an online playground so they could try it out for themselves. I posted a link on Svelte discord, it got shared around on Twitter and all of a sudden there was interest.

Allen mentioned having enjoyed using online interactive playgrounds to try out a few programming languages. TryRuby, a browser-based tutorial for the Ruby programming language, Rust, TypeScript, and Go have playgrounds too. The Svelte documentation site itself makes heavy use of the Svelte REPL.

Allen then explained the rationale behind the talk:

The Svelte REPL has been around for quite a while. Due to its complexity, it isn’t particularly well-understood but most of that complexity comes from handling edge cases or in additional features. At its core, the Svelte REPL is relatively simple. There are only a few concepts you need to know and that’s what we’re going to look at today. We’re going to build the simplest possible version of the Svelte REPL and see how it works under the hood.

A sample picture of the simplified REPL is as follows:

Simplified Svelte REPL screenshot

A user writes an <App> component, whose code is in an App.svelte entry file. That component may additionally import other components whose source code will be in neighboring tabs. The user may also add Svelte components by creating a new tab (+ button).

The playground must then handle an array of components whose source file is displayed in the tab area, and source code in a text area. The state of the simplified REPL thus consists of the array of components, the source code (i.e. the content of the <textarea>) for each component, and the currently selected component. The markup that is rendered on the right side of the screen is derived from the state of the REPL.

The App component markup breaks down as follows:

<main>
  <Input ... />
  <Output ... />
</main>

The Input component displays the tabs and text areas. The Output component displays the compiled and bundled App component.

The text area holding the source code for components will be bound to the local state of the <App> component using Svelte’s two-way data binding mechanism. Allen skipped in the talk the implementation of the tab area and the + button. A screenshot of the implementation Input component is as follows:

Simplified Svelte REPL - Input component screenshot

Allen then moved the focus on the Output component that compiles and renders the App component after every modification by the user.

Allen then explained the backpressure problem created by a compilation process (consumer) that is much slower than the user key inputs (producer). This means that having both user inputs and compilation-as-you-type on the same thread may result in the blocking of the main thread and a poor user experience.

To solve this, Allen delegates the compilation to a worker thread. The worker and the main thread (UI) communicate via messages. Allen uses Svelte’s reactivity to trigger a message to the worker that contains the components’ source code when the components update.

This done, Allen moved on to the next issue: compilation. The compilation of the array of source codes involves transforming the Svelte code into JavaScript and bundling the resulting files. Allen used the Rollup bundler’s JavaScript API and explained how to create a Rollup plugin.

A Rollup plugin is a simple object with a series of methods that are run by the bundler at specific points of its processing. Allen used three such methods: resolveId that resolves import statements; load that loads source codes; andtransform that compiles a Svelte source code into JavaScript. An excerpt of the worker implementation is as follows:

// The entry file is fixed and set to App.svelte
const bundle = await rollup({input: './App.svelte'}, plugins: [{
  name: 'repl-plugin',
  
  // Importee is the file to import from
  // Importer is the source file containing the import statement 
  resolveId (importee:string, importer:string) {...},
  
  // `load` receives the file to load as parameter
  load(id: string){...},
  
  transform(code: string, id: string) {...}
}]);

const output: string = (await bundle.generate({format: 'esm'})).output[0].code 

// Sends the compiled bundle back to the main thread
self.postMessage(output)

The simplicity of writing Rollup plugins had been previously noted by Surma and Archibald in a talk (making things fast in the world of build tools) at JSConf Budapest 2019. Archibald credited 16 custom Rollup plugins for allowing them to implement numerous performance optimizations:

You might feel like, we’re, you know, kicking Webpack a lot here. You are right, we are. The honest truth is that the difference that we felt between working on a project with Webpack and working on a project with Rollup was really, really, night and day for us. Not only did we feel like we understood what was happening, we felt capable of changing what was happening if we needed to.

Now that the compilation is implemented, the resulting string must be executed and the App component rendered. The Output component will run the compiled bundle sent back by the worker to the main thread in an iframe. There again, the main thread and the iframe communicate via the postMessage API, and the appropriate bindings and event listening are performed. The main thread sends the compiled bundle string; the iframe converts it into the actual compiled component that is exported by the bundle (default export). The iframe does so by converting the string into an URL object that is dynamically imported and parsed by the JavaScript runtime.

final results

The reader is encouraged to review the full talk, which contains plenty of detailed technical explanations. The source code and additional information are available on a dedicated GitHub project.

Svelte Summit is a virtual conference about Svelte. The 2020 edition took place online in October. The full list of talks will be made available on the Youtube channel of the Svelte Society.

Rate this Article

Adoption
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT