What breaks over time, how to tell, and how to fix it.
Everything in this plugin is stable except the channel header patch. Discord ships a new client build constantly, and any of them can move or reshape the code the patch targets.
When that happens:
- The plugin still loads
- The context menu (right-click a channel → View Media) still works
- The chat bar button still works
- The header button silently disappears
Nothing crashes. That graceful degradation is the reason those other entry points exist.
DevTools (Cmd+Opt+I) → Console, filter for Vencord:
| Message | Meaning |
|---|---|
Patch by MediaTab (name:"Search",renderLoader:) errored |
The find matched but the regex didn't |
Patch by MediaTab … found no module |
The find string is gone |
| nothing about MediaTab | It's not the patch — check the plugin is enabled, and that you reloaded with Cmd+R |
node tests/fetch-discord-bundle.mjs
node tests/run.mjsThe five patch tests tell you exactly which assumption broke:
| Failing test | What changed |
|---|---|
| find string is unique | The string vanished, or now appears in several modules |
| match regex hits exactly once | The surrounding code was restructured |
| captures channelId and guildId | The props destructuring changed |
| patched module is valid JavaScript | The replacement no longer fits the syntax |
| replaces the Fragment and keeps order | The children array was reshaped |
cd tests/.cache
node -e '
const s = require("fs").readFileSync("web.js", "utf8");
// the header bar is the module that composes a toolbar and a search box
for (const needle of ["mobileToolbar:", "hideSearch:", "renderHeaderToolbar"]) {
const i = s.indexOf(needle);
console.log("\n=== " + needle + " @ " + i + " ===");
if (i > 0) console.log(s.slice(i - 800, i + 800));
}
'mobileToolbar: and hideSearch: are both good anchors — they were unique in
the whole bundle at the time of writing, and they're semantic names rather than
minified ones.
Check uniqueness before committing to it:
node -e '
const s = require("fs").readFileSync("tests/.cache/web.js", "utf8");
for (const c of [`name:"Search",renderLoader:`, "mobileToolbar:", "hideSearch:"])
console.log(c, "→", s.split(c).length - 1, "hits");
'You want exactly 1.
Edit plugin/mediaTab/headerPatch.ts — that file exists so this is the only
place to change. Then:
node tests/run.mjsIterate until all five patch tests pass. You're checking the regex against the real code, so when the tests go green the patch genuinely works.
./scripts/build.sh
# then Cmd+R in DiscordIf Discord restructures so far that there's no [toolbar, searchBar] array to
inject into, options in order of preference:
- Find the new toolbar composition point. There will still be somewhere the header icons are assembled. Search for the module that renders the pin or member-list icon.
- Fall back to the titlebar.
VencordToolboxpatchesfind: '?"BACK_FORWARD_NAVIGATION":'withmatch: /(trailing:.{0,50}?)\i\.Fragment,(?=\{children:\[)/. That was verified working against the same bundle this plugin was built on, and puts the button in the top-right of the window rather than the channel header. - Drop the header button. Set
headerButtonto off by default and lean on the context menu and chat bar button, both of which use official APIs.
Stable for years, but if searching starts failing:
node -e '
const s = require("fs").readFileSync("tests/.cache/web.js", "utf8");
const i = s.indexOf("messages/search");
console.log(s.slice(i - 600, i + 400));
'That prints Discord's own endpoint table. Compare against DISCORD-SEARCH-API.md.
To re-check the parameter names Discord's client uses, search the bundle for
attachment_extension — the surrounding module maps every search filter to its
queryKey.
To re-check what Discord's own media tab sends, search for include_nsfw; the
tab → filter mapping ({1:{has:["image","video"]}, …}) is nearby.
Vencord occasionally renames or deprecates exports. pnpm testTsc catches all of
it, since Vencord ships types for everything this plugin imports.
Known migration in progress: the ModalRoot / ModalHeader / ModalContent
components in @utils/modal are deprecated in favour of the single Modal
component from @webpack/common. This plugin already uses the new one.
./scripts/setup.sh # pulls Vencord, reinstalls deps, syncs, rebuildsIf the build then fails, it's an API change in Vencord — pnpm testTsc will
point at the line.
Worth running after any Discord or Vencord update:
node tests/fetch-discord-bundle.mjs # refresh the bundle
node tests/run.mjs # 40 tests
cd Vencord && pnpm testTsc && pnpm lint
cd .. && ./scripts/build.shFour commands, under a minute, and it catches everything that's realistically going to break.