diff options
author | Vendicated <vendicated@riseup.net> | 2022-10-04 00:52:42 +0200 |
---|---|---|
committer | Vendicated <vendicated@riseup.net> | 2022-10-04 00:52:50 +0200 |
commit | cc257533148419b1c94a1cd257e756d2688a403c (patch) | |
tree | 84affcf23ec84304efcb381626ac4d995db0ec95 | |
parent | a9eae106c7cc6cccbb5c3f030130d3c7b6461c3e (diff) | |
download | Vencord-cc257533148419b1c94a1cd257e756d2688a403c.tar.gz Vencord-cc257533148419b1c94a1cd257e756d2688a403c.tar.bz2 Vencord-cc257533148419b1c94a1cd257e756d2688a403c.zip |
feat: Experimental browser support
-rw-r--r-- | browser/Vencord.ts | 3 | ||||
-rw-r--r-- | browser/VencordNativeStub.ts | 39 | ||||
-rw-r--r-- | browser/background.js | 1 | ||||
-rw-r--r-- | browser/content.js | 10 | ||||
-rw-r--r-- | browser/manifest.json | 30 | ||||
-rwxr-xr-x | build.mjs | 3 | ||||
-rw-r--r-- | buildWeb.mjs | 86 | ||||
-rw-r--r-- | package.json | 5 | ||||
-rw-r--r-- | pnpm-lock.yaml | 45 | ||||
-rw-r--r-- | src/components/Settings.tsx | 13 | ||||
-rw-r--r-- | src/plugins/settings.ts | 12 | ||||
-rw-r--r-- | src/utils/isWeb.ts | 1 | ||||
-rw-r--r-- | src/utils/types.ts | 4 | ||||
-rw-r--r-- | src/webpack/patchWebpack.ts | 1 |
14 files changed, 212 insertions, 41 deletions
diff --git a/browser/Vencord.ts b/browser/Vencord.ts new file mode 100644 index 0000000..2d4315d --- /dev/null +++ b/browser/Vencord.ts @@ -0,0 +1,3 @@ +import "./VencordNativeStub"; + +export * from "../src/Vencord"; diff --git a/browser/VencordNativeStub.ts b/browser/VencordNativeStub.ts new file mode 100644 index 0000000..bdcae4e --- /dev/null +++ b/browser/VencordNativeStub.ts @@ -0,0 +1,39 @@ +import IpcEvents from "../src/utils/IpcEvents"; + +// Discord deletes this so need to store in variable +var localStorage = window.localStorage; + +const handlers = { + [IpcEvents.GET_REPO]: () => "", // TODO + [IpcEvents.GET_SETTINGS_DIR]: () => "LocalStorage", + + [IpcEvents.GET_QUICK_CSS]: () => localStorage.getItem("VencordQuickCss"), + [IpcEvents.GET_SETTINGS]: () => localStorage.getItem("VencordSettings") || "{}", + [IpcEvents.SET_SETTINGS]: (s: string) => localStorage.setItem("VencordSettings", s), + + [IpcEvents.GET_UPDATES]: () => ({ ok: true, value: [] }), + + [IpcEvents.OPEN_EXTERNAL]: (url: string) => open(url, "_blank"), + [IpcEvents.OPEN_QUICKCSS]: () => { } // TODO +}; + +function onEvent(event: string, ...args: any[]) { + const handler = handlers[event]; + if (!handler) throw new Error(`Event ${event} not implemented.`); + return handler(...args); +} + +window.VencordNative = { + getVersions: () => ({}), + ipc: { + send: (event: string, ...args: any[]) => void onEvent(event, ...args), + sendSync: onEvent, + on(event: string, listener: () => {}) { + // TODO quickCss + }, + off(event: string, listener: () => {}) { + // not used for now + }, + invoke: (event: string, ...args: any[]) => Promise.resolve(onEvent(event, ...args)) + }, +}; diff --git a/browser/background.js b/browser/background.js new file mode 100644 index 0000000..872134b --- /dev/null +++ b/browser/background.js @@ -0,0 +1 @@ +// could use this in the future diff --git a/browser/content.js b/browser/content.js new file mode 100644 index 0000000..5922e8f --- /dev/null +++ b/browser/content.js @@ -0,0 +1,10 @@ +// This is just the bootstrap script + +if (typeof browser === "undefined") { + var browser = chrome; +} + +var script = document.createElement("script"); +script.src = browser.runtime.getURL("dist/Vencord.js"); +// documentElement because we load before body/head are ready +document.documentElement.appendChild(script); diff --git a/browser/manifest.json b/browser/manifest.json new file mode 100644 index 0000000..c01bc44 --- /dev/null +++ b/browser/manifest.json @@ -0,0 +1,30 @@ +{ + "manifest_version": 2, + "name": "Vencord Web", + "description": "Yeee", + "version": "1.0.0", + "author": "Vendicated", + "homepage_url": "https://github.com/Vendicated/Vencord", + "background": { + "scripts": [ + "background.js" + ] + }, + "content_scripts": [ + { + "run_at": "document_start", + "matches": [ + "*://*.discord.com/*" + ], + "js": [ + "content.js" + ] + } + ], + "permissions": [ + "*://*.discord.com/*" + ], + "web_accessible_resources": [ + "dist/Vencord.js" + ] +} @@ -2,7 +2,6 @@ import { execSync } from "child_process"; import esbuild from "esbuild"; import { readdirSync } from "fs"; -import { performance } from "perf_hooks"; /** * @type {esbuild.WatchMode|false} @@ -115,7 +114,7 @@ await Promise.all([ sourcemap: false, watch, minify: true, - }) + }), ]).catch(err => { console.error("Build failed"); console.error(err.message); diff --git a/buildWeb.mjs b/buildWeb.mjs new file mode 100644 index 0000000..9031d14 --- /dev/null +++ b/buildWeb.mjs @@ -0,0 +1,86 @@ +// TODO: Modularise these plugins since both build scripts use them + +import { execSync } from "child_process"; +import { createWriteStream, readdirSync } from "fs"; +import yazl from "yazl"; +import esbuild from "esbuild"; + +/** + * @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 esbuild.build({ + logLevel: "info", + entryPoints: ["browser/Vencord.ts"], + outfile: "dist/browser.js", + format: "iife", + bundle: true, + globalName: "Vencord", + target: ["esnext"], + footer: { js: "//# sourceURL=VencordWeb" }, + external: ["plugins", "git-hash"], + plugins: [ + globPlugins, + gitHashPlugin + ], + sourcemap: false, + minify: true, +}); + +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 bde4752..39ac699 100644 --- a/package.json +++ b/package.json @@ -2,14 +2,17 @@ "devDependencies": { "@types/node": "^18.7.13", "@types/react": "^18.0.17", + "@types/yazl": "^2.4.2", "electron": "^20.1.0", - "esbuild": "^0.15.5" + "esbuild": "^0.15.5", + "yazl": "^2.5.1" }, "dependencies": { "discord-types": "^1.3.26", "electron-devtools-installer": "^3.2.0" }, "scripts": { + "buildWeb": "node buildWeb.mjs", "build": "node build.mjs", "watch": "node build.mjs --watch" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 304261d..25adfb4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,28 +1,26 @@ -lockfileVersion: 5.3 +lockfileVersion: 5.4 specifiers: - '@types/flux': ^3.1.11 '@types/node': ^18.7.13 '@types/react': ^18.0.17 + '@types/yazl': ^2.4.2 discord-types: ^1.3.26 electron: ^20.1.0 electron-devtools-installer: ^3.2.0 esbuild: ^0.15.5 - jsposed: ^1.0.2 - prettier: ^2.7.1 + yazl: ^2.5.1 dependencies: discord-types: 1.3.26 electron-devtools-installer: 3.2.0 - jsposed: 1.0.2 - prettier: 2.7.1 devDependencies: - '@types/flux': 3.1.11 '@types/node': 18.7.13 '@types/react': 18.0.17 + '@types/yazl': 2.4.2 electron: 20.1.0 esbuild: 0.15.5 + yazl: 2.5.1 packages: @@ -65,17 +63,6 @@ packages: defer-to-connect: 1.1.3 dev: true - /@types/fbemitter/2.0.32: - resolution: {integrity: sha512-Hwq28bBlbmfCgLnNJvjl5ssTrbZCTSblI4vqPpqZrbbEL8vn5l2UivxhlMYfUY7a4SR8UB6RKoLjOZfljqAa6g==} - dev: true - - /@types/flux/3.1.11: - resolution: {integrity: sha512-Aq4UB1ZqAKcPbhB0GpgMw2sntvOh71he9tjz53TLKrI7rw3Y3LxCW5pTYY9IV455hQapm4pmxFjpqlWOs308Yg==} - dependencies: - '@types/fbemitter': 2.0.32 - '@types/react': 18.0.17 - dev: true - /@types/keyv/3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: @@ -126,6 +113,12 @@ packages: dev: true optional: true + /@types/yazl/2.4.2: + resolution: {integrity: sha512-T+9JH8O2guEjXNxqmybzQ92mJUh2oCwDDMSSimZSe1P+pceZiFROZLYmcbqkzV5EUwz6VwcKXCO2S2yUpra6XQ==} + dependencies: + '@types/node': 18.7.13 + dev: true + /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: false @@ -684,10 +677,6 @@ packages: graceful-fs: 4.2.10 dev: true - /jsposed/1.0.2: - resolution: {integrity: sha512-t1vQsxnH65kOBRc4swue6EFm/WmPZwLLJ/84IV3aP93f2F724tHK5HIWwrRUKYYqJb9BJEewBsVh/jHQssJfbw==} - dev: false - /jszip/3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} dependencies: @@ -822,12 +811,6 @@ packages: engines: {node: '>=4'} dev: true - /prettier/2.7.1: - resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: false - /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: false @@ -1001,3 +984,9 @@ packages: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 dev: true + + /yazl/2.5.1: + resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} + dependencies: + buffer-crc32: 0.2.13 + dev: true diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index d4a3dca..4dbb1b2 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -9,6 +9,7 @@ import { startPlugin } from "../plugins"; import { stopPlugin } from '../plugins/index'; import { Flex } from './Flex'; import { ChangeList } from '../utils/ChangeList'; +import { IS_WEB } from '../utils/isWeb'; function showErrorToast(message: string) { Toasts.show({ @@ -72,7 +73,7 @@ export default ErrorBoundary.wrap(function Settings() { SettingsDir: <code style={{ userSelect: 'text', cursor: 'text' }}>{settingsDir}</code> </Forms.FormText> - <Flex className={classes(Margins.marginBottom20)}> + {!IS_WEB && <Flex className={classes(Margins.marginBottom20)}> <Button onClick={() => window.DiscordNative.app.relaunch()} size={Button.Sizes.SMALL} @@ -94,7 +95,7 @@ export default ErrorBoundary.wrap(function Settings() { > Open QuickCSS File </Button> - </Flex> + </Flex>} <Forms.FormDivider /> <Forms.FormTitle tag="h5">Settings</Forms.FormTitle> <Switch @@ -104,20 +105,20 @@ export default ErrorBoundary.wrap(function Settings() { > Use QuickCss </Switch> - <Switch + {!IS_WEB && <Switch value={settings.notifyAboutUpdates} onChange={(v: boolean) => settings.notifyAboutUpdates = v} note="Shows a Toast on StartUp" > Get notified about new Updates - </Switch> - <Switch + </Switch>} + {!IS_WEB && <Switch value={settings.unsafeRequire} onChange={(v: boolean) => settings.unsafeRequire = v} note="Enables VencordNative.require. Useful for testing, very bad for security. Leave this off unless you need it." > Enable Unsafe Require - </Switch> + </Switch>} <Forms.FormDivider /> diff --git a/src/plugins/settings.ts b/src/plugins/settings.ts index 2ed85e6..6927f64 100644 --- a/src/plugins/settings.ts +++ b/src/plugins/settings.ts @@ -1,6 +1,7 @@ import definePlugin from "../utils/types"; import gitHash from "git-hash"; import { Devs } from '../utils/constants'; +import { IS_WEB } from "../utils/isWeb"; export default definePlugin({ name: "Settings", @@ -15,9 +16,12 @@ export default definePlugin({ replace: m => { const idx = m.indexOf("Host") - 1; const template = m.slice(0, idx); - return `${m}, ${template}"Vencord ", "${gitHash}"), " "), ` + - `${template} "Electron ",VencordNative.getVersions().electron)," "), ` + - `${template} "Chrome ",VencordNative.getVersions().chrome)," ")`; + let r = `${m}, ${template}"Vencord ", "${gitHash}${IS_WEB ? " (Web)" : ""}"), " ")`; + if (!IS_WEB) { + r += `,${template} "Electron ",VencordNative.getVersions().electron)," "),`; + r += `${template} "Chrome ",VencordNative.getVersions().chrome)," ")`; + } + return r; } } ] @@ -28,7 +32,7 @@ export default definePlugin({ 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},` + + `{section:"VencordUpdater",label:"Updater",element:Vencord.Components.Updater,predicate:()=>!IS_WEB},` + `{section:${mod}.ID.DIVIDER},${m}` } diff --git a/src/utils/isWeb.ts b/src/utils/isWeb.ts new file mode 100644 index 0000000..4082164 --- /dev/null +++ b/src/utils/isWeb.ts @@ -0,0 +1 @@ +export const IS_WEB = window.IS_WEB = typeof window.DiscordNative === "undefined"; diff --git a/src/utils/types.ts b/src/utils/types.ts index a6b79c5..1c63613 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -33,6 +33,10 @@ interface PluginDef { patches?: Omit<Patch, "plugin">[]; dependencies?: string[], required?: boolean; + /** + * Set this if your plugin only works on Browser or Desktop, not both + */ + target?: "WEB" | "DESKTOP" | "BOTH"; } export type IpcRes<V = any> = { ok: true; value: V; } | { ok: false, error: any; }; diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 469b930..ffd81d5 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -6,6 +6,7 @@ let webpackChunk: any[]; const logger = new Logger("WebpackInterceptor", "#8caaee"); +console.log("prepatch is", window[WEBPACK_CHUNK]); Object.defineProperty(window, WEBPACK_CHUNK, { get: () => webpackChunk, set: (v) => { |