The only thing that’s implicitly loaded in an Observable notebook is the Observable standard library.
In addition, when using require, any dependencies of the module you require are also loaded. For example, if you look at the d3-graphviz bundle, you’ll see that it depends on a few other modules (viz.js/viz, d3-selection, d3-dispatch, d3-transition, etc.):
https://unpkg.com/d3-graphviz@2.1.0/build/d3-graphviz.js
These modules are loaded because they are dependencies of d3-graphviz, but they are not exposed on the object resolved by require because they are considered internal dependencies to d3-graphviz.
If you want access to these dependent modules, you need to require them separately. Note, however, that this won’t cause the scripts to be downloaded twice—require is smart enough to detect that it has already loaded a module and return the existing copy.
For example, you might say:
d3 = require("d3-graphviz", "d3-selection", "d3-dispatch", …)
Viz = require("viz.js/viz")
(Note that I’m using the “splat” capabilities of Observable’s require that allows combining of multiple modules into a single shared namespace object. This is nice for D3 modules since they are designed for this pattern.)
There are two unfortunate limitations here:
First, you can’t mix and match D3’s default bundle (d3) with individual D3 modules (such as d3-selection). Since d3-graphviz (correctly) depends on the D3 modules, your notebook must also load the D3 modules separately. We could fix that in D3 by providing an AMD-only bundle that depends on the D3 modules (as we already do for CommonJS). But for now you have to list the D3 modules by hand.
Second, Observable’s require doesn’t currently handle dependency version resolution. Meaning, when you require a module, it will always require the latest version of any dependencies, regardless of what’s declared in the dependencies block of the module’s package.json. You can specify versions at the top level, such as require("d3-selection@1")
, but if you do this, it will no longer be considered the same module as the require("d3-selection")
dependency of d3-graphviz, so then you’ll have two copies of d3-selection.
These limitations can be avoided by using ES dynamic import instead of require, since unpkg dynamically rewrites static imports to resolve dependency versions. However, the D3 default bundle also isn’t optimized for ES imports at the moment—it’ll trigger about 500+ requests for unminified code, making it much slower than require.
Our hope is that in the long term these challenges will evaporate with widespread adoption of ES modules and support for ES import. But we’re still a ways from that, so it may be needed for us to ship some interim improvements to require.