-1

I am having a problem to import some of the content of a JavaScript module (ipfs). Here is the code (test.js), taken from OrbitDB Module with IPFS Instance that I am trying to run from the command line as a node app (node test.js):

import IPFS from 'ipfs'
import OrbitDB from 'orbit-db'

;(async function () {
  const ipfs = await IPFS.create()
  const orbitdb = await OrbitDB.createInstance(ipfs)

  // Create / Open a database
  const db = await orbitdb.log("hello")
  await db.load()

  // Listen for updates from peers
  db.events.on("replicated", address => {
    console.log(db.iterator({ limit: -1 }).collect())
  })

  // Add an entry
  const hash = await db.add("world")
  console.log(hash)

  // Query
  const result = db.iterator({ limit: -1 }).collect()
  console.log(JSON.stringify(result, null, 2))
})()

When I run this code from the command line with node, it throws the following error:

import IPFS from 'ipfs'
       ^^^^
SyntaxError: The requested module 'ipfs' does not provide an export named 'default'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:127:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:193:5)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:337:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)

Process finished with exit code 1

I tried to find out what is wrong here. So I ctrl-clicked on ipfs and it takes me to the following index.d.ts:

/**
 * @typedef {import('ipfs-core-types').IPFS} IPFS
 */
export const create: typeof import("ipfs-core/src/components").create;
export const crypto: typeof import("libp2p-crypto");
export const isIPFS: typeof import("is-ipfs");
export const CID: typeof import("multiformats").CID;
export const multiaddr: typeof import("multiaddr").Multiaddr;
export const PeerId: typeof import("peer-id");
export const globSource: typeof import("ipfs-utils/src/files/glob-source");
export const urlSource: typeof import("ipfs-utils/src/files/url-source");
export const path: typeof pathImport;
export type IPFS = import('ipfs-core-types').IPFS;
import { path as pathImport } from "./path.js";
//# sourceMappingURL=index.d.ts.map

It looks to me like IPFS is exported by a named export. So I tried to change my code to named import, like this:

import {IPFS} from 'ipfs'

This throws the following error:

import {IPFS} from 'ipfs'
        ^^^^
SyntaxError: The requested module 'ipfs' does not provide an export named 'IPFS'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:127:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:193:5)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:337:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)

Process finished with exit code 1

So how can I solve this problem?

Here is the package.json that I have together with test.js:

{
  "name": "ipfs-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",  
  "type": "module"
}

I should mention that I wrote the code in Intellij, and it did not show a compilation error, which it usually does when it cannot locate imports. So that's also weird.

rapt
  • 11,810
  • 35
  • 103
  • 145
  • As a debugging step, you could always `import * as name from "module-name";` then see what properties `name` has to determine what is actually exported – Jaromanda X May 17 '23 at 23:07
  • I don't see the property I need (IPFS) exported. But maybe it does not appear there because it was exported as a type. I am assuming that I am not supposed to change the module that I want to import. – rapt May 17 '23 at 23:26
  • I don't even know what *I am assuming that I am not supposed to change the module that I want to import* means. import what you need I guess – Jaromanda X May 17 '23 at 23:28
  • It means that I do not want to change the imported module. As I said in my question, I am getting an error when I try to import what I need (`IPFS`). – rapt May 17 '23 at 23:38
  • but that's not exported according to your findings. Sorry, I'm blissfully unaware of how typescript messes with imports/exports, I just offered you a way to determine what is actually being exported. – Jaromanda X May 17 '23 at 23:42
  • Thanks for that, but I'm just letting other contributers know that it did not solve my problem. I assume that `export type IPFS = import('ipfs-core-types').IPFS;` does some kind of exporting. Otherwise, why would it be there? However, I don't understand why my import syntax did not work. – rapt May 17 '23 at 23:50
  • I'd start by reading the docs ~ https://github.com/ipfs/js-ipfs#install-as-an-application-developer. The `ipfs` package is for CLI usage. For application development, you want `ipfs-core` – Phil May 18 '23 at 01:42
  • @Phil I really wanted someone to help me better understand the JavaScript here and the general principle why my code failed, rather than just find some other code that does work (but does something else) and forget about it. That being said, you linked to a different project that may export a different API. I intend to use my IPFS import together with OrbitDB like this (Module with IPFS Instance): https://github.com/orbitdb/orbit-db#module-with-ipfs-instance. From that page it seems like this code was supposed work in a browser or from the command line with node. – rapt May 18 '23 at 06:32
  • The documentation I linked to is the same project as `ipfs`. The `ipfs` package is for CLI usage and `ipfs-core` is for application development. It's probably the case that the `orbit-db` docs you linked to are simply out-of-date. There's certainly enough bugs in their issues list to indicate they have **many** problems. – Phil May 18 '23 at 06:48
  • This one looks very relevant ~ https://github.com/orbitdb/orbit-db/issues/1058 – Phil May 18 '23 at 06:58
  • "I don't see the property I need (IPFS) exported" - the whole object is that "property"! – CherryDT May 18 '23 at 11:37
  • @Phil Good job! OrbitDB does have many open issues. But I could not find any other decentralized database that is being developed by more than one developer (there are quite a few single-developer abandoned projects). – rapt May 18 '23 at 20:56

1 Answers1

0

There is no default export (export default somethingSomething) so using import IPFS from 'ipfs' won't work.

You are half-right that a named export IPFS is there, however you looked at a TypeScript definition file, and the export named IPFS is just a type in TypeScript and not anything JavaScript even sees.

Instead, you can see that the create method you used in IPFS.create is a named export, so import { create } from 'ipfs' would work, but in fact you can keep your code that uses IPFS.create and simply change import IPFS from 'ipfs' to import * as IPFS from 'ipfs'!

The import * as something from 'something' syntax will give you an object with all named exports inside.

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • Thanks for the explanation. You have also clarified another point: I was really wondering if `index.d.ts`, since it's a typescript file (which applies when using the module in a typescript project), has any effect on the javascript code. From looking at the javascript code, it seems to me that from javascript point of view, IPFS is not exported (or defined) in the current version of the module. Is this correct? And if I used this module in a typescript project, how would I import the `type IPFS`? What is the typescript syntax for importing a named exported type? – rapt May 18 '23 at 20:39
  • Correct. `import type { IPFS } from 'ipfs'` would be the TS syntax for importing the type definition. – CherryDT May 19 '23 at 18:30
  • Thank you for the explanation! It helped me solve the problem. – rapt Jun 27 '23 at 20:49