feat: sidebar customisaitons and settings fixes

This commit is contained in:
2026-07-26 11:32:04 +09:30
parent 88926aaee7
commit c5ab69ba82
19 changed files with 1479 additions and 222 deletions
+53
View File
@@ -0,0 +1,53 @@
import type { Plugin, ViteDevServer } from "vite";
/**
* CRXJS + Vite 6 often corrupt content-script ESM bindings after HMR /
* `[crx] runtime reload` — modules load but named/`default` exports are missing
* until the dev server is restarted.
*
* Prefer invalidating the module graph + a full page reload over partial HMR.
*/
export default function stabilizeCrxDevHmr(): Plugin {
let reloadTimer: ReturnType<typeof setTimeout> | null = null;
const scheduleFullReload = (s: ViteDevServer) => {
if (reloadTimer) clearTimeout(reloadTimer);
// Debounce cascading invalidations (e.g. many files in one save).
reloadTimer = setTimeout(() => {
reloadTimer = null;
s.ws.send({ type: "full-reload", path: "*" });
}, 50);
};
return {
name: "stabilize-crx-dev-hmr",
apply: "serve",
enforce: "pre",
configureServer(s) {
s.ws.on("bsplus:reset-module-graph", () => {
s.moduleGraph.invalidateAll();
scheduleFullReload(s);
});
},
handleHotUpdate({ file, modules, server: viteServer }) {
if (!file.replace(/\\/g, "/").includes("/src/")) return;
if (file.includes("node_modules")) return;
const seen = new Set(modules);
const queue = [...modules];
while (queue.length) {
const mod = queue.pop()!;
viteServer.moduleGraph.invalidateModule(mod);
for (const importer of mod.importers) {
if (seen.has(importer)) continue;
seen.add(importer);
queue.push(importer);
}
}
scheduleFullReload(viteServer);
// Skip Vite's partial HMR for these modules — it is what leaves exports empty.
return [];
},
};
}
+7 -47
View File
@@ -1,55 +1,15 @@
import fs from "fs";
import type { Plugin } from "vite";
/**
* Creates a Vite plugin designed to improve the reliability of Hot Module Replacement (HMR)
* for global CSS files.
* Previously touched CSS mtimes on JS HMR to force style refresh.
* That raced with CRXJS runtime reload and corrupted Vite's module graph
* (missing named/`default` exports until `npm run dev` was restarted).
*
* When a JavaScript/TypeScript module that imports a CSS file is updated, Vite's HMR
* might not always reliably update the styles injected by that global CSS. This plugin
* attempts to mitigate this by listening for hot updates. If an updated module
* has direct importers that are CSS files (e.g., a JS file imports a global CSS file),
* this plugin will "touch" those CSS files by updating their access and modification
* timestamps using `fs.utimesSync`. This action can help signal to Vite or the browser
* that the CSS file has changed, potentially triggering a more reliable style reload.
*
* @returns {import('vite').Plugin} A Vite plugin object configured with `name` and `handleHotUpdate` hooks.
* Style updates are now covered by `stabilizeCrxDevHmr` full reloads.
*/
export default function touchGlobalCSSPlugin() {
export default function touchGlobalCSSPlugin(): Plugin {
return {
/**
* The unique name of this Vite plugin.
* This name is used by Vite for identification purposes and will appear in logs.
* @type {string}
*/
name: "touch-global-css",
/**
* A Vite hook that is called when a module is hot-updated.
* This function inspects the importers of the updated module. If any of these
* importers are CSS files, their filesystem timestamps are updated ("touched").
*
* @param {object} context The context object provided by Vite's `handleHotUpdate` hook.
* @param {Array<import('vite').ModuleNode>} context.modules An array of `ModuleNode` instances that have been updated.
* This plugin specifically accesses `modules[0]._clientModule.importers`
* to find CSS files that import the updated module.
*/
handleHotUpdate({ modules }) {
// It's assumed `modules[0]` is the primary updated module of interest.
// `_clientModule` and `importers` might be internal or less stable Vite APIs.
const importers = modules[0]?._clientModule?.importers;
if (importers) {
importers.forEach((importer) => {
// Check if the importer is a CSS file
if (importer.file && importer.file.includes(".css")) {
console.log("[touch-global-css] touching", importer.file);
try {
// Update the access and modification times of the CSS file to the current time
fs.utimesSync(importer.file, new Date(), new Date());
} catch (err) {
console.error(`[touch-global-css] Error touching file ${importer.file}:`, err);
}
}
});
}
},
apply: "serve",
};
}