🏠 back to Observable

Import/require works then doesn't

New observable user here, so I’m sure its my issue, but I’m having a strange problem where I either import or require (via bundle.run) a module, which works for a while, then stops. Here is one example: observablehq.com/@dhowe/rita-test . I’ve read that bundle.run is not reliable, but it also seems to happens with import (from jsdelivr or unpkg) - both die after awhile (seemingly after I publish).

It’s possible that you changed your location and/or IP, and ended up loading from a different server where the package hadn’t been compiled yet or had errored out during compilation.

For those reading along, here is the correct notebook URL:


You wrote:

import {RiTa} from "https://unpkg.com/rita@2.0.26/dist/rita-web.js"

Unfortunately static imports in notebooks don’t work for arbitrary modules, only for other Observable notebooks. You can read more about notebook imports here:

If you want to import a module you’ll have to do it dynamically:

foo = (await import('foo')).default

However, you can load RiTa directly via require:

RiTa = require('rita@2.0.26').catch(e => window.RiTa)

Finding the proper method to load a library can be tricky. In the future, I’d recommend to check available (detectable) methods with this notebook:

3 Likes

Yes, I checked that page first, and started by using the ‘bundle.run’ method, which also worked for a while then also stopped. So I’m a bit confused about whats going on here as it has happened with multiple methods, including those suggested on the module debugger page.

I guess the larger question is how to get the library (rita - npm) packaged so that it works the correct default way in observable. It uses webpack and has external dependencies – is there an ohq-compatible lib with a similar setup I can use as a template?

Edit: I was already done writing all this when I finally realized that you’re the author of RiTa. So please keep that in mind when reading the response below. :slight_smile:

The Require Debugger notebook attempts to guess the available methods based on various heuristics, like the info given in a package’s package.json, testing inclusion methods directly, etc. There is sadly no one-size-fits-all when it comes to modules, and especially modules that have been written primarily for Node.

bundle.run is a service that bundles and transpiles CommonJS modules into UMD modules. This process is hit-or-miss, and can either time out or error out. bundle.run will cache the result even if the bundling was unsuccessful. However, you can force a new bundling attempt by attaching a cache-breaking query to the final URL, e.g. “?foo”.

The require function that is available in Observable is actually d3-require, which only supports AMD style modules.

Back to RiTa: The default CDN used by d3-require is jsdeliver.com. We can browse the rita package files through its web UI:

There we can see that the dist folder contains a file rita-umd.js, and UMD should work with d3-require. Sadly, the UMD wrapper in that file accesses a global identifier (where this would have been expected). Because global is not defined, it causes the inclusion of this file to fail (in fact, any error will).

So in order to include rita the “proper” way, we’d have to write:

RiTa = (window.global = window), require('rita@2.0.29/dist/rita-umd')

Note that there is no “clean” way to include the package without polluting any scope, as its code will also modify String.prototype.

Yes, I added that umd version yesterday as a test (actually the node version on jsdelivr, rita.js, is also umd)… But would be great if someone could point me to a library (ideally with dependencies and using webpack) that generates correct umd for use in observable. Then I can just republish it. Thanks !

Also, can you explain what you mean about String.prototype (and where you see that?). There shouldn’t be any prototype modification in rita…

Ok, so I (think I) have solved the require problem. For anyone who might stumble upon this using webpack/umd, you need to include globalObject: 'this' in module.exports.output in your webpack config.

Now (as of v2.0.31) rita can be required in the usual way:

RiTa = require('rita@2')

But, the original problem, where the notebook works for some time, then, after a publish, shows the RiTa object as invalid still remains, which one can see in the linked notebook

@shadoof suggested that this was perhaps due to some strangeness involving the yield/delay cell, which looks like this:

 while (true) {
   yield Promises.delay(1000, RiTa.evaluate(query));
 }

Perhaps someone more familiar with observable can provide some insight ?

So finally, with the help of @jashkenas, I traced the issue back to a bug introduced in the library itself when the webpack configs were updated for compatibility with observable. Thanks for everyone’s help above!

1 Like