console.log('dupa'); // ympek's dev blog

printing my way through life.

Embedding Asciinema asciicast in your Docusaurus 2 docs

Published on

Tags: react docusaurus asciinema

Introduction

Asciinema is a brilliant tool for recording screencasts inside the terminal. What makes it better alternative for any generic screencasting tool is that it simply captures output like your keystrokes and what is printed on the terminal and the final product is tiny tiny plaintext file with timestamps instead of some video format. This is lightweight, efficient and enables extra cool features like different themes, sizes (presentation styles in general). Terrific stuff. See how it works - incredibly educational.

Another fun tool is Docusaurus 2 which many projects are using for documentation publishing. I use it too.

In this post we will learn how to embed asciinema cast on the page. You can read about the issues I've encountered below, or scroll down straight to the copypastable solution.

Problems along the way

Well, when you click Sharing & embedding and see Embedding the player section, you can see there is copypastable script tag, but React (which is the foundation of Docusaurus) won't let you do it like this :). Nothing will show up.

Well then you probably rush to google and type "asciinema docusaurus" or more generic "asciinema react" and find the library asciinema-player on npm registry. But how to use it with React? You find this snippet by @dunnkers on GitHub and happily adapt it to your use case.

It works! Yes! But wait... You try to build production build, and you will most likely see an error like:

# Docusaurus Node/SSR could not render static page with path

Of course I forgot the production build of Docusaurus is SSR-ed and one can't simply use libraries that assume they are always running in the browser. Newer versions of Docusaurus even inform you about this and hint that the solution is BrowserOnly. (Which might making this post look kinda silly). The version I was using when I've stumbled into this issue was not doing it.

Solution: wrap component in BrowserOnly

So the solution is actually simple, because Docusaurus provides us with a way to disable SSR for certain parts of the code that can't be rendered on the backend (e.g. are depending on browser-only APIs). It's called <BrowserOnly> component (see the docs).

Let's go step by step:

  1. Add asciinema-player to your project:

yarn add asciinema-player
  1. Create some glue code which will wrap asciinema-player, (which is regular JS library) into React component. I'm putting it into src/components folder, which already exists in base Docusaurus project template. I've called the component AsciinemaWidget:

project_root/src/components/AsciinemaWidget/index.js:

import BrowserOnly from '@docusaurus/BrowserOnly';
import React, { useEffect, useRef } from 'react';
import 'asciinema-player/dist/bundle/asciinema-player.css';

const AsciinemaWidget = ({ src, ...asciinemaOptions}) => {
  return (
    <BrowserOnly fallback={<div>Loading asciinema cast...</div>}>
      {() => {
        const AsciinemaPlayer = require('asciinema-player');
        const ref = useRef(null);

        useEffect(() => {
          AsciinemaPlayer.create(src, ref.current, asciinemaOptions);
        }, [src]);

        return <div ref={ref} />;
      }}
    </BrowserOnly>
  );
};

export default AsciinemaWidget;

Notice we are importing .css too - you're gonna need that!

Also notice I am not using TypeScript; if you need TypeScript you can take some code from @dunnker's snippet linked above

  1. Use it like this in your Docusaurus .md (MDX) pages:
import AsciinemaWidget from '../src/components/AsciinemaWidget';

<AsciinemaWidget src="https://asciinema.org/a/427282.cast" rows={30} idleTimeLimit={3} preload={true} />

You can use asciinema-player options documented here as props, as presented on the snippet. And for src you can put URL (absolute or relative) or path to .cast file.

To sum up: