Using custom scripts in Obsidian

Intro

Custom JavaScript can transform your Obsidian setup into a productivity powerhouse.

In this guide, we’ll explore how to leverage custom JavaScript functions in Obsidian using the Dataview and Templater plugins. This can enhance your vault’s functionality and enable code reuse, allowing you to automate and customize tasks efficiently based on your needs.

My journey into creating a smart journal

One of the main reasons I wrote this post was to bring more order into my daily and weekly note-taking workflow.

I keep a daily and weekly work journal. The daily journal helps me to keep track of what I’ve done and prepare for the next day. In my weekly journal, I set some weekly goals and have a higher level view on how I’ve spent my week. It also helps me to present my progress to my teammates in our weekly meetings and give a breakdown of planned vs unplanned work. Now I can walk into weekly meetings with confidence — no more or mumbling about what I did last week!

Writing these pages from scratch and manually copying records from daily notes to the weekly notes would be tedious enough to make me quit. I don’t like quitting!

So here is where Obsidian plugins Dataview and Templater come to the rescue.

I’ve created templates for both daily and weekly notes, each template having a dedicated structure and fields for me to fill. But how to aggregate the daily tasks into a weekly report? Dataview allows me to find all my daily notes for the relevant week. I’m using the DataviewJS, since it allows me greater flexibility than an SQL-like syntax. From the daily notes, I extract tasks completed that day, divided by “planned” and “unplanned” tags along with my achievements list.

Great! But that’s almost a screen long of Javascript code! Surely I can extract all the boilerplate code and reusable snippets out!

Well yes, and let me show you how!

Setting up your vault

Storing your code

Create a folder to store your Javascript files. I call mine Scripts and place in my vault root folder.

Place your JavaScript files inside the folder that you have created. Make sure that you properly define module.exports.

Attention: Custom scripts in Obsidian only support CommonJS modules. If you’re used to ES Modules, you may need to adjust your code accordingly.

A mock example of Javascript code with two functions and an export section:

function say_message(msg) {
  return `Message from my script: ${msg}`;
}

function cow_say(msg) {
  return `Cow says ${msg}`;
}

module.exports = { say_message, cow_say };

Notice the required module.exports to comply with Common.js syntax.

Configuring the Templater plugin

Under Settings > Community Plugins > Templater > Script files folder location Set the folder to Scripts.

When Templater detects user scripts, it displays loaded the scripts as bullets under the header: Detected ${num_of_scripts} User Script(s) With a list of scripts detected.

Configuring the Dataview plugin

Toggle Enable JavaScript Queries.

[!Note] Script Folder Configuration Unlike Templater, Dataview doesn’t allow setting up custom script folder in configuration.

Using Custom Scripts

Usage with Templater

An example of code block in an Obsidian page template:

<%*
  let title = tp.file.title
  if (title.startsWith("Untitled")) {
	title = await tp.system.prompt("Title");
	await tp.file.rename(title);
  }
  tp.user.my_script.say_message('Let templater use my custom scripts!')
%>

Notice the following line:

tp.user.my_script.say_message("Let templater use my custom scripts!");
  • tp.user - A header to indicate custom scripts
  • my_script - The filename of Javascript file, as stored in the scripts folder.
  • say_message - The function that you want to call.

Usage with Dataview

There are 3 ways loading the custom scripts in Dataview scripts:

Using scripts as they were loaded at the Obsidian startup

The most common use case.

// Get reference to the script
const myScript = require(dv.app.vault.adapter.basePath +
  "/Scripts/my_script.js");
// Use functions exported by the script
dv.paragraph(1, myScript.cow_say("Loading script at Obsidian startup!"));

Reloading the script every time

If you want to reload the referenced library every time without restarting Obsidian. This is very useful for debugging your code.

// Get reference to the script path
const src = dv.app.vault.adapter.basePath + "/Scripts/my_script.js";
// Delete from cache
delete global.require.cache[global.require.resolve(src)];
// Load new version
const myScript = require(src);
// Use functions exported by the script
dv.paragraph(1, myScript.cow_say("Reloading script at Obsidian!"));

Reloading the script asynchronously

This allows you loading your scripts only when needed.

// Execute under some conditions, like file tags.
if (dv.current().file.tags.includes("cows_talk")) {
  // Load script
  const myScript = await dv.require("/Scripts/my_script.js");
  // Use functions exported by the script
  dv.paragraph(
    1,
    myScript.cow_say("Reloading script at Obsidian asynchronously!")
  );
}

Summary and final thoughts

In this article I’ve shown how to organize your Javascript code to allow writing smart templates and data views while creating clear, readable and reusable code in Obsidian plugins.

Try implementing your first custom script today, and tag me on social media to share how it enhances your workflow!

Sources: