UNPKG

vite-plugin-symfony

Version:

A Vite plugin to integrate easily Vite in your Symfony application

111 lines (97 loc) 3.61 kB
import { createControllersModule, virtualSymfonyControllersModuleId, parseStimulusRequest, extractStimulusIdentifier, } from "./bridge"; import { join, relative, resolve } from "node:path"; import { Logger, Plugin, ResolvedConfig, UserConfig } from "vite"; import { VitePluginSymfonyStimulusOptions } from "~/types"; import { ControllersFileContent } from "../types"; import { addBootstrapHmrCode, addControllerHmrCode } from "./hmr"; import { getStimulusControllerId } from "../util"; import { isPathIncluded } from "./utils"; import { readFile, stat } from "node:fs/promises"; const stimulusRE = /\?stimulus\b/; const virtualRE = /^virtual:/; const isStimulusRequest = (request: string): boolean => stimulusRE.test(request); const isVirtualRequest = (request: string): boolean => virtualRE.test(request); export default function symfonyStimulus(pluginOptions: VitePluginSymfonyStimulusOptions, logger: Logger) { let viteConfig: ResolvedConfig; let viteCommand: string; let controllersJsonContent: ControllersFileContent | null = null; let controllersFilePath: string; return { name: "symfony-stimulus", config(userConfig, { command }) { viteCommand = command; const extraConfig: UserConfig = { optimizeDeps: { exclude: [...(userConfig?.optimizeDeps?.exclude ?? []), virtualSymfonyControllersModuleId], }, }; return extraConfig; }, async configResolved(config) { viteConfig = config; controllersFilePath = resolve(viteConfig.root, pluginOptions.controllersFilePath); try { await stat(controllersFilePath); controllersJsonContent = JSON.parse((await readFile(controllersFilePath)).toString()); } catch { controllersJsonContent = { controllers: {}, entrypoints: {}, }; } }, resolveId(this: unknown, id) { if (id === virtualSymfonyControllersModuleId) { return id; } }, load(this: unknown, id) { if (id === virtualSymfonyControllersModuleId) { if (controllersJsonContent) { return createControllersModule(controllersJsonContent, pluginOptions, logger); } else { return `export default [];`; } } }, transform(this: unknown, code, id, options) { if ((options?.ssr && !process.env.VITEST) || id.includes("node_modules") || isVirtualRequest(id)) { return null; } if (isStimulusRequest(id)) { return parseStimulusRequest(code, id, pluginOptions, viteConfig); } if (viteCommand === "serve" && pluginOptions.hmr) { if (id.endsWith("bootstrap.js") || id.endsWith("bootstrap.ts")) { return addBootstrapHmrCode(code, logger); } const isInsideControllerDir = isPathIncluded(join(viteConfig.root, pluginOptions.controllersDir), id); if (!isInsideControllerDir) { return null; } const relativePath = relative(viteConfig.root, id); const identifier = extractStimulusIdentifier(code) ?? getStimulusControllerId(relativePath, pluginOptions.identifierResolutionMethod); if (identifier) { return addControllerHmrCode(code, identifier); } } return null; }, configureServer(devServer) { const { watcher } = devServer; watcher.on("change", (path) => { if (path === controllersFilePath) { logger.info("✨ controllers.json updated, we restart server."); devServer.restart(); } }); }, } satisfies Plugin; }