branch:
vite-plugin-devtools-json.ts
2149 bytesRaw
import fs from "fs";
import path from "path";
import crypto from "node:crypto";
import type { Plugin } from "vite";

const ENDPOINT = "/.well-known/appspecific/com.chrome.devtools.json";

function generateUUID(): string {
  return crypto.randomUUID();
}

function isValidUUID(uuid: string): boolean {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
    uuid
  );
}

export default function devtoolsJson(
  options: { uuid?: string; projectRoot?: string } = {}
): Plugin {
  return {
    name: "devtools-json",
    enforce: "post",

    configureServer(server) {
      const { config } = server;

      if (!config.env.DEV) return;

      const getOrCreateUUID = () => {
        if (options.uuid) return options.uuid;

        let { cacheDir } = config;
        if (!path.isAbsolute(cacheDir)) {
          let { root } = config;
          if (!path.isAbsolute(root)) root = path.resolve(process.cwd(), root);
          cacheDir = path.resolve(root, cacheDir);
        }
        const uuidPath = path.resolve(cacheDir, "uuid.json");
        if (fs.existsSync(uuidPath)) {
          const uuid = fs.readFileSync(uuidPath, { encoding: "utf-8" });
          if (isValidUUID(uuid)) return uuid;
        }
        if (!fs.existsSync(cacheDir)) {
          fs.mkdirSync(cacheDir, { recursive: true });
        }
        const uuid = generateUUID();
        fs.writeFileSync(uuidPath, uuid, { encoding: "utf-8" });
        return uuid;
      };

      server.middlewares.use(ENDPOINT, async (_req, res) => {
        let root = options.projectRoot
          ? path.resolve(options.projectRoot)
          : config.root;
        if (!path.isAbsolute(root)) {
          root = path.resolve(process.cwd(), root);
        }

        res.setHeader("Content-Type", "application/json");
        res.end(
          JSON.stringify(
            { workspace: { root, uuid: getOrCreateUUID() } },
            null,
            2
          )
        );
      });
    },

    configurePreviewServer(server) {
      server.middlewares.use(ENDPOINT, async (_req, res) => {
        res.writeHead(404);
        res.end();
      });
    }
  };
}