observablehq / runtime

The reactive dataflow runtime that powers Observable Framework and Observable notebooks
https://observablehq.com/@observablehq/how-observable-runs
ISC License
1.01k stars 71 forks source link

Re-export d3-require #247

Closed GordonSmith closed 3 years ago

GordonSmith commented 4 years ago

When writing additional libraries for the runtime which also use d3-require to lazy load dependencies (in UMD mode), the different instances tend to interfere with each other.

If the runtime (and stdlib?) re-exported d3-require then my additional library could use that version and avail of the shared cache + global define.

GordonSmith commented 4 years ago

Actually it might be better if we could supply a "primed" require into the runtime / library (so that we could provide a custom resolver etc.)?

mbostock commented 4 years ago

You can do that by passing a resolve function the Library constructor or by changing the require passed to the Runtime constructor.

GordonSmith commented 4 years ago

I can see the Library resolve option: https://github.com/observablehq/stdlib/blob/master/src/library.js#L18-L19

But I don't see anyway to pass a require into the runtime: https://github.com/observablehq/runtime/blob/master/src/runtime.js#L14-L30

Or am I missing something?

asg017 commented 4 years ago

@GordonSmith from the docs:

Or to define a new builtin, or override an existing one: const runtime = new Runtime(Object.assign(new Library, {color: "red"}));

So if you have your own myRequire function, you could do something like so:

const myRequire = function(){/* whatever your require is */}
const runtime = new Runtime(Object.assign(new Library, {require: myRequire}));

This would override the default require builtin from the default Observable stdlib with your own myRequire implementation.

Then, with runtime, you can define modules with runtime.module, and any reference to require would use your myRequire implementation.

Keep in mind, your myRequire function may need to be wrapped in a function (#195) to work properly. You can see this being used in the stdlib source, all the builtin cells that are functions (require, html, resolve, etc.) are wrapped in constant(). So your may need to define your myRequire like so:

function myRequire() {
  return function() {
    // your implementation
  }
}

const runtime = new Runtime(Object.assign(new Library, {require: myRequire}));
mbostock commented 3 years ago

See the custom-library and standalone examples for how to override the standard library and provide your own require function. Alternatively, if you want to extract the require used by the runtime, you can say:

const library = new Library();
const require = library.require();
const runtime = new Runtime(library);