How to load local library

maze = require('http://127.0.0.1:31338/maze.js')

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("http://127.0.0.1:31338/maze.js")).text()
mod_maze = {
  var exports = {};
  eval(text.toString());
  return exports;
}

works.
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())
2 Likes

@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())
2 Likes

Hi.
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.

2 Likes