mirror of
https://github.com/Nystik-gh/ignis.git
synced 2026-06-17 04:35:53 +00:00
refactor bridge plugin into virtual module
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
const esbuild = require("esbuild");
|
||||
const path = require("path");
|
||||
|
||||
module.exports = esbuild.build({
|
||||
entryPoints: [path.join(__dirname, "src", "main.js")],
|
||||
bundle: true,
|
||||
outfile: path.join(__dirname, "main.js"),
|
||||
format: "cjs",
|
||||
platform: "browser",
|
||||
target: ["chrome90"],
|
||||
external: ["obsidian", "fs"],
|
||||
logLevel: "info",
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"id": "ignis-bridge",
|
||||
"name": "Ignis Bridge",
|
||||
"version": "0.8.1",
|
||||
"minAppVersion": "1.12.4",
|
||||
"description": "Additional Ignis specific functionality and ignis plugin management.",
|
||||
"author": "Nystik",
|
||||
"authorUrl": "https://github.com/Nystik-gh/ignis",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
@@ -2,10 +2,5 @@
|
||||
"name": "@ignis/bridge",
|
||||
"version": "0.0.0-internal",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "node build.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.20.0"
|
||||
}
|
||||
"main": "src/main.js"
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ const { initStatusBar } = require("./status-bar");
|
||||
const { WorkspacePickerModal } = require("./workspace-picker");
|
||||
const { startDemoGuards, stopDemoGuards } = require("./demo-guards");
|
||||
|
||||
window.__obsidianAPI = require("obsidian");
|
||||
|
||||
class IgnisBridgePlugin extends Plugin {
|
||||
async onload() {
|
||||
if (!window.__ignis) {
|
||||
|
||||
@@ -13,6 +13,10 @@ module.exports = esbuild.build({
|
||||
alias: {
|
||||
path: "path-browserify",
|
||||
},
|
||||
loader: {
|
||||
".css": "text",
|
||||
},
|
||||
external: ["obsidian", "fs"],
|
||||
define: {
|
||||
__IGNIS_VERSION__: JSON.stringify(ignisVersion),
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Injects a link to the CSS overrides stylesheet served from /assets/overrides.css.
|
||||
import bridgeCss from "@ignis/bridge/styles.css";
|
||||
|
||||
export function installCssOverrides() {
|
||||
const link = document.createElement("link");
|
||||
@@ -6,4 +6,9 @@ export function installCssOverrides() {
|
||||
link.href = "/assets/overrides.css";
|
||||
link.setAttribute("data-ignis", "css-overrides");
|
||||
document.head.appendChild(link);
|
||||
|
||||
const bridgeStyle = document.createElement("style");
|
||||
bridgeStyle.textContent = bridgeCss;
|
||||
bridgeStyle.setAttribute("data-ignis", "bridge-css");
|
||||
document.head.appendChild(bridgeStyle);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { markLocalOp } from "./echo-guard.js";
|
||||
import { isInputCachePath, inputCacheGet } from "./input-cache.js";
|
||||
import { applyReadTransform, applyWriteTransform, resolvePath } from "./transforms.js";
|
||||
import { hasVirtualFile, getVirtualFile } from "./virtual-files.js";
|
||||
|
||||
export function createFsPromises(metadataCache, contentCache, transport) {
|
||||
return {
|
||||
@@ -49,6 +50,21 @@ export function createFsPromises(metadataCache, contentCache, transport) {
|
||||
const wantText = encoding === "utf8" || encoding === "utf-8";
|
||||
const resolved = resolvePath(path);
|
||||
|
||||
// Virtual plugin source overrides any cache/transport version.
|
||||
if (hasVirtualFile(resolved)) {
|
||||
const content = getVirtualFile(resolved);
|
||||
|
||||
if (wantText) {
|
||||
return typeof content === "string"
|
||||
? content
|
||||
: new TextDecoder().decode(content);
|
||||
}
|
||||
|
||||
return typeof content === "string"
|
||||
? new TextEncoder().encode(content)
|
||||
: content;
|
||||
}
|
||||
|
||||
let result = null;
|
||||
|
||||
// Check input cache for files picked via browser file dialogs.
|
||||
|
||||
23
packages/shim/src/fs/virtual-files.js
Normal file
23
packages/shim/src/fs/virtual-files.js
Normal file
@@ -0,0 +1,23 @@
|
||||
// Virtual plugin source served from memory; the fs shim's read path checks here before disk.
|
||||
|
||||
function normalize(p) {
|
||||
return (p || "").replace(/\\/g, "/").replace(/^\/+/, "").replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
const virtualFiles = new Map();
|
||||
|
||||
export function setVirtualFile(path, content) {
|
||||
virtualFiles.set(normalize(path), content);
|
||||
}
|
||||
|
||||
export function removeVirtualFile(path) {
|
||||
virtualFiles.delete(normalize(path));
|
||||
}
|
||||
|
||||
export function getVirtualFile(path) {
|
||||
return virtualFiles.get(normalize(path));
|
||||
}
|
||||
|
||||
export function hasVirtualFile(path) {
|
||||
return virtualFiles.has(normalize(path));
|
||||
}
|
||||
@@ -4,11 +4,24 @@ import { installCssOverrides } from "./css-overrides.js";
|
||||
import { initialize } from "./init.js";
|
||||
import { fsShim } from "./fs/index.js";
|
||||
import { registerUI } from "./ui-registry.js";
|
||||
import { extractObsidianModule } from "./virtual-plugin-loader.js";
|
||||
|
||||
// __IGNIS_VERSION__ is replaced at build time from package.json.
|
||||
window.__ignis = { version: __IGNIS_VERSION__ };
|
||||
window.__ignis_registerUI = registerUI;
|
||||
|
||||
const BRIDGE_MANIFEST = {
|
||||
id: "ignis-bridge",
|
||||
name: "Ignis Bridge",
|
||||
version: __IGNIS_VERSION__,
|
||||
minAppVersion: "1.12.4",
|
||||
description:
|
||||
"Additional Ignis specific functionality and ignis plugin management.",
|
||||
author: "Nystik",
|
||||
authorUrl: "https://github.com/Nystik-gh/ignis",
|
||||
isDesktopOnly: false,
|
||||
};
|
||||
|
||||
installGlobals(); // process, Buffer, window overrides (before require so Buffer is available)
|
||||
installRequire(); // shim registry, window.require
|
||||
installCssOverrides(); // browser-specific CSS fixes
|
||||
@@ -27,4 +40,15 @@ if (window.__currentVaultId) {
|
||||
fsShim._watcherClient.connect(window.__currentVaultId);
|
||||
}
|
||||
|
||||
extractObsidianModule()
|
||||
.then(async () => {
|
||||
// Dynamic import so bridge's top-level require("obsidian") fires after installRequire + extractObsidianModule.
|
||||
const mod = await import("@ignis/bridge");
|
||||
const IgnisBridgePlugin = mod.default || mod;
|
||||
const bridge = new IgnisBridgePlugin(window.app, BRIDGE_MANIFEST);
|
||||
await bridge.onload();
|
||||
console.log("[ignis] bridge loaded");
|
||||
})
|
||||
.catch((e) => console.error("[ignis] bridge load failed:", e));
|
||||
|
||||
console.log("[ignis] Shim loader initialized");
|
||||
|
||||
@@ -67,3 +67,8 @@ export function installRequire() {
|
||||
|
||||
installDebugHelpers(rawRegistry);
|
||||
}
|
||||
|
||||
// For modules captured at runtime, e.g. the obsidian module via the virtual-plugin loader.
|
||||
export function registerShim(name, mod) {
|
||||
shimRegistry[name] = mod;
|
||||
}
|
||||
|
||||
105
packages/shim/src/virtual-plugin-loader.js
Normal file
105
packages/shim/src/virtual-plugin-loader.js
Normal file
@@ -0,0 +1,105 @@
|
||||
// Capture the obsidian module via a one-shot synthetic plugin so virtual plugins (bridge, future bundled) can require("obsidian").
|
||||
|
||||
import { setVirtualFile, removeVirtualFile } from "./fs/virtual-files.js";
|
||||
import { registerShim } from "./require.js";
|
||||
|
||||
const EXTRACTOR_ID = "ignis-obsidian-extractor";
|
||||
const EXTRACTOR_DIR = ".ignis/virtual/" + EXTRACTOR_ID;
|
||||
const EXTRACTOR_PATH = EXTRACTOR_DIR + "/main.js";
|
||||
|
||||
const EXTRACTOR_SRC = `
|
||||
const obsidian = require("obsidian");
|
||||
window.__ignisCapturedObsidian = obsidian;
|
||||
module.exports = class extends obsidian.Plugin {
|
||||
onload() {}
|
||||
};
|
||||
`;
|
||||
|
||||
const EXTRACTOR_MANIFEST = {
|
||||
id: EXTRACTOR_ID,
|
||||
name: "Ignis Obsidian Module Extractor",
|
||||
version: "0.0.0",
|
||||
minAppVersion: "1.0.0",
|
||||
description: "Internal: captures the obsidian module for virtual plugins.",
|
||||
author: "ignis",
|
||||
authorUrl: "",
|
||||
isDesktopOnly: false,
|
||||
dir: EXTRACTOR_DIR,
|
||||
};
|
||||
|
||||
function waitForApp() {
|
||||
return new Promise((resolve) => {
|
||||
if (window.app && window.app.plugins && window.app.workspace) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (window.app && window.app.plugins && window.app.workspace) {
|
||||
clearInterval(interval);
|
||||
resolve();
|
||||
}
|
||||
}, 20);
|
||||
});
|
||||
}
|
||||
|
||||
export async function extractObsidianModule() {
|
||||
if (window.__obsidian) {
|
||||
return window.__obsidian;
|
||||
}
|
||||
|
||||
await waitForApp();
|
||||
|
||||
const plugins = window.app.plugins;
|
||||
|
||||
// loadPlugin gates on isEnabled(). Force-enable, restore on cleanup.
|
||||
const wasEnabled = plugins.isEnabled();
|
||||
let toggledOn = false;
|
||||
|
||||
if (!wasEnabled) {
|
||||
try {
|
||||
await plugins.setEnable(true);
|
||||
toggledOn = true;
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
"[ignis] could not enable community plugins for extractor:",
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setVirtualFile(EXTRACTOR_PATH, EXTRACTOR_SRC);
|
||||
plugins.manifests[EXTRACTOR_ID] = EXTRACTOR_MANIFEST;
|
||||
|
||||
try {
|
||||
await plugins.loadPlugin(EXTRACTOR_ID);
|
||||
} catch (e) {
|
||||
console.error("[ignis] extractor load failed:", e);
|
||||
}
|
||||
|
||||
const captured = window.__ignisCapturedObsidian;
|
||||
|
||||
try {
|
||||
await plugins.unloadPlugin(EXTRACTOR_ID);
|
||||
} catch {}
|
||||
|
||||
delete plugins.manifests[EXTRACTOR_ID];
|
||||
removeVirtualFile(EXTRACTOR_PATH);
|
||||
delete window.__ignisCapturedObsidian;
|
||||
|
||||
if (toggledOn) {
|
||||
try {
|
||||
await plugins.setEnable(false);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (!captured) {
|
||||
console.error("[ignis] obsidian module extraction failed");
|
||||
return null;
|
||||
}
|
||||
|
||||
window.__obsidian = captured;
|
||||
registerShim("obsidian", captured);
|
||||
|
||||
console.log("[ignis] obsidian module captured");
|
||||
return captured;
|
||||
}
|
||||
Reference in New Issue
Block a user