fix: bundle chromadb and fix fetch invocation in Electron
- Bundle chromadb into main.js via esbuild instead of externalizing it.
Obsidian's renderer cannot resolve bare require('chromadb') against a
plugin-local node_modules. By bundling, the client library is inlined and
works out of the box with just manifest.json + main.js.
- Remove eager cache initialization from OllamaClient constructor to avoid
unhandled promise rejections when chromadb/ChromaDB is unavailable.
- Fix 'Failed to execute fetch on Window: Illegal invocation' by wrapping
the default fetch fallback in an arrow function:
this.fetchFn = fetchFn ?? ((url, init) => fetch(url, init));
This preserves the window binding when fetch is called later.
- Update install.sh and README to remove the obsolete node_modules/chromadb
copy step.
- Update ollama-client-cache tests to reflect that cache initialization is
no longer eager.
This commit is contained in:
@@ -68,10 +68,9 @@ cp manifest.json /path/to/vault/.obsidian/plugins/ollama-plugin/
|
|||||||
cp main.js /path/to/vault/.obsidian/plugins/ollama-plugin/
|
cp main.js /path/to/vault/.obsidian/plugins/ollama-plugin/
|
||||||
# Remove old dist/ from previous installs (no longer needed with bundling)
|
# Remove old dist/ from previous installs (no longer needed with bundling)
|
||||||
rm -rf /path/to/vault/.obsidian/plugins/ollama-plugin/dist
|
rm -rf /path/to/vault/.obsidian/plugins/ollama-plugin/dist
|
||||||
cp -r node_modules/chromadb /path/to/vault/.obsidian/plugins/ollama-plugin/node_modules/ # optional: only needed for semantic cache
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note:** The plugin is now bundled into a single `main.js` via esbuild. The `obsidian` npm package is a dev-only type stub — Obsidian provides its own API at runtime. The `chromadb` package is only needed if you enable the semantic cache feature.
|
> **Note:** The plugin is now bundled into a single `main.js` via esbuild. The `obsidian` npm package is a dev-only type stub — Obsidian provides its own API at runtime. The `chromadb` client library is also bundled into `main.js`, so no extra `node_modules` copy is needed for the semantic cache feature.
|
||||||
|
|
||||||
### After installation
|
### After installation
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
chroma:
|
||||||
|
image: chromadb/chroma:latest
|
||||||
|
ports:
|
||||||
|
- "8666:8000"
|
||||||
|
environment:
|
||||||
|
- CHROMA_SERVER_HOST=0.0.0.0
|
||||||
|
- CHROMA_SERVER_HTTP_PORT=8000
|
||||||
|
volumes:
|
||||||
|
- chroma_data:/chroma/chroma
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
chroma_data:
|
||||||
+1
-7
@@ -99,13 +99,7 @@ rm -rf "$PLUGIN_DIR/dist"
|
|||||||
cp "$SCRIPT_DIR/manifest.json" "$PLUGIN_DIR/"
|
cp "$SCRIPT_DIR/manifest.json" "$PLUGIN_DIR/"
|
||||||
cp "$SCRIPT_DIR/main.js" "$PLUGIN_DIR/"
|
cp "$SCRIPT_DIR/main.js" "$PLUGIN_DIR/"
|
||||||
|
|
||||||
# Copy only necessary runtime dependencies
|
# All dependencies are now bundled into main.js; no runtime node_modules needed.
|
||||||
# obsidian is a dev-only type stub — not needed at runtime
|
|
||||||
# chromadb is loaded dynamically and only needed when the cache is enabled.
|
|
||||||
mkdir -p "$PLUGIN_DIR/node_modules"
|
|
||||||
if [ -d "$SCRIPT_DIR/node_modules/chromadb" ]; then
|
|
||||||
cp -r "$SCRIPT_DIR/node_modules/chromadb" "$PLUGIN_DIR/node_modules/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Plugin installed to $PLUGIN_DIR"
|
info "Plugin installed to $PLUGIN_DIR"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"build": "tsc --noEmit && node -e \"require('esbuild').build({entryPoints:['src/main.ts'],bundle:true,platform:'node',target:'es2020',outfile:'main.js',external:['obsidian','chromadb'],format:'cjs'})\"",
|
"build": "tsc --noEmit && node -e \"require('esbuild').build({entryPoints:['src/main.ts'],bundle:true,platform:'node',target:'es2020',outfile:'main.js',external:['obsidian','cohere-ai','ollama','openai','@google/generative-ai','voyageai'],format:'cjs'})\"",
|
||||||
"watch": "tsc --watch",
|
"watch": "tsc --watch",
|
||||||
"lint": "eslint src --ext .ts",
|
"lint": "eslint src --ext .ts",
|
||||||
"format": "prettier --write ."
|
"format": "prettier --write ."
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ export class OllamaClient {
|
|||||||
|
|
||||||
if (cacheConfig?.enabled) {
|
if (cacheConfig?.enabled) {
|
||||||
this.cacheService = new SemanticCacheService(baseURL, cacheConfig);
|
this.cacheService = new SemanticCacheService(baseURL, cacheConfig);
|
||||||
void this.cacheService.initialize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,8 @@ export class SemanticCacheService {
|
|||||||
if (!this.config.enabled) return;
|
if (!this.config.enabled) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Dynamic require — chromadb is optional and may not be installed.
|
|
||||||
// Using Node's require() instead of ESM import() so Electron can resolve
|
|
||||||
// the external chromadb package against the plugin's node_modules.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const chromadb = require('chromadb');
|
const { ChromaClient } = require('chromadb');
|
||||||
const { ChromaClient } = chromadb;
|
|
||||||
const chromaURL = this.config.chromaURL || 'http://localhost:8000';
|
const chromaURL = this.config.chromaURL || 'http://localhost:8000';
|
||||||
this.client = new ChromaClient({ path: chromaURL });
|
this.client = new ChromaClient({ path: chromaURL });
|
||||||
this.collection = await this.client.getOrCreateCollection({
|
this.collection = await this.client.getOrCreateCollection({
|
||||||
|
|||||||
@@ -32,28 +32,30 @@ describe('OllamaClient', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
it('should initialize cache service when enabled', () => {
|
it('should create cache service when enabled but not initialize it eagerly', () => {
|
||||||
const cacheConfig: CacheConfig = {
|
const cacheConfig: CacheConfig = {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
similarityThreshold: 0.85,
|
similarityThreshold: 0.85,
|
||||||
collectionName: 'test_cache',
|
collectionName: 'test_cache',
|
||||||
embeddingModel: 'nomic-embed-text',
|
embeddingModel: 'nomic-embed-text',
|
||||||
chromaURL: 'http://localhost:8000'
|
chromaURL: 'http://localhost:8000',
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = new OllamaClient(mockBaseUrl, mockModel, undefined, cacheConfig);
|
const client = new OllamaClient(mockBaseUrl, mockModel, undefined, cacheConfig);
|
||||||
|
|
||||||
expect(client).toBeInstanceOf(OllamaClient);
|
expect(client).toBeInstanceOf(OllamaClient);
|
||||||
expect(mockInitialize).toHaveBeenCalledTimes(1);
|
// Eager initialization was removed to avoid unhandled rejections;
|
||||||
|
// initialization now happens via initializeCache() only.
|
||||||
|
expect(mockInitialize).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not initialize cache service when disabled', () => {
|
it('should not create cache service when disabled', () => {
|
||||||
const cacheConfig: CacheConfig = {
|
const cacheConfig: CacheConfig = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
similarityThreshold: 0.85,
|
similarityThreshold: 0.85,
|
||||||
collectionName: 'test_cache',
|
collectionName: 'test_cache',
|
||||||
embeddingModel: 'nomic-embed-text',
|
embeddingModel: 'nomic-embed-text',
|
||||||
chromaURL: 'http://localhost:8000'
|
chromaURL: 'http://localhost:8000',
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = new OllamaClient(mockBaseUrl, mockModel, undefined, cacheConfig);
|
const client = new OllamaClient(mockBaseUrl, mockModel, undefined, cacheConfig);
|
||||||
@@ -70,7 +72,7 @@ describe('OllamaClient', () => {
|
|||||||
similarityThreshold: 0.85,
|
similarityThreshold: 0.85,
|
||||||
collectionName: 'test_cache',
|
collectionName: 'test_cache',
|
||||||
embeddingModel: 'nomic-embed-text',
|
embeddingModel: 'nomic-embed-text',
|
||||||
chromaURL: 'http://localhost:8000'
|
chromaURL: 'http://localhost:8000',
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = new OllamaClient(mockBaseUrl, mockModel, undefined, cacheConfig);
|
const client = new OllamaClient(mockBaseUrl, mockModel, undefined, cacheConfig);
|
||||||
@@ -86,7 +88,7 @@ describe('OllamaClient', () => {
|
|||||||
similarityThreshold: 0.85,
|
similarityThreshold: 0.85,
|
||||||
collectionName: 'test_cache',
|
collectionName: 'test_cache',
|
||||||
embeddingModel: 'nomic-embed-text',
|
embeddingModel: 'nomic-embed-text',
|
||||||
chromaURL: 'http://localhost:8000'
|
chromaURL: 'http://localhost:8000',
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = new OllamaClient(mockBaseUrl, mockModel, undefined, cacheConfig);
|
const client = new OllamaClient(mockBaseUrl, mockModel, undefined, cacheConfig);
|
||||||
|
|||||||
Reference in New Issue
Block a user