Files
tuono/packages/tuono-react-vite-plugin/src/plugin.ts
T

84 lines
2.3 KiB
TypeScript
Raw Normal View History

2025-02-16 15:39:25 +01:00
import { normalize } from 'node:path'
2024-07-08 21:39:00 +02:00
import type { Plugin, ViteDevServer } from 'vite'
2024-07-08 21:39:00 +02:00
import { routeGenerator } from './fs-routing/generator'
import { getStylesForComponentId, isCssModulesFile } from './styles'
const CRITICAL_CSS_PATH = '/vite-server/tuono_internal__critical_css'
2024-12-01 10:07:35 +01:00
2024-07-08 21:39:00 +02:00
const ROUTES_DIRECTORY_PATH = './src/routes'
let lock = false
export function TuonoReactPlugin(): Plugin {
2024-07-08 21:39:00 +02:00
const generate = async (): Promise<void> => {
if (lock) return
lock = true
try {
await routeGenerator()
} catch (err) {
console.error(err)
} finally {
lock = false
}
}
const handleFile = async (file: string): Promise<void> => {
const filePath = normalize(file)
if (filePath.startsWith(ROUTES_DIRECTORY_PATH)) {
await generate()
}
}
// This manifest is used to store the CSS modules contents in dev mode
// { [filePath]: cssContent }
const cssModulesManifest: Record<string, string> = {}
2024-07-08 21:39:00 +02:00
return {
name: 'vite-plugin-tuono-react',
2024-07-08 21:39:00 +02:00
configResolved: async (): Promise<void> => {
await generate()
},
watchChange: async (
file: string,
context: { event: string },
): Promise<void> => {
if (['create', 'update', 'delete'].includes(context.event)) {
await handleFile(file)
}
},
transform: (code, id): void => {
if (isCssModulesFile(id)) {
cssModulesManifest[id] = code
}
},
configureServer: (server: ViteDevServer): void => {
// Using middlewares in order to take advantage of async requests out of
// the box
// eslint-disable-next-line @typescript-eslint/no-misused-promises
server.middlewares.use(async (req, res, next): Promise<void> => {
const url = new URL(req.url || '', `http://${req.headers.host || ''}`)
// Give the request handler access to the critical CSS in dev to avoid a
// flash of unstyled content since Vite injects CSS file contents via JS
if (url.pathname === CRITICAL_CSS_PATH) {
const componentId = url.searchParams.get('componentId')
const css = await getStylesForComponentId(
server,
componentId,
cssModulesManifest,
)
res.writeHead(200, { 'Content-Type': 'text/css' })
res.end(css)
return
}
next()
})
},
2024-07-08 21:39:00 +02:00
}
}