# Runtime and dependencies

**URL:** <https://talk.observablehq.com/t/runtime-and-dependencies/1953>\
**Category:** Help\
**Created:** [May 6, 2019, 10:12am UTC](https://talk.observablehq.com/t/runtime-and-dependencies/1953 "2019-05-06T10:12:07Z")\
**Posts on this page:** 1\
**Showing post:** 6

<div class="post-metadata">

**Author:** ![bgchen](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/bgchen/32/784_2.png) [@bgchen](https://talk.observablehq.com/u/bgchen)\
**Post date:** [May 6, 2019, 3:46pm UTC](https://talk.observablehq.com/t/runtime-and-dependencies/1953/6 "2019-05-06T15:46:33Z")

</div>

So far as I can tell, the issue is that the backend service that generates the module files at [api.observablehq.com/d/notebook.js](http://api.observablehq.com/d/notebook.js) can create duplicate variables inside the module arrays when variables are imported multiple times. Here’s a function which deduplicates variables in general imported notebook modules (it automates what you did manually in your fix notebook):

```auto
function dedup({id, modules}) {
  return {id, modules:modules.map(({id, variables}) => {
    const set = new Set();
    const newVariables = [];
    for (const v of variables) {
      if(!set.has(v.name)) {
        newVariables.push(v);
        set.add(v.name);
      }
    }
    return {id, variables:newVariables};
  })};
}

```

(Just use e.g. `dedup(notebook2)` in place of `notebook2`).

Note that these modules served by the API are written for the V1 runtime, which may become unsupported at some point. A more future-proof solution is to switch to using the V3 runtime like this:

```auto
notebook2v3 = (await import("https://api.observablehq.com/d/8e5e6d7c80d7e3dd.js?v=3")).default

```

```auto
new Promise((resolve, reject) => {
  (new Runtime()).module(notebook2v3, name => {
    if (name === "str2") {
      return { fulfilled: resolve, rejected: reject };
    }
  });
})

```

This also avoids the duplicate variable issue.

Now, if you want to play around with a really convoluted solution that stays in the V1 runtime world, you can try this:

```auto
import {fromV1, toV1, utoa} from '@bryangingechen/fromv1'

```

```auto
mm = {
  const fV1 = fromV1(await import('https://api.observablehq.com/d/8e5e6d7c80d7e3dd.js'));
  const nbObj = await toV1(({id:'xx', version:'0', nodes:fV1}));
  const mm = await import(`data:text/javascript;base64,${utoa(nbObj)}`);
  return mm;
}

```

```auto
new Promise((resolve, reject) => {
  Runtime.load(mm.default, variable => {
    if (variable.name === "str2") {
      return { fulfilled: resolve, rejected: reject };
    }
  });
})

```

This uses the following two functions I wrote some time back:

- `fromV1` reverse-engineers a V1 module to generate cell definitions
- `toV1` creates a V1 module from cell definitions (and luckily, my [hacked-together implementation](https://observablehq.com/@bryangingechen/from-raw-notebook-source-to-observable-runtime-v1-modules#getCellsFromModule) does remove duplicates from imports)

See the [`fromv1` notebook](https://observablehq.com/@bryangingechen/fromv1) and [its parent](https://observablehq.com/@bryangingechen/from-raw-notebook-source-to-observable-runtime-v1-modules) for more behind the scenes details.

---

_[View the full topic](https://talk.observablehq.com/t/runtime-and-dependencies/1953)._
