Add ability to load Vencord from custom location (dev install)

This commit is contained in:
Vendicated 2023-04-09 02:26:31 +02:00
parent 591d380160
commit 805b6fbcc4
No known key found for this signature in database
GPG key ID: A1DC0CFB5615D905
14 changed files with 456 additions and 310 deletions

View file

@ -13,16 +13,19 @@
"package": "pnpm build && electron-builder", "package": "pnpm build && electron-builder",
"package:dir": "pnpm build && electron-builder --dir", "package:dir": "pnpm build && electron-builder --dir",
"start": "pnpm build && electron .", "start": "pnpm build && electron .",
"start:watch": "tsx scripts/startWatch.mts", "start:dev": "pnpm build --dev && electron .",
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"watch": "pnpm build --watch" "watch": "pnpm build --watch"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^18.15.11", "@types/node": "^18.15.11",
"@types/react": "^18.0.33",
"electron": "^23.2.0", "electron": "^23.2.0",
"electron-builder": "^23.6.0", "electron-builder": "^23.6.0",
"esbuild": "^0.17.14", "esbuild": "^0.17.14",
"source-map-support": "^0.5.21",
"tsx": "^3.12.6", "tsx": "^3.12.6",
"type-fest": "^3.8.0",
"typescript": "^5.0.2" "typescript": "^5.0.2"
}, },
"build": { "build": {

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,9 @@
import { BuildContext, BuildOptions, context } from "esbuild"; import { BuildContext, BuildOptions, context } from "esbuild";
const isDev = process.argv.includes("--dev");
const CommonOpts: BuildOptions = { const CommonOpts: BuildOptions = {
minify: true, minify: !isDev,
bundle: true, bundle: true,
sourcemap: "linked", sourcemap: "linked",
logLevel: "info" logLevel: "info"
@ -13,6 +15,9 @@ const NodeCommonOpts: BuildOptions = {
platform: "node", platform: "node",
external: ["electron"], external: ["electron"],
target: ["esnext"], target: ["esnext"],
define: {
IS_DEV: JSON.stringify(isDev)
}
}; };
const contexts = [] as BuildContext[]; const contexts = [] as BuildContext[];

2
src/globals.d.ts vendored
View file

@ -4,6 +4,8 @@ declare global {
// TODO // TODO
export var Vencord: any; export var Vencord: any;
export var vcdLS: typeof localStorage; export var vcdLS: typeof localStorage;
export var IS_DEV: boolean;
} }
export { }; export { };

View file

@ -1,8 +1,10 @@
import { app } from "electron"; import { app } from "electron";
import { join } from "path"; import { join } from "path";
export const DATA_DIR = process.env.VENCORD_USER_DATA_DIR ?? join(app.getPath("userData"), "VencordDesktop"); export const DATA_DIR = process.env.VENCORD_USER_DATA_DIR || join(app.getPath("userData"), "VencordDesktop");
export const VENCORD_FILES_DIR = join(DATA_DIR, "vencordDist"); // needs to be inline require because of circular dependency
// as otherwise "DATA_DIR" (which is used by ./settings) will be uninitialised
export const VENCORD_FILES_DIR = require("./settings").Settings.vencordDir || join(DATA_DIR, "vencordDist");
export const VENCORD_SETTINGS_DIR = join(DATA_DIR, "settings"); export const VENCORD_SETTINGS_DIR = join(DATA_DIR, "settings");
export const VENCORD_QUICKCSS_FILE = join(VENCORD_SETTINGS_DIR, "quickCss.css"); export const VENCORD_QUICKCSS_FILE = join(VENCORD_SETTINGS_DIR, "quickCss.css");
export const VENCORD_SETTINGS_FILE = join(VENCORD_SETTINGS_DIR, "settings.json"); export const VENCORD_SETTINGS_FILE = join(VENCORD_SETTINGS_DIR, "settings.json");

View file

@ -3,16 +3,20 @@ import { join } from "path";
import { ICON_PATH } from "../shared/paths"; import { ICON_PATH } from "../shared/paths";
import { once } from "../shared/utils/once"; import { once } from "../shared/utils/once";
import { DATA_DIR, VENCORD_FILES_DIR } from "./constants"; import { DATA_DIR, VENCORD_FILES_DIR } from "./constants";
import "./ipc";
import { createMainWindow } from "./mainWindow"; import { createMainWindow } from "./mainWindow";
import { Settings } from "./settings"; import { Settings } from "./settings";
import { createSplashWindow } from "./splash"; import { createSplashWindow } from "./splash";
import { ensureVencordFiles } from "./utils/vencordLoader"; import { ensureVencordFiles } from "./utils/vencordLoader";
import "./ipc";
if (IS_DEV) {
require("source-map-support").install();
}
// Make the Vencord files use our DATA_DIR // Make the Vencord files use our DATA_DIR
process.env.VENCORD_USER_DATA_DIR = DATA_DIR; process.env.VENCORD_USER_DATA_DIR = DATA_DIR;
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "main.js"))); const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js")));
let mainWin: BrowserWindow | null = null; let mainWin: BrowserWindow | null = null;

View file

@ -1,5 +1,5 @@
import { app, ipcMain, shell } from "electron"; import { app, dialog, ipcMain, shell } from "electron";
import { readFileSync, watch } from "fs"; import { existsSync, readFileSync, watch } from "fs";
import { open, readFile } from "fs/promises"; import { open, readFile } from "fs/promises";
import { join } from "path"; import { join } from "path";
import { debounce } from "shared/utils/debounce"; import { debounce } from "shared/utils/debounce";
@ -12,6 +12,10 @@ ipcMain.on(IpcEvents.GET_VENCORD_PRELOAD_FILE, e => {
e.returnValue = join(VENCORD_FILES_DIR, "preload.js"); e.returnValue = join(VENCORD_FILES_DIR, "preload.js");
}); });
ipcMain.on(IpcEvents.GET_VENCORD_RENDERER_SCRIPT, e => {
e.returnValue = readFileSync(join(VENCORD_FILES_DIR, "vencordDesktopRenderer.js"), "utf-8");
});
ipcMain.on(IpcEvents.GET_RENDERER_SCRIPT, e => { ipcMain.on(IpcEvents.GET_RENDERER_SCRIPT, e => {
e.returnValue = readFileSync(join(__dirname, "renderer.js"), "utf-8"); e.returnValue = readFileSync(join(__dirname, "renderer.js"), "utf-8");
}); });
@ -39,6 +43,20 @@ ipcMain.handle(IpcEvents.FOCUS, () => {
mainWin?.focus(); mainWin?.focus();
}); });
ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
const res = await dialog.showOpenDialog(mainWin!, {
properties: ["openDirectory"]
});
if (!res.filePaths.length) return "cancelled";
const dir = res.filePaths[0];
for (const file of ["vencordDesktopMain.js", "preload.js", "vencordDesktopRenderer.js", "renderer.css"]) {
if (!existsSync(join(dir, file))) return "invalid";
}
return dir;
});
function readCss() { function readCss() {
return readFile(VENCORD_QUICKCSS_FILE, "utf-8").catch(() => ""); return readFile(VENCORD_QUICKCSS_FILE, "utf-8").catch(() => "");
} }

View file

@ -1,21 +1,31 @@
import { app, ipcRenderer } from "electron"; import { app, ipcRenderer } from "electron";
import type { Settings } from "../main/settings"; import type { Settings } from "shared/settings";
import type { LiteralUnion } from "type-fest";
import { IpcEvents } from "../shared/IpcEvents"; import { IpcEvents } from "../shared/IpcEvents";
function invoke<T = any>(event: IpcEvents, ...args: any[]) {
return ipcRenderer.invoke(event, ...args) as Promise<T>;
}
function sendSync<T = any>(event: IpcEvents, ...args: any[]) {
return ipcRenderer.sendSync(event, ...args) as T;
}
export const VencordDesktopNative = { export const VencordDesktopNative = {
app: { app: {
relaunch: () => ipcRenderer.invoke(IpcEvents.RELAUNCH), relaunch: () => invoke<void>(IpcEvents.RELAUNCH),
getVersion: () => app.getVersion() getVersion: () => app.getVersion()
}, },
fileManager: { fileManager: {
showItemInFolder: (path: string) => ipcRenderer.invoke(IpcEvents.SHOW_ITEM_IN_FOLDER, path) showItemInFolder: (path: string) => invoke<void>(IpcEvents.SHOW_ITEM_IN_FOLDER, path),
selectVencordDir: () => invoke<LiteralUnion<"cancelled" | "invalid", string>>(IpcEvents.SELECT_VENCORD_DIR),
}, },
settings: { settings: {
get: () => ipcRenderer.sendSync(IpcEvents.GET_SETTINGS), get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
set: (settings: typeof Settings) => ipcRenderer.invoke(IpcEvents.SET_SETTINGS, settings) set: (settings: Settings) => invoke<void>(IpcEvents.SET_SETTINGS, settings)
}, },
win: { win: {
focus: () => ipcRenderer.invoke(IpcEvents.FOCUS) focus: () => invoke<void>(IpcEvents.FOCUS)
} }
} }

View file

@ -6,5 +6,6 @@ contextBridge.exposeInMainWorld("VencordDesktopNative", VencordDesktopNative);
require(ipcRenderer.sendSync(IpcEvents.GET_VENCORD_PRELOAD_FILE)); require(ipcRenderer.sendSync(IpcEvents.GET_VENCORD_PRELOAD_FILE));
webFrame.executeJavaScript(ipcRenderer.sendSync(IpcEvents.GET_VENCORD_RENDERER_SCRIPT));
webFrame.executeJavaScript(ipcRenderer.sendSync(IpcEvents.GET_RENDERER_SCRIPT)); webFrame.executeJavaScript(ipcRenderer.sendSync(IpcEvents.GET_RENDERER_SCRIPT));
ipcRenderer.invoke(IpcEvents.GET_RENDERER_STYLES).then(s => webFrame.insertCSS(s)); ipcRenderer.invoke(IpcEvents.GET_RENDERER_STYLES).then(s => webFrame.insertCSS(s));

View file

@ -1,9 +1,13 @@
import { getValueAndOnChange, useSettings } from "renderer/settings"; import { getValueAndOnChange, useSettings } from "renderer/settings";
import { Common } from "../vencord"; import { Common, Util } from "../vencord";
import "./settings.css";
const { Margins } = Util;
export default function SettingsUi() { export default function SettingsUi() {
const Settings = useSettings(); const Settings = useSettings();
const { Forms: { FormSection, FormText, FormDivider, FormSwitch, FormTitle }, Text, Select } = Common; const { Forms: { FormSection, FormText, FormDivider, FormSwitch, FormTitle }, Text, Select, Button } = Common;
return ( return (
<FormSection> <FormSection>
@ -11,7 +15,9 @@ export default function SettingsUi() {
Vencord Desktop Settings Vencord Desktop Settings
</Text> </Text>
<FormTitle>Discord Branch</FormTitle> <FormTitle className={Margins.top16}>
Discord Branch
</FormTitle>
<Select <Select
placeholder="Stable" placeholder="Stable"
options={[ options={[
@ -25,12 +31,58 @@ export default function SettingsUi() {
serialize={s => s} serialize={s => s}
/> />
<FormDivider className={Margins.top16 + " " + Margins.bottom16} />
<FormSwitch <FormSwitch
{...getValueAndOnChange("openLinksWithElectron")} {...getValueAndOnChange("openLinksWithElectron")}
note={"This will open links in a new window instead of your WebBrowser"} note={"This will open links in a new window instead of your WebBrowser"}
> >
Open Links in app Open Links in app
</FormSwitch> </FormSwitch>
<FormTitle>Vencord Desktop Location</FormTitle>
<FormText>
Files are loaded from
{" "}
{Settings.vencordDir
? (
<a
href="about:blank"
onClick={e => {
e.preventDefault();
VencordDesktopNative.fileManager.showItemInFolder(Settings.vencordDir!);
}}
>
{Settings.vencordDir}
</a>
)
: "the default location"
}
</FormText>
<div className="vcd-location-btns">
<Button
size={Button.Sizes.SMALL}
onClick={async () => {
const choice = await VencordDesktopNative.fileManager.selectVencordDir();
switch (choice) {
case "cancelled":
case "invalid":
// TODO
return;
}
Settings.vencordDir = choice;
}}
>
Change
</Button>
<Button
size={Button.Sizes.SMALL}
color={Button.Colors.RED}
onClick={() => Settings.vencordDir = void 0}
>
Reset
</Button>
</div>
</FormSection> </FormSection>
); );
} }

View file

@ -0,0 +1,6 @@
.vcd-location-btns {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5em;
margin-top: 0.5em;
}

View file

@ -1,12 +1,13 @@
// TODO: Taaaips when? // FIXME: this is terrible
const { Webpack, Plugins } = Vencord; const { Webpack, Plugins, Util } = Vencord;
const { Common } = Webpack; const { Common } = Webpack;
const { plugins } = Plugins; const { plugins } = Plugins;
export { export {
Webpack, Webpack,
Common, Common,
Util,
Plugins, Plugins,
plugins plugins
}; };

View file

@ -1,5 +1,6 @@
export const enum IpcEvents { export const enum IpcEvents {
GET_VENCORD_PRELOAD_FILE = "VCD_GET_VC_PRELOAD_FILE", GET_VENCORD_PRELOAD_FILE = "VCD_GET_VC_PRELOAD_FILE",
GET_VENCORD_RENDERER_SCRIPT = "VCD_GET_VC_RENDERER_SCRIPT",
GET_RENDERER_SCRIPT = "VCD_GET_RENDERER_SCRIPT", GET_RENDERER_SCRIPT = "VCD_GET_RENDERER_SCRIPT",
GET_RENDERER_STYLES = "VCD_GET_RENDERER_STYLES", GET_RENDERER_STYLES = "VCD_GET_RENDERER_STYLES",
@ -9,5 +10,7 @@ export const enum IpcEvents {
SHOW_ITEM_IN_FOLDER = "VCD_SHOW_ITEM_IN_FOLDER", SHOW_ITEM_IN_FOLDER = "VCD_SHOW_ITEM_IN_FOLDER",
GET_SETTINGS = "VCD_GET_SETTINGS", GET_SETTINGS = "VCD_GET_SETTINGS",
SET_SETTINGS = "VCD_SET_SETTINGS", SET_SETTINGS = "VCD_SET_SETTINGS",
SELECT_VENCORD_DIR = "VCD_SELECT_VENCORD_DIR"
} }

View file

@ -9,4 +9,5 @@ export interface Settings {
}; };
discordBranch?: "stable" | "canary" | "ptb"; discordBranch?: "stable" | "canary" | "ptb";
openLinksWithElectron?: boolean; openLinksWithElectron?: boolean;
vencordDir?: string;
} }