Handling Dependencies for an es6 Module

This should be obvious, but I haven’t seen an example yet in the notebooks: How do I handle dependencies in my notebooks?

Simple example: I have a github repo which uses Three. Do I simply require() it, then import() my es6 module after that? The order dependency seems to go against reactivity.

And to make things worse, my repo is “hosted” in a github page as a CDN rather than in npm for unpkg use. I’ll make a npm pkg soon but if there is a way to have the awkward Three unpkg require() resolved as a dependency for my CDN es6 module?

I think the answer is like
https://beta.observablehq.com/@tmcw/requiring-modules-troubleshooting
shows with Three and OrbitControl: do everything in a block that returns my module after it’s gotten Three and Orbit playing nice together.

Any example of importing modules with dependencies much appreciated.

1 Like

Cells in Observable are evaluated in topological order, not top-down order, so if you require Three.js, any cell that references it (THREE) will automatically wait until it has been loaded. Here’s a quick hello-world:

https://beta.observablehq.com/@mbostock/hello-three-js

If a library is defined as an AMD or an ES module, then library dependencies are loaded automatically. For example, if you require d3-scale:

d3 = require("d3-scale")

This will also cause d3-array, d3-collection, d3-format, d3-interpolate, d3-time and d3-time-format to be loaded. If you are a library author, I recommend using Rollup to bundle your library. It lets you declare your dependencies in the package.json and supports AMD, UMD, IIFE and ES module bundle formats.

While Three is defined in the UMD format, Three OrbitControls are not, so you have to jump through another hoop to load them. The OrbitControls module is CommonJS: it depends on a global module.exports, which it assigns to a function. You need to call this function in order to create the OrbitControls object. Here’s what I recommend:

THREE = {
  const THREE = await require("three@0.82.1/build/three.min.js");
  if (!THREE.OrbitControls) { // If not previously loaded.
    const module = window.module = {exports: undefined};
    THREE.OrbitControls = await require("three-orbit-controls@82.1.0/index.js").catch(() => module.exports(THREE));
  }
  return THREE;
}

This code is extra tricky because require is cached internally, so we have to be careful to not try to load OrbitControls more than once. Here’s a working demonstration:

https://beta.observablehq.com/@mbostock/hello-three-js-orbit-controls

1 Like