This is a plugin for Obsidian
that fixes require()
calls and simplifies working with custom JavaScript
/TypeScript
modules.
This plugin heavily simplifies working with custom JavaScript
/TypeScript
modules. You can work with them using DevTools Console, CustomJS scripts, dataviewjs scripts, Modules scripts, QuickAdd scripts, Templater scripts, etc.
Certain built-in modules are available for import during plugin development but show Uncaught Error: Cannot find module
if you try to require()
them manually. This plugin fixes that problem, allowing the following require()
calls to work properly:
require('obsidian');
require('@codemirror/autocomplete');
require('@codemirror/collab');
require('@codemirror/commands');
require('@codemirror/language');
require('@codemirror/lint');
require('@codemirror/search');
require('@codemirror/state');
require('@codemirror/text');
require('@codemirror/view');
require('@lezer/common');
require('@lezer/lr');
require('@lezer/highlight');
Example usage:
const obsidian = require('obsidian');
new obsidian.Notice('My notice');
const { Notice } = require('obsidian');
new Notice('My notice');
Get the list of built-in module names fixed by the plugin:
app.plugins.getPlugin('fix-require-modules').builtInModuleNames;
There is a global variable app
that gives access to obsidian App
instance.
However, starting from Obsidian v1.3.5
this global variable is deprecated in the public API.
Starting from Obsidian v1.6.6
this global variable was completely removed from the public API.
Currently this global variable is still available, but it's better not rely on it, as it is not guaranteed to be maintained.
This plugin gives you a safer alternative:
require('obsidian/app');
Fixes Cannot find module
errors for relative paths:
require('./some/relative/path.js');
require('../some/other/relative/path.js');
Optionally provide the path to the current script/note if detection fails. Submit an issue if needed:
require('./some/relative/path.js', 'path/to/current/script.js');
require('./some/relative/path.js', 'path/to/current/note.md');
Adds support for root-relative paths:
require('/path/from/root.js');
The root /
directory is configurable via settings.
Adds support for vault-root-relative paths:
require('//path/from/vault/root.js');
Originally, require()
only supported CommonJS
(cjs
) modules and would throw require() of ES Module path/to/script.mjs not supported. Instead change the require of path/to/script.mjs to a dynamic import() which is available in all CommonJS modules
. This plugin adds support for ECMAScript modules:
require('path/to/script.mjs');
Now you can use any type of JavaScript modules:
require('path/to/script.js');
require('path/to/script.cjs');
require('path/to/script.mjs');
TypeScript
Modules
Adds support for TypeScript
modules:
require('path/to/script.ts');
require('path/to/script.cts');
require('path/to/script.mts');
You can require NPM modules installed into your configured scripts root folder.
require('npm-package-name');
See Tips how to avoid performance issues.
Modules are cached for performance, but the cache is invalidated if the script or its dependencies change. Use a query string to skip cache invalidation:
require('./someScript.js?someQuery');
If you need to clear the require
cache, you can click the corresponding button in the settings or invoke the Fix Require Modules: Clear Cache
command.
Manages source maps for compiled code, allowing seamless debugging in Obsidian
.
Use dynamicImport()
to extend the built-in import()
function with all the features of require()
and support for URLs:
await dynamicImport('obsidian');
await dynamicImport('./some/relative/path.js');
await dynamicImport('../some/other/relative/path.js');
await dynamicImport('./some/relative/path.js', 'path/to/current/script.js');
await dynamicImport('./some/relative/path.js', 'path/to/current/note.md');
await dynamicImport('/path/from/root.js');
await dynamicImport('//path/from/vault/root.js');
await dynamicImport('path/to/script.js');
await dynamicImport('path/to/script.cjs');
await dynamicImport('path/to/script.mjs');
await dynamicImport('path/to/script.ts');
await dynamicImport('path/to/script.cts');
await dynamicImport('path/to/script.mts');
await dynamicImport('obsidian?someQuery');
await dynamicImport('https://some-site.com/some-script.js');
await dynamicImport('file:///C:/path/to/vault/then/to/script.js');
await dynamicImport('app://obsidian-resource-path-prefix/C:/path/to/vault/then/to/script.js'); // See obsidian.Platform.resourcePathPrefix
Make any script invocable by defining a module that exports a function named invoke
(sync or async) that accepts app
argument
// cjs sync
exports.invoke = (app) => { console.log('cjs sync'); };
// cjs async
exports.invoke = async (app) => { console.log('cjs async'); await Promise.resolve(); };
// mjs sync
export function invoke(app) { console.log('mjs sync'); };
// mjs async
export async function invoke(app) { console.log('mjs async'); await Promise.resolve(); };
// cts sync
exports.invoke = (app: App): void => { console.log('cts sync'); };
// cts async
exports.invoke = async (app: App): Promise<void> => { console.log('cts async'); await Promise.resolve(); };
// mts sync
export function invoke(app: App): void { console.log('mts sync'); };
// mts async
export async function invoke(app: App): Promise<void> { console.log('mts async'); await Promise.resolve(); };
Configure a script directory so every script in it can be invoked using the Command Palette
. Use Fix Require Modules: Invoke Script: <<Choose>>
for more predictable lists:
Invoke any script when Obsidian
loads via a configuration setting.
You can add a cleanup()
function to the startup script, which will be called when the plugin is unloaded.
The function has the same signature as invoke()
function.
Assign hotkeys to frequently used scripts:
Create code buttons that execute JavaScript
/TypeScript
:
```code-button Click me!
// CommonJS (cjs) style
const { dependency1 } = require('./path/to/script1.js');
// ES Modules (esm) style
import { dependency2 } from './path/to/script2.js';
// Top-level await
await Promise.resolve(42);
// TypeScript syntax
function myTypeScriptFn(arg: string): void {}
```
If you plan to use scripts extensively, consider putting them in a dot directory
, such as .scripts
within your vault. Obsidian
doesn't track changes within dot directories
and won't re-index your node_modules
folder repeatedly.
Dynamic import()
Extending dynamic import()
expressions to support const obsidian = await import('obsidian')
is currently impossible due to Electron
limitations within Obsidian
. Although Obsidian
1.6.5+
uses Node.js v20.14.0
which includes Module.register()
, it depends on Node.js Worker threads
and fails with The V8 platform used by this instance of Node does not support creating Workers
. Use dynamicImport()
as a workaround.
Fix Require Modules
is available on the official Community Plugins repository.- Beta releases can be installed through BRAT.