Skip to content

Commit 9d4ca97

Browse files
mikolajruraclaude
andcommitted
fix: load RDKit locally from plugin folder, no internet needed
Replace CDN script injection with Node.js require() via eval to prevent esbuild bundling. RDKit_minimal.js and RDKit_minimal.wasm are copied next to main.js during build and loaded at runtime using __dirname. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent be01854 commit 9d4ca97

2 files changed

Lines changed: 32 additions & 29 deletions

File tree

esbuild.config.mjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import esbuild from "esbuild";
22
import process from "process";
33
import builtins from "builtin-modules";
44
import { copyFileSync } from "fs";
5+
import { resolve, dirname } from "path";
6+
import { fileURLToPath } from "url";
7+
8+
const __dirname = dirname(fileURLToPath(import.meta.url));
59

610
const banner = `/*
711
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
@@ -11,6 +15,8 @@ if you want to view the source, please visit the github repository of this plugi
1115

1216
const prod = process.argv[2] === "production";
1317

18+
const rdkitSrc = resolve(__dirname, "node_modules/@rdkit/rdkit/dist");
19+
1420
const context = await esbuild.context({
1521
banner: { js: banner },
1622
entryPoints: ["src/main.ts"],
@@ -37,11 +43,22 @@ const context = await esbuild.context({
3743
sourcemap: prod ? false : "inline",
3844
treeShaking: true,
3945
outfile: "main.js",
46+
define: {
47+
// Make __dirname available inside the bundle (plugin folder at runtime)
48+
"__dirname": "__dirname",
49+
},
4050
});
4151

4252
if (prod) {
4353
await context.rebuild();
54+
// Copy RDKit runtime files next to main.js
55+
copyFileSync(`${rdkitSrc}/RDKit_minimal.js`, "RDKit_minimal.js");
56+
copyFileSync(`${rdkitSrc}/RDKit_minimal.wasm`, "RDKit_minimal.wasm");
57+
console.log("Copied RDKit_minimal.js and RDKit_minimal.wasm");
4458
process.exit(0);
4559
} else {
60+
// Dev mode: also copy so hot reload works
61+
copyFileSync(`${rdkitSrc}/RDKit_minimal.js`, "RDKit_minimal.js");
62+
copyFileSync(`${rdkitSrc}/RDKit_minimal.wasm`, "RDKit_minimal.wasm");
4663
await context.watch();
4764
}

src/rdkit-loader.ts

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
1-
// Singleton RDKit WASM module loader.
2-
// RDKit is heavy (~10MB WASM), load once and reuse.
3-
4-
declare global {
5-
interface Window {
6-
initRDKitModule: () => Promise<RDKitModule>;
7-
RDKit: RDKitModule | null;
8-
}
9-
}
1+
// Load RDKit WASM from the local plugin directory (no internet needed).
2+
// RDKit_minimal.js and RDKit_minimal.wasm must sit next to main.js.
103

114
export interface RDKitMol {
125
get_svg(): string;
@@ -18,33 +11,26 @@ export interface RDKitMol {
1811

1912
export interface RDKitModule {
2013
get_mol(smiles: string): RDKitMol;
21-
get_mol_from_smiles(smiles: string): RDKitMol;
2214
version(): string;
2315
}
2416

2517
let rdkitPromise: Promise<RDKitModule> | null = null;
2618

27-
export async function loadRDKit(): Promise<RDKitModule> {
19+
export function loadRDKit(): Promise<RDKitModule> {
2820
if (rdkitPromise) return rdkitPromise;
2921

30-
rdkitPromise = new Promise((resolve, reject) => {
31-
// RDKit bundles a self-contained WASM init function.
32-
// We load it from the CDN since bundling WASM into Obsidian plugins is complex.
33-
const script = document.createElement("script");
34-
script.src =
35-
"https://unpkg.com/@rdkit/rdkit/Code/MinimalLib/dist/RDKit_minimal.js";
36-
script.onload = async () => {
37-
try {
38-
const mod = await (window as any).initRDKitModule();
39-
(window as any).RDKit = mod;
40-
resolve(mod);
41-
} catch (e) {
42-
reject(e);
43-
}
44-
};
45-
script.onerror = () => reject(new Error("Failed to load RDKit script"));
46-
document.head.appendChild(script);
47-
});
22+
rdkitPromise = (async () => {
23+
// Use Node.js require (available in Electron/Obsidian).
24+
// eval('require') prevents esbuild from trying to bundle the dynamic path.
25+
// __dirname points to the plugin folder where RDKit_minimal.js lives.
26+
const nodeRequire = eval("require") as NodeRequire;
27+
const path = nodeRequire("path") as typeof import("path");
28+
const rdkitJsPath = path.join(__dirname, "RDKit_minimal.js");
29+
const initRDKitModule = nodeRequire(rdkitJsPath) as (
30+
opts?: object
31+
) => Promise<RDKitModule>;
32+
return await initRDKitModule();
33+
})();
4834

4935
return rdkitPromise;
5036
}

0 commit comments

Comments
 (0)