How to load local library

maze = require('')

gives error:

maze = vt: invalid module

The module is build with Typescript using config:

  "compilerOptions": {
    "target": "ES2017",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
   "outDir": "./dist",                        /* Redirect output structure to the directory. */
    "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
    "strict": true,                           /* Enable all strict type-checking options. */

Loading it with:

text = (await fetch("")).text()
mod_maze = {
  var exports = {};
  return exports;

I’ve also tried AMD, UMD combinations with ES5, ES2015, etc. with the same result.

Hi @alfa07.

Observable’s require uses AMD, so you’ll need to generate an AMD-compatible bundle rather than targeting CommonJS. (UMD is recommended.)

If your AMD bundle doesn’t work with require, I’d be happy to take a look, but you’d need to share the generated code, say by attaching the bundle as a file attachment to a notebook and then sharing that notebook. If you don’t want to share this code publicly you are welcome to email us at support.

Also, I think some browsers won’t let you access HTTP servers from Observable (which uses HTTPS exclusively). Though it appears your browser allows it for localhost. You can avoid this, again, by attaching the generated bundle to your notebook as a file, e.g.:

maze = require(await FileAttachment("maze.js").url())

@mbostock thank you for the reply!
Here is a repro as you’ve recommended:
Require Test

My goal is to develop a library in a TypeScript and use it in an Observable notebook. I thought that requiring it from a local server should work, but it turned out not to be so simple.

The reason this AMD bundle isn’t working is because it’s generating multiple named AMD modules, whereas what you want is to generate a single unnamed module. Unfortunately, I’m not familiar with the TypeScript compiler, so I don’t know what options would be needed to generate an anonymous AMD module (which is the more common format).

You could maybe also try using the ES2015 output format, and then using a dynamic import instead of require.

maze = import(await FileAttachment("maze_es.js").url())

I know this is somewhat of an old question, but what worked for me was setting

“compilerOptions”: {
“target”: “ES6”,
“module”: “ES6”,

and then using module = import(“url”) in the notebook.

minor issues

  • needing to reload page rather than rerun cell to reload module
  • couldn’t get import {something} from “url” format to work. (or import “url” returning the default export)

Would be be possible to load the map file also? Perhaps they can be packaged together?

At least for me, the idea of having typescript in an external editor (for “heavier” code) and then the notebook to work with it seems a great combo.

1 Like

Thank you @carl, yes, the import is not working and it is a deal breaker. After spending too much time on it I just gave up. Observable is awesome for snippets but when your project grows (and now I have a second project in thousands of lines) the lack of a proper editor and types shows.

Ok, I’ve managed make it work. The key is to use ES6 modules as @carl suggested and to use rollup to package into a single file.

Here is the example together with server part.