// src/index.ts import { resolve as resolve2 } from "path"; import _debug2, { log } from "debug"; import { createUtils } from "@windicss/plugin-utils"; // ../shared/virtual-module.ts import { existsSync, promises as fs } from "fs"; var MODULE_IDS = [/^virtual:windi(.*?)\.css/, /^windi(.*?)\.css/]; var MODULE_ID_VIRTUAL_PREFIX = "/@windicss/windi"; var MODULE_ID_VIRTUAL = /\/\@windicss\/windi-?(.*?)\.css/; var MODULE_ID_VIRTUAL_MODULES = [ `${MODULE_ID_VIRTUAL_PREFIX}.css`, `${MODULE_ID_VIRTUAL_PREFIX}-base.css`, `${MODULE_ID_VIRTUAL_PREFIX}-utilities.css`, `${MODULE_ID_VIRTUAL_PREFIX}-components.css` ]; function createVirtualModuleLoader(ctx) { return { resolveId(id) { if (id.startsWith(MODULE_ID_VIRTUAL_PREFIX)) return id; for (const idRegex of MODULE_IDS) { const match = id.match(idRegex); if (match) return `${MODULE_ID_VIRTUAL_PREFIX}${match[1]}.css`; } return null; }, async load(id) { const match = id.match(MODULE_ID_VIRTUAL); if (match) { await ctx.utils.scan(); await ctx.utils.waitLocks(); ctx.utils.files.map((id2) => this.addWatchFile(id2)); const layer = match[1] || void 0; const css = await ctx.utils.generateCSS(layer); return css; } }, async watchChange(id, change) { if (change.event === "delete" || !existsSync(id)) return; if (!ctx.utils.isDetectTarget(id)) return; ctx.utils.lock(async () => { const content = await fs.readFile(id, "utf-8"); await ctx.utils.extractFile(content, id, true); }); } }; } // src/devtools.ts import fs2 from "fs"; import { dirname, resolve } from "path"; import { fileURLToPath } from "url"; import _debug from "debug"; // src/constants.ts var NAME = "vite-plugin-windicss"; // src/modules.ts function getChangedModuleNames(utils) { if (utils.hasPending) utils.buildPendingStyles(); const moduleNames = [ `${MODULE_ID_VIRTUAL_PREFIX}.css` ]; Object.entries(utils.layersMeta).forEach(([name, meta]) => { if (meta.cssCache == null) moduleNames.push(`${MODULE_ID_VIRTUAL_PREFIX}-${name}.css`); }); return moduleNames; } function getCssModules(server, names = MODULE_ID_VIRTUAL_MODULES) { return names.map((name) => server.moduleGraph.getModuleById(name)).filter(Boolean); } function invalidateCssModules(server, modules = getCssModules(server)) { return modules.forEach((m) => server.moduleGraph.invalidateModule(m)); } function sendHmrReload(server, modules = getCssModules(server)) { const timestamp = +Date.now(); server.ws.send({ type: "update", updates: modules.map((m) => ({ acceptedPath: m.id || m.file, path: m.id || m.file, timestamp, type: "js-update" })) }); } function reloadChangedCssModules(server, utils) { const cssModules = getCssModules(server, getChangedModuleNames(utils)); invalidateCssModules(server, cssModules); sendHmrReload(server, cssModules); return cssModules; } // src/devtools.ts var _dirname = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url)); var debug = { devtools: _debug(`${NAME}:devtools`) }; var DEVTOOLS_MODULE_ID = "virtual:windi-devtools"; var MOCK_CLASSES_MODULE_ID = "virtual:windi-mock-classes"; var MOCK_CLASSES_PATH = "/@windicss/mock-classes"; var DEVTOOLS_PATH = "/@windicss/devtools"; var MODULES_MAP = { [DEVTOOLS_MODULE_ID]: DEVTOOLS_PATH, [MOCK_CLASSES_MODULE_ID]: MOCK_CLASSES_PATH }; var POST_PATH = "/@windicss-devtools-update"; function getBodyJson(req) { return new Promise((resolve3, reject) => { let body = ""; req.on("data", (chunk) => body += chunk); req.on("error", reject); req.on("end", () => { try { resolve3(JSON.parse(body) || {}); } catch (e) { reject(e); } }); }); } function createDevtoolsPlugin(ctx) { let config; let server; let clientCode = ""; function updateCSS() { if (!server) return; const names = getChangedModuleNames(ctx.utils); const modules = getCssModules(server, names); invalidateCssModules(server, modules); sendHmrReload(server, modules); } function toClass(name) { return `.${ctx.utils.processor.e(name)}{}`; } function getMockClassesInjector() { const completions = ctx.utils.getCompletions(); const comment = "/* Windi CSS mock class names for devtools auto-completion */\n"; const css = [ ...completions.color, ...completions.static ].map(toClass).join(""); return ` const style = document.createElement('style') style.setAttribute('type', 'text/css') style.innerHTML = ${JSON.stringify(comment + css)} document.head.prepend(style) `; } return [ { name: `${NAME}:devtools`, configResolved(_config) { config = _config; }, configureServer(_server) { server = _server; server.middlewares.use(async (req, res, next) => { if (req.url !== POST_PATH) return next(); try { const data = await getBodyJson(req); const type = data?.type; debug.devtools(data); let changed = false; switch (type) { case "add-classes": changed = ctx.utils.addClasses(data.data || []); } if (changed) updateCSS(); res.statusCode = 200; } catch (e) { console.error(e); res.statusCode = 500; } res.end(); }); }, resolveId(id) { return MODULES_MAP[id]; }, async load(id, options) { if (options?.ssr && [DEVTOOLS_PATH, MOCK_CLASSES_PATH].includes(id)) return ""; if (id === DEVTOOLS_PATH) { if (!clientCode) { clientCode = [ await fs2.promises.readFile(resolve(_dirname, "client.mjs"), "utf-8"), `import('${MOCK_CLASSES_MODULE_ID}')` ].join("\n").replace("__POST_PATH__", (config.server?.origin ?? "") + POST_PATH); } return config.command === "build" ? "" : clientCode; } else if (id === MOCK_CLASSES_PATH) { return getMockClassesInjector(); } } } ]; } // src/index.ts export * from "@windicss/plugin-utils"; var debug2 = { hmr: _debug2(`${NAME}:hmr`), css: _debug2(`${NAME}:transform:css`), group: _debug2(`${NAME}:transform:group`), alias: _debug2(`${NAME}:transform:alias`), memory: _debug2(`${NAME}:memory`) }; function VitePluginWindicss(userOptions = {}, utilsOptions = {}) { let utils; let server; let viteConfig; const plugins = []; plugins.push({ name: `${NAME}:alias`, enforce: "pre", configResolved(_config) { viteConfig = _config; }, async transform(code, id) { await utils.ensureInit(); if (!utils.isDetectTarget(id)) return; debug2.alias(id); return utils.transformAlias(code, !!viteConfig.build.sourcemap); } }); if (userOptions.transformGroups !== false) { plugins.push({ name: `${NAME}:groups`, enforce: "pre", async transform(code, id) { await utils.ensureInit(); if (!utils.isDetectTarget(id)) return; debug2.group(id); return utils.transformGroups(code, !!viteConfig.build.sourcemap); } }); } plugins.push({ name: NAME, get api() { return utils; } }); plugins.push({ name: `${NAME}:entry`, enforce: "post", configureServer(_server) { server = _server; }, async configResolved(_config) { utils = utilsOptions.utils ?? createUtils(userOptions, { name: NAME, root: _config.root, onConfigurationError(e) { if (_config.command === "build") { throw e; } else { console.error(`[${NAME}] Error on loading configurations`); console.error(e); } }, ...utilsOptions }); await utils.ensureInit(); }, ...createVirtualModuleLoader({ get utils() { return utils; } }) }); let _cssReloadTask; function reloadCssModules(server2) { clearTimeout(_cssReloadTask); _cssReloadTask = setTimeout(() => { reloadChangedCssModules(server2, utils); }, 1); } plugins.push({ name: `${NAME}:hmr`, apply: "serve", enforce: "pre", async configureServer(_server) { server = _server; await utils.ensureInit(); if (utils.configFilePath) server.watcher.add(utils.configFilePath); const supportsGlobs = server.config.server.watch?.disableGlobbing === false; server.watcher.add(supportsGlobs ? utils.globs : await utils.getFiles()); }, async handleHotUpdate({ server: server2, file, read }) { if (resolve2(file) === utils.configFilePath) { debug2.hmr(`config file changed: ${file}`); await utils.init(); setTimeout(() => { log("configure file changed, reloading"); server2.ws.send({ type: "full-reload" }); }, 0); return getCssModules(server2); } if (!utils.isDetectTarget(file)) return; utils.extractFile(await read(), file, true).then((changed) => { if (changed) { debug2.hmr(`refreshed by ${file}`); reloadCssModules(server2); } }); } }); const { transformCSS: transformCSSOptions = true } = userOptions; const transformCSS = (code, id) => utils.transformCSS(code, id, { onLayerUpdated() { if (server) reloadCssModules(server); } }); if (transformCSSOptions === true) { plugins.push({ name: `${NAME}:css`, async transform(code, id) { await utils.ensureInit(); if (!utils.isCssTransformTarget(id) || id.startsWith(MODULE_ID_VIRTUAL_PREFIX)) return; debug2.css(id); code = transformCSS(code, id); if (viteConfig.build.sourcemap) { return { code: transformCSS(code, id), map: { mappings: "" } }; } else { return code; } } }); } else if (typeof transformCSSOptions === "string") { plugins.push({ name: `${NAME}:css`, enforce: transformCSSOptions, transform(code, id) { if (!utils.isCssTransformTarget(id) || id.startsWith(MODULE_ID_VIRTUAL_PREFIX)) return; debug2.css(id, transformCSSOptions); code = transformCSS(code, id); if (viteConfig.build.sourcemap) { return { code: transformCSS(code, id), map: { mappings: "" } }; } else { return code; } } }); } plugins.push({ name: `${NAME}:css:svelte`, api: { sveltePreprocess: { style({ content, id }) { return { code: transformCSS(content, id) }; } } } }); plugins.push(...createDevtoolsPlugin({ get utils() { return utils; } })); return plugins; } var src_default = VitePluginWindicss; export { src_default as default };