TypeError: Script methods can only be called on script instances

Since the most recent update all my dataviewjs references are getting the following error:

TypeError: Script methods can only be called on script instances.

Steps to reproduce

For example:

dv.view("dv-views/annotations/v1")

Which contains the following script:

var dvUtils = require(app.vault.adapter.basePath + "/📦 Resources/🏃‍♂️ Runbooks/🧰 Devops/dv-views/dvUtils.js");

let curr = dv.current();
let quote = curr.file.frontmatter.quote;
let sources = curr.file.frontmatter.sources;
let person = sources[0].person != "" ? sources[0].person : "Unknown";
let place = sources[0].place != "" ? sources[0].place : "Unknown";
let location = sources[0].location != "" ? " | " + sources[0].location : "";
let acknowledgement;

let quoteblock = `

>[!quote] ${quote}

><span class="source"><span class="person"> ${person} </span></br>

><span class="place">${place} ${location}</span></span>

`

dv.span(quoteblock)

Did you follow the troubleshooting guide? [Y/N]

I did but I had some trouble recreating the issue exactly. From this I did confirm that the issue is based on the first line:

var dvUtils = require(app.vault.adapter.basePath + "/📦 Resources/🏃‍♂️ Runbooks/🧰 Devops/dv-views/dvUtils.js");

I’m assuming this error refers to the require() but I don’t understand the language “Script methods can only be called on script instances.”

Expected result

Actual result

Environment

SYSTEM INFO:
Obsidian version: v1.4.2
Installer version: v1.3.4
Operating system: Darwin Kernel Version 22.5.0: Thu Jun 8 22:22:20 PDT 2023; root:xnu-8796.121.3~7/RELEASE_ARM64_T6000 22.5.0
Login status: logged in
Catalyst license: insider
Insider build toggle: on
Live preview: on
Legacy editor: off
Base theme: dark
Community theme: Things v2.1.6
Snippets enabled: 4
Restricted mode: off
Plugins installed: 33
Plugins enabled: 20
1: Hotkeys++ v0.2.7
2: Natural Language Dates v0.6.1
3: Templater v1.16.0
4: Periodic Notes v0.0.17
5: Obsidian Query Language v2.1.1
6: Dataview v0.5.56
7: Advanced Mobile Toolbar v1.8.0
8: Advanced Tables v0.19.1
9: Folder Note v0.7.3
10: PlantUML v1.6.6
11: QuickAdd v1.2.1
12: Tag Wrangler v0.5.11
13: Banners v1.3.3
14: LanguageTool Integration v0.3.4
15: Calendar v1.5.10
16: Bible Reference v1.7.3
17: Scales and Chords v1.0.1
18: Excalidraw v1.9.15
19: Importer v1.1.0
20: Tasks v4.5.0


Additional information

I use this require() call on all my scripts to have common functions available to me so any help in understanding the issue will help. Thanks!

Moved to help

1 Like

After some searching I think it might be related to this Electron bug: [Bug]: proxyquire can't load modules after window.open method is called · Issue #37404 · electron/electron · GitHub

I’ve decided to inline my shared JS code so I can do without require.

Unfortunately that works. It resolves the error message but really limits my scripting to have to repeat utility code throughout the various scripts. From what you shared this sounds like an issue that Electon has to resolve and not the Obsidian team, correct?

As far as I can tell: yes.

Hi,
Any update on this? Getting pretty much the same error

I dug into a workaround for this as it was killing my attempts to share scripts.

I looked into how dv.view() works (see inline-api.ts) and managed to get a simple workaround going - note this deliberately doesn’t pass parameters to the script, you could add that and more if you were keen.

I have a simple util.js file:

function foo(bar) {
    return `foo applied to ${bar}`;
}

return {foo: foo}

Then in my other javascript files I add a prefix:

const utilFile = '/Meta/scripts/utils.js';
let viewFile = app.metadataCache.getFirstLinkpathDest(utilFile, "");
if (!viewFile) {
    dv.paragraph(`ERROR: Could not find util file ${utilFile}`);
    return;
}
let contents = await app.vault.read(viewFile);
let func = new Function("dv", contents);
let utils = func(dv);

(you could inline a few variables to make it terser!)

This lets me call e.g. utils.foo("baz") to access that shared function, and dv is exposed as a variable as well. Note Function is pretty much the same as eval - breaks all security promises, don’t call anyone’s code but your own this way!

I hope others find this useful - it’d be nice if dataview exposed some sort of “require” functionality itself!

I should probably add a caveat - this is very dependant on Dataview internals so could break if they rename things!

Maybe there is some error in your script, I’ve an example which works for me.

/** System: Debian & Wayland & Plasma */

/** The Dataview Codeblock

```dataviewjs
    
    const viewFile = "hellskitchen/TagList/AnyView";
    await dv.view(viewFile, ["🔴", "🟡", "🟢"]);
    // ["🔴", "🟡", "🟢"] = any type, optional
```

*/

/** The View-File → AnyView.js */

const dummy = app.vault.adapter.basePath + "/hellskitchen/TagList/THEAnswer.js";

const answer = require(dummy);

function myHeader(param) {

    return dv.header(4, "The answer is " + param.foo);

};


function mylist(param) {

    return dv.list(param.reverse());

};

myHeader(answer);
mylist(input); 
// input = ["🔴", "🟡", "🟢"]
// input is a pre-defined name, don't change it ❗

/** THEAnswer.js

const bar = 42;    // if you want to import this somewhere, ...

exports.foo = bar; // ... you have to export it.

*/

Thanks! And that feels too brittle for me to rely on.

Thanks @Amolip, it seems to be somewhat working again.

I created a test vault (see below) for this.
Only dataview is installed and I have three uses of it:

  1. straight up inline dataviewjs usage
  2. using dv.view on a view file (and dir)
  3. using dv.view on a view file that uses a util.js

This all seems to work correctly again, which is nice!

But: if you update the console.log in util.js you’ll discover that some aggressive caching is happening in the 3rd usage. Doing the “Dataview: Force Refresh All Views and Blocks” doesn’t help. The only consistent way I’ve found to clear the cache for util.js is to close and reopen the whole vault.

So basically: the developer experience sucks, but I guess you can just develop your util.js content in a view.jsand then when done move it to a separate file and close and reopen the vault.

Bug kinda fixed?

dataviewjs_import_test.zip (468.8 KB)

Would it be an option to use another plugin like Templater or CustomJS to inject your utility code somewhere “semipermanently”?

Templater offers to run a startup template, which could do this process, and CustomJS is made for just this kind of stuff, if I understand you guys correctly after skimming this thread.

I think adding a plugin would complicate things.

The nice thing about just having a JavaScript file in your vault (just like your own myname.css snippets) is that it’s simple. And it should and does work, mostly :slight_smile:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.