Import a notebook dynamically for embedding

Does anyone have experience importing a notebook dynamically and embedding it? I’m trying to write a React component that will use the runtime to embed a notebook. I can’t use the ES6 syntax suggested by the runtime docs

import define from "https://api.observablehq.com/@observablehq/hello-world.js?v=3";

because I want it to be able to import a notebook specified by the user. Here’s what I’m currently attempting:

import { Runtime, Inspector } from '@observablehq/runtime'
import { useEffect, useState } from 'react'

export default function NotebookRenderer({ config }) {
    const [notebook, setNotebook] = useState(null)

    useEffect(() => {
        const notebookUrl = `https://api.observablehq.com/${config.notebook}.js?v=3`
        import(notebookUrl).then(notebook => setNotebook(notebook))
    })

    return (
        <>
            {/* code to render notebook will go here */}
        </>
    )
}

But I get

Uncaught (in promise) Error: Cannot find module 'https://api.observablehq.com/NOTEBOOKURL.js?v=3'

in the console. I’m using webpack via create-react-app if that is influencing this behavior.

Ah maybe this actually is a webpack issue after all: reactjs - Using `dynamic import` to fetch script from another host? - Stack Overflow

This was indeed a webpack issue, but in case anyone else runs across it, adding this webpack magic comment turned out to be the solution:

import(/* webpackIgnore: true */notebookUrl).then(notebook => setNotebook(notebook))

See for more detail:

2 Likes

Nice Harris! We recently started putting together an example of dynamic imports for embedding in our repo of runtime examples. It has a couple outstanding bugs, as you can read about in the PR comments; I gotta get back to it and fix those sometime. The example uses Rollup but I should add a note about Webpack. Great find, thanks for working through it.

1 Like

Oooh, thanks for those added details, @tophtucker. That’s excellent! And yes, those examples and comments are elucidating (and touch on some things I’ve overlooked in my prototyping :sweat_smile:)

While we’re here @tophtucker do you have any examples or advice for rendering cells in two different React components? For example if I want one component to actually render some cells with the inspector but I want another component to show a list of cell names. Should I instantiate the module twice, once for each component? Or do some complicated ref forwarding?

Oh hm that’s a good question. My instinct is some complicated ref forwarding haha but I haven’t tried.

1 Like