diff --git a/build.mjs b/build.mjs
deleted file mode 100755
index e5797865..00000000
--- a/build.mjs
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/node
-import { execSync } from "child_process";
-import esbuild from "esbuild";
-import { readdirSync } from "fs";
-
-/**
- * @type {esbuild.WatchMode|false}
- */
-const watch = process.argv.includes("--watch");
-
-// https://github.com/evanw/esbuild/issues/619#issuecomment-751995294
-/**
- * @type {esbuild.Plugin}
- */
-const makeAllPackagesExternalPlugin = {
- name: "make-all-packages-external",
- setup(build) {
- let filter = /^[^.\/]|^\.[^.\/]|^\.\.[^\/]/; // Must not start with "/" or "./" or "../"
- build.onResolve({ filter }, args => ({ path: args.path, external: true }));
- },
-};
-
-/**
- * @type {esbuild.Plugin}
- */
-const globPlugins = {
- name: "glob-plugins",
- setup: build => {
- build.onResolve({ filter: /^plugins$/ }, args => {
- return {
- namespace: "import-plugins",
- path: args.path
- };
- });
-
- build.onLoad({ filter: /^plugins$/, namespace: "import-plugins" }, () => {
- const files = readdirSync("./src/plugins");
- let code = "";
- let obj = "";
- for (let i = 0; i < files.length; i++) {
- if (files[i] === "index.ts") {
- continue;
- }
- const mod = `__pluginMod${i}`;
- code += `import ${mod} from "./${files[i].replace(/.tsx?$/, "")}";\n`;
- obj += `[${mod}.name]: ${mod},`;
- }
- code += `export default {${obj}}`;
- return {
- contents: code,
- resolveDir: "./src/plugins"
- };
- });
- }
-};
-
-const gitHash = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
-/**
- * @type {esbuild.Plugin}
- */
-const gitHashPlugin = {
- name: "git-hash-plugin",
- setup: build => {
- const filter = /^git-hash$/;
- build.onResolve({ filter }, args => ({
- namespace: "git-hash", path: args.path
- }));
- build.onLoad({ filter, namespace: "git-hash" }, () => ({
- contents: `export default "${gitHash}"`
- }));
- }
-};
-
-await Promise.all([
- esbuild.build({
- logLevel: "info",
- entryPoints: ["src/preload.ts"],
- outfile: "dist/preload.js",
- format: "cjs",
- bundle: true,
- platform: "node",
- target: ["esnext"],
- sourcemap: "linked",
- plugins: [makeAllPackagesExternalPlugin],
- watch
- }),
- esbuild.build({
- logLevel: "info",
- entryPoints: ["src/patcher.ts"],
- outfile: "dist/patcher.js",
- bundle: true,
- format: "cjs",
- target: ["esnext"],
- external: ["electron"],
- platform: "node",
- sourcemap: "linked",
- plugins: [makeAllPackagesExternalPlugin],
- watch
- }),
- esbuild.build({
- logLevel: "info",
- entryPoints: ["src/Vencord.ts"],
- outfile: "dist/renderer.js",
- format: "iife",
- bundle: true,
- target: ["esnext"],
- footer: { js: "//# sourceURL=VencordRenderer" },
- globalName: "Vencord",
- external: ["plugins", "git-hash"],
- plugins: [
- globPlugins,
- gitHashPlugin
- ],
- sourcemap: false,
- watch,
- minify: true,
- }),
-]).catch(err => {
- console.error("Build failed");
- console.error(err.message);
- // make ci fail
- if (!watch)
- process.exitCode = 1;
-});
diff --git a/buildWeb.mjs b/buildWeb.mjs
deleted file mode 100644
index 0bd6618b..00000000
--- a/buildWeb.mjs
+++ /dev/null
@@ -1,110 +0,0 @@
-// TODO: Modularise the plugins since both build scripts use them
-
-import { execSync } from "child_process";
-import { createWriteStream, readdirSync, readFileSync } from "fs";
-import yazl from "yazl";
-import esbuild from "esbuild";
-// wtf is this assert syntax
-import PackageJSON from "./package.json" assert { type: "json" };
-
-/**
- * @type {esbuild.Plugin}
- */
-const globPlugins = {
- name: "glob-plugins",
- setup: build => {
- build.onResolve({ filter: /^plugins$/ }, args => {
- return {
- namespace: "import-plugins",
- path: args.path
- };
- });
-
- build.onLoad({ filter: /^plugins$/, namespace: "import-plugins" }, () => {
- const files = readdirSync("./src/plugins");
- let code = "";
- let obj = "";
- for (let i = 0; i < files.length; i++) {
- if (files[i] === "index.ts") {
- continue;
- }
- const mod = `__pluginMod${i}`;
- code += `import ${mod} from "./${files[i].replace(/.tsx?$/, "")}";\n`;
- obj += `[${mod}.name]: ${mod},`;
- }
- code += `export default {${obj}}`;
- return {
- contents: code,
- resolveDir: "./src/plugins"
- };
- });
- }
-};
-
-const gitHash = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
-/**
- * @type {esbuild.Plugin}
- */
-const gitHashPlugin = {
- name: "git-hash-plugin",
- setup: build => {
- const filter = /^git-hash$/;
- build.onResolve({ filter }, args => ({
- namespace: "git-hash", path: args.path
- }));
- build.onLoad({ filter, namespace: "git-hash" }, () => ({
- contents: `export default "${gitHash}"`
- }));
- }
-};
-
-/**
- * @type {esbuild.BuildOptions}
- */
-const commonOptions = {
- logLevel: "info",
- entryPoints: ["browser/Vencord.ts"],
- globalName: "Vencord",
- format: "iife",
- bundle: true,
- minify: true,
- sourcemap: false,
- external: ["plugins", "git-hash"],
- plugins: [
- globPlugins,
- gitHashPlugin
- ],
- target: ["esnext"],
-};
-
-await Promise.all(
- [
- esbuild.build({
- ...commonOptions,
- outfile: "dist/browser.js",
- footer: { js: "//# sourceURL=VencordWeb" },
- }),
- esbuild.build({
- ...commonOptions,
- outfile: "dist/Vencord.user.js",
- banner: {
- js: readFileSync("browser/userscript.meta.js", "utf-8").replace("%version%", PackageJSON.version)
- },
- footer: {
- // UserScripts get wrapped in an iife, so define Vencord prop on window that returns our local
- js: "Object.defineProperty(window,'Vencord',{get:()=>Vencord});"
- },
- })
- ]
-);
-
-const zip = new yazl.ZipFile();
-zip.outputStream.pipe(createWriteStream("dist/extension.zip")).on("close", () => {
- console.info("Extension written to dist/extension.zip");
-});
-
-zip.addFile("dist/browser.js", "dist/Vencord.js");
-["background.js", "content.js", "manifest.json"].forEach(f => {
- zip.addFile(`browser/${f}`, `${f}`);
-});
-zip.end();
diff --git a/package.json b/package.json
index 48734b3d..711fde14 100644
--- a/package.json
+++ b/package.json
@@ -18,15 +18,15 @@
"doc": "docs"
},
"scripts": {
- "build": "node build.mjs",
- "buildWeb": "node --require=./scripts/suppressExperimentalWarnings.js buildWeb.mjs",
+ "build": "node scripts/build/build.mjs",
+ "buildWeb": "node --require=./scripts/suppressExperimentalWarnings.js scripts/build/buildWeb.mjs",
"inject": "node scripts/patcher/install.js",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "pnpm lint --fix",
"test": "pnpm lint && pnpm build && pnpm testTsc",
"testTsc": "tsc --noEmit",
"uninject": "node scripts/patcher/uninstall.js",
- "watch": "node build.mjs --watch"
+ "watch": "node scripts/build/build.mjs --watch"
},
"dependencies": {
"console-menu": "^0.1.0",
diff --git a/scripts/build/build.mjs b/scripts/build/build.mjs
new file mode 100755
index 00000000..281246af
--- /dev/null
+++ b/scripts/build/build.mjs
@@ -0,0 +1,53 @@
+#!/usr/bin/node
+import esbuild from "esbuild";
+import { commonOpts, gitHashPlugin, globPlugins, makeAllPackagesExternalPlugin } from "./common.mjs";
+
+/**
+ * @type {esbuild.BuildOptions}
+ */
+const nodeCommonOpts = {
+ ...commonOpts,
+ format: "cjs",
+ platform: "node",
+ target: ["esnext"],
+ sourcemap: "linked",
+ plugins: [makeAllPackagesExternalPlugin],
+};
+
+await Promise.all([
+ esbuild.build({
+ ...nodeCommonOpts,
+ entryPoints: ["src/preload.ts"],
+ outfile: "dist/preload.js",
+ }),
+ esbuild.build({
+ ...nodeCommonOpts,
+ entryPoints: ["src/patcher.ts"],
+ outfile: "dist/patcher.js",
+ }),
+ esbuild.build({
+ ...commonOpts,
+ entryPoints: ["src/Vencord.ts"],
+ outfile: "dist/renderer.js",
+ format: "iife",
+ target: ["esnext"],
+ footer: { js: "//# sourceURL=VencordRenderer" },
+ globalName: "Vencord",
+ external: ["plugins", "git-hash"],
+ plugins: [
+ globPlugins,
+ gitHashPlugin
+ ],
+ sourcemap: "inline",
+ minify: true,
+ define: {
+ IS_WEB: "false"
+ }
+ }),
+]).catch(err => {
+ console.error("Build failed");
+ console.error(err.message);
+ // make ci fail
+ if (!watch)
+ process.exitCode = 1;
+});
diff --git a/scripts/build/buildWeb.mjs b/scripts/build/buildWeb.mjs
new file mode 100644
index 00000000..dd8cb5df
--- /dev/null
+++ b/scripts/build/buildWeb.mjs
@@ -0,0 +1,61 @@
+// TODO: Modularise the plugins since both build scripts use them
+
+import { createWriteStream, readFileSync } from "fs";
+import yazl from "yazl";
+import esbuild from "esbuild";
+// wtf is this assert syntax
+import PackageJSON from "../../package.json" assert { type: "json" };
+import { commonOpts, gitHashPlugin, globPlugins } from "./common.mjs";
+
+/**
+ * @type {esbuild.BuildOptions}
+ */
+const commonOptions = {
+ ...commonOpts,
+ entryPoints: ["browser/Vencord.ts"],
+ globalName: "Vencord",
+ format: "iife",
+ minify: true,
+ sourcemap: false,
+ external: ["plugins", "git-hash"],
+ plugins: [
+ globPlugins,
+ gitHashPlugin
+ ],
+ target: ["esnext"],
+ define: {
+ IS_WEB: "true"
+ }
+};
+
+await Promise.all(
+ [
+ esbuild.build({
+ ...commonOptions,
+ outfile: "dist/browser.js",
+ footer: { js: "//# sourceURL=VencordWeb" },
+ }),
+ esbuild.build({
+ ...commonOptions,
+ outfile: "dist/Vencord.user.js",
+ banner: {
+ js: readFileSync("browser/userscript.meta.js", "utf-8").replace("%version%", PackageJSON.version)
+ },
+ footer: {
+ // UserScripts get wrapped in an iife, so define Vencord prop on window that returns our local
+ js: "Object.defineProperty(window,'Vencord',{get:()=>Vencord});"
+ },
+ })
+ ]
+);
+
+const zip = new yazl.ZipFile();
+zip.outputStream.pipe(createWriteStream("dist/extension.zip")).on("close", () => {
+ console.info("Extension written to dist/extension.zip");
+});
+
+zip.addFile("dist/browser.js", "dist/Vencord.js");
+["background.js", "content.js", "manifest.json"].forEach(f => {
+ zip.addFile(`browser/${f}`, `${f}`);
+});
+zip.end();
diff --git a/scripts/build/common.mjs b/scripts/build/common.mjs
new file mode 100644
index 00000000..d9b2878d
--- /dev/null
+++ b/scripts/build/common.mjs
@@ -0,0 +1,80 @@
+import { execSync } from "child_process";
+import esbuild from "esbuild";
+import { readdir } from "fs/promises";
+
+/**
+ * @type {esbuild.WatchMode|false}
+ */
+export const watch = process.argv.includes("--watch");
+
+/**
+ * @type {esbuild.BuildOptions}
+ */
+export const commonOpts = {
+ logLevel: "info",
+ bundle: true,
+ watch
+};
+
+// https://github.com/evanw/esbuild/issues/619#issuecomment-751995294
+/**
+ * @type {esbuild.Plugin}
+ */
+export const makeAllPackagesExternalPlugin = {
+ name: "make-all-packages-external",
+ setup(build) {
+ let filter = /^[^.\/]|^\.[^.\/]|^\.\.[^\/]/; // Must not start with "/" or "./" or "../"
+ build.onResolve({ filter }, args => ({ path: args.path, external: true }));
+ },
+};
+
+/**
+ * @type {esbuild.Plugin}
+ */
+export const globPlugins = {
+ name: "glob-plugins",
+ setup: build => {
+ build.onResolve({ filter: /^plugins$/ }, args => {
+ return {
+ namespace: "import-plugins",
+ path: args.path
+ };
+ });
+
+ build.onLoad({ filter: /^plugins$/, namespace: "import-plugins" }, async () => {
+ const files = await readdir("./src/plugins");
+ let code = "";
+ let plugins = "\n";
+ for (let i = 0; i < files.length; i++) {
+ if (files[i] === "index.ts") {
+ continue;
+ }
+ const mod = `p${i}`;
+ code += `import ${mod} from "./${files[i].replace(/.tsx?$/, "")}";\n`;
+ plugins += `[${mod}.name]:${mod},\n`;
+ }
+ code += `export default {${plugins}};`;
+ return {
+ contents: code,
+ resolveDir: "./src/plugins"
+ };
+ });
+ }
+};
+
+const gitHash = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
+/**
+ * @type {esbuild.Plugin}
+ */
+export const gitHashPlugin = {
+ name: "git-hash-plugin",
+ setup: build => {
+ const filter = /^git-hash$/;
+ build.onResolve({ filter }, args => ({
+ namespace: "git-hash", path: args.path
+ }));
+ build.onLoad({ filter, namespace: "git-hash" }, () => ({
+ contents: `export default "${gitHash}"`
+ }));
+ }
+};
diff --git a/src/Vencord.ts b/src/Vencord.ts
index 48006210..659d032b 100644
--- a/src/Vencord.ts
+++ b/src/Vencord.ts
@@ -17,12 +17,6 @@ import { checkForUpdates, UpdateLogger } from "./utils/updater";
import { onceReady } from "./webpack";
import { Router } from "./webpack/common";
-Object.defineProperty(window, "IS_WEB", {
- get: () => !window.DiscordNative,
- configurable: true,
- enumerable: true
-});
-
export let Components: any;
async function init() {
@@ -30,21 +24,23 @@ async function init() {
startAllPlugins();
Components = await import("./components");
- try {
- const isOutdated = await checkForUpdates();
- if (isOutdated && Settings.notifyAboutUpdates)
- setTimeout(() => {
- showNotice(
- "A Vencord update is available!",
- "View Update",
- () => {
- popNotice();
- Router.open("VencordUpdater");
- }
- );
- }, 10000);
- } catch (err) {
- UpdateLogger.error("Failed to check for updates", err);
+ if (!IS_WEB) {
+ try {
+ const isOutdated = await checkForUpdates();
+ if (isOutdated && Settings.notifyAboutUpdates)
+ setTimeout(() => {
+ showNotice(
+ "A Vencord update is available!",
+ "View Update",
+ () => {
+ popNotice();
+ Router.open("VencordUpdater");
+ }
+ );
+ }, 10000);
+ } catch (err) {
+ UpdateLogger.error("Failed to check for updates", err);
+ }
}
}
diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx
index 6c5b5014..2a2cc5d8 100644
--- a/src/components/Settings.tsx
+++ b/src/components/Settings.tsx
@@ -72,7 +72,7 @@ export default ErrorBoundary.wrap(function Settings() {
SettingsDir: {settingsDir}
- {!IS_WEB &&
+ {!IS_WEB &&
}
+
- Settings
settings.useQuickCss = v}
diff --git a/src/components/Updater.tsx b/src/components/Updater.tsx
index 31060b48..153d5e56 100644
--- a/src/components/Updater.tsx
+++ b/src/components/Updater.tsx
@@ -158,7 +158,7 @@ function Newer(props: CommonProps) {
);
}
-export default ErrorBoundary.wrap(function Updater() {
+function Updater() {
const [repo, err, repoPending] = useAwaiter(getRepo, "Loading...");
React.useEffect(() => {
@@ -188,4 +188,6 @@ export default ErrorBoundary.wrap(function Updater() {
{isNewer ? : }
);
-});
+}
+
+export default IS_WEB ? null : ErrorBoundary.wrap(Updater);
diff --git a/src/globals.d.ts b/src/globals.d.ts
index 4320e1c6..72b0b282 100644
--- a/src/globals.d.ts
+++ b/src/globals.d.ts
@@ -1,10 +1,30 @@
declare global {
+ /**
+ * This exists only at build time, so references to it in patches should insert it
+ * via String interpolation OR use different replacement code based on this
+ * but NEVER refrence it inside the patched code
+ *
+ * @example
+ * // BAD
+ * replace: "IS_WEB?foo:bar"
+ * // GOOD
+ * replace: IS_WEB ? "foo" : "bar"
+ * // also good
+ * replace: `${IS_WEB}?foo:bar`
+ */
export var IS_WEB: boolean;
export var VencordNative: typeof import("./VencordNative").default;
export var Vencord: typeof import("./Vencord");
export var appSettings: {
set(setting: string, v: any): void;
};
+ /**
+ * Only available when running in Electron, undefined on web.
+ * Thus, avoid using this or only use it inside an {@link IS_WEB} guard.
+ *
+ * If you really must use it, mark your plugin as Desktop App only via
+ * `target: "DESKTOP"`
+ */
export var DiscordNative: any;
interface Window {
diff --git a/src/plugins/clickableRoleDot.ts b/src/plugins/clickableRoleDot.ts
index 61e6b289..28a511d6 100644
--- a/src/plugins/clickableRoleDot.ts
+++ b/src/plugins/clickableRoleDot.ts
@@ -18,7 +18,16 @@ export default definePlugin({
],
copyToClipBoard(color: string) {
- window.DiscordNative.clipboard.copy(color);
+ if (IS_WEB) {
+ navigator.clipboard.writeText(color)
+ .then(() => this.notifySuccess);
+ } else {
+ DiscordNative.clipboard.copy(color);
+ this.notifySuccess();
+ }
+ },
+
+ notifySuccess() {
Toasts.show({
message: "Copied to Clipboard!",
type: Toasts.Type.SUCCESS,
diff --git a/src/plugins/noRPC.ts b/src/plugins/noRPC.ts
index 95dcf04e..f1094fd9 100644
--- a/src/plugins/noRPC.ts
+++ b/src/plugins/noRPC.ts
@@ -5,6 +5,7 @@ export default definePlugin({
name: "No RPC",
description: "Disables Discord's RPC server.",
authors: [Devs.Cyn],
+ target: "DESKTOP",
patches: [
{
find: '.ensureModule("discord_rpc")',
diff --git a/src/plugins/noSystemBadge.ts b/src/plugins/noSystemBadge.ts
index 25f873b6..7b687c7b 100644
--- a/src/plugins/noSystemBadge.ts
+++ b/src/plugins/noSystemBadge.ts
@@ -5,6 +5,7 @@ export default definePlugin({
name: "NoSystemBadge",
description: "Disables the taskbar and system tray unread count badge.",
authors: [Devs.rushii],
+ target: "DESKTOP",
patches: [
{
find: "setSystemTrayApplications:function",
diff --git a/src/plugins/settings.ts b/src/plugins/settings.ts
index afd3fd30..d26688a6 100644
--- a/src/plugins/settings.ts
+++ b/src/plugins/settings.ts
@@ -28,12 +28,15 @@ export default definePlugin({
find: "Messages.ACTIVITY_SETTINGS",
replacement: {
match: /\{section:(.{1,2})\.ID\.HEADER,\s*label:(.{1,2})\..{1,2}\.Messages\.ACTIVITY_SETTINGS\}/,
- replace: (m, mod) =>
- `{section:${mod}.ID.HEADER,label:"Vencord"},` +
- '{section:"VencordSetting",label:"Vencord",element:Vencord.Components.Settings},' +
- '{section:"VencordUpdater",label:"Updater",element:Vencord.Components.Updater,predicate:()=>!IS_WEB},' +
- `{section:${mod}.ID.DIVIDER},${m}`
-
+ replace: (m, mod) => {
+ const updater = !IS_WEB ? '{section:"VencordUpdater",label:"Updater",element:Vencord.Components.Updater},' : "";
+ return (
+ `{section:${mod}.ID.HEADER,label:"Vencord"},` +
+ '{section:"VencordSetting",label:"Vencord",element:Vencord.Components.Settings},' +
+ updater +
+ `{section:${mod}.ID.DIVIDER},${m}`
+ );
+ }
}
}]
});