From e5a9e4a24b0b8d0b34d807c967005b94a2a2ccd1 Mon Sep 17 00:00:00 2001 From: Andrew Beal Date: Mon, 1 Jun 2026 00:04:39 +0100 Subject: [PATCH] refactor: bundle assets at build time instead of loading from disk Remove runtime asset loading from AssetsService by importing assets directly and configuring esbuild loaders for SVG (text) and PNG (dataurl). This ensures assets work in release builds where only main.js is shipped without the Assets folder. --- Services/AssetsService.ts | 30 ++++++++++-------------------- esbuild.config.mjs | 2 ++ global.d.ts | 10 ++++++++++ main.ts | 5 +---- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/Services/AssetsService.ts b/Services/AssetsService.ts index 7b39fd1..bffaf7c 100644 --- a/Services/AssetsService.ts +++ b/Services/AssetsService.ts @@ -1,30 +1,20 @@ -import type VaultkeeperAIPlugin from "main"; -import { Resolve } from "./DependencyService"; -import { Services } from "./Services"; import { addIcon } from "obsidian"; +import iconSvg from "../Assets/vaultkeeper-mono.svg"; +import bannerSource from "../Assets/vaultkeeper-social-1280x330.png"; export class AssetsService { - private readonly plugin: VaultkeeperAIPlugin; - - public pluginIcon: string = ""; - public bannerSource: string = ""; + public pluginIcon: string; + public bannerSource: string; + // Assets are bundled into main.js at build time (see esbuild loader config). + // They must NOT be read from disk at runtime: released/mobile installs ship + // only main.js, manifest.json and styles.css, so the Assets/ folder is absent. public constructor() { - this.plugin = Resolve(Services.VaultkeeperAIPlugin); + this.pluginIcon = this.addIcon(iconSvg, "vaultkeeper-ai-icon"); + this.bannerSource = bannerSource; } - - public async loadAssets(): Promise { - this.pluginIcon = this.addIcon( - await this.plugin.app.vault.adapter.read(`${this.plugin.manifest.dir}/Assets/vaultkeeper-mono.svg`), - "vaultkeeper-ai-icon" - ); - - this.bannerSource = this.plugin.app.vault.adapter.getResourcePath( - `${this.plugin.manifest.dir}/Assets/vaultkeeper-social-1280x330.png` - ); - } - + private addIcon(icon: string, name: string): string { addIcon(name, icon); return name; diff --git a/esbuild.config.mjs b/esbuild.config.mjs index e643d3a..ae6db53 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -296,6 +296,8 @@ const buildOptions = { minify: prod, loader: { ".css": "css", + ".svg": "text", + ".png": "dataurl", ".ttf": "file", ".woff": "file", ".woff2": "file", diff --git a/global.d.ts b/global.d.ts index d257ebe..595f21b 100644 --- a/global.d.ts +++ b/global.d.ts @@ -2,3 +2,13 @@ declare module '*.css' { const content: string; export default content; } + +declare module '*.svg' { + const content: string; + export default content; +} + +declare module '*.png' { + const content: string; + export default content; +} diff --git a/main.ts b/main.ts index 391e353..cc6417c 100644 --- a/main.ts +++ b/main.ts @@ -20,10 +20,6 @@ export default class VaultkeeperAIPlugin extends Plugin { public async onload() { await RegisterPlugin(this); - - const assetsService = Resolve(Services.AssetsService); - - await assetsService.loadAssets(); RegisterDependencies(); this.registerView( @@ -43,6 +39,7 @@ export default class VaultkeeperAIPlugin extends Plugin { } }); + const assetsService = Resolve(Services.AssetsService); this.addRibbonIcon(assetsService.pluginIcon, "Vaultkeeper AI", async () => { await this.activateMainView(); });