feat: Experimental browser support
This commit is contained in:
		
							parent
							
								
									a9eae106c7
								
							
						
					
					
						commit
						cc25753314
					
				
					 14 changed files with 212 additions and 41 deletions
				
			
		
							
								
								
									
										3
									
								
								browser/Vencord.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								browser/Vencord.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| import "./VencordNativeStub"; | ||||
| 
 | ||||
| export * from "../src/Vencord"; | ||||
							
								
								
									
										39
									
								
								browser/VencordNativeStub.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								browser/VencordNativeStub.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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)) | ||||
|     }, | ||||
| }; | ||||
							
								
								
									
										1
									
								
								browser/background.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								browser/background.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| // could use this in the future
 | ||||
							
								
								
									
										10
									
								
								browser/content.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								browser/content.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
							
								
								
									
										30
									
								
								browser/manifest.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								browser/manifest.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
|  |  | |||
							
								
								
									
										86
									
								
								buildWeb.mjs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								buildWeb.mjs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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(); | ||||
|  | @ -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" | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										45
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										45
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							|  | @ -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 | ||||
|  |  | |||
|  | @ -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 /> | ||||
| 
 | ||||
|  |  | |||
|  | @ -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}` | ||||
| 
 | ||||
|         } | ||||
|  |  | |||
							
								
								
									
										1
									
								
								src/utils/isWeb.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/utils/isWeb.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| export const IS_WEB = window.IS_WEB = typeof window.DiscordNative === "undefined"; | ||||
|  | @ -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; }; | ||||
|  |  | |||
|  | @ -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) => { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue