astro-client-pragma
v1.0.0
Published
Astro integration that auto-adds the proper client:* directive to every template by reading a "client:*"; pragma at the top of each framework component.
Maintainers
Readme
astro-client-pragma
Annotate once – hydrate everywhere.
Put a string literal such as "client:visible"; at the very top of a React / Vue / Svelte / Solid component file and this integration automatically injects the matching client:visible directive everywhere that component is rendered in your .astro templates.
🌱 Inspiration & Purpose
This plugin borrows the ergonomics of Next .js’s server/client-component split—where a terse top-of-file directive ('use client') opts a file into client-side behavior—and brings that same developer experience to Astro’s island architecture.
The goal is to let teams enjoy performance-first web development without sacrificing DX: you write declarative hydration hints, Astro ships lean HTML by default, and your codebase stays as friendly as any mainstream framework.
It was crafted by a developer who’s obsessed with sustainability, performance, and joyful developer experience. By making it effortless to ship less JavaScript, the plugin helps you build lighter, faster sites that tread a little more softly on the planet. ✨🌍
✨ Features
| 🚀 | What you get |
| -------------------------- | --------------------------------------------------------------- |
| Zero template clutter | No need to sprinkle client:* attributes across pages. |
| Hot-reload aware | Changing the pragma updates dependent .astro files instantly. |
| Alias-aware resolution | Works with Vite/Rollup aliases and monorepos. |
| Directive validation | Warns if you type an unknown directive (e.g. "client:foo"). |
| Extensible | Configure which files are scanned and plug in your own logger. |
| Framework-agnostic | React, Preact, Solid, Vue, Svelte—anything Astro supports. |
📦 Install
npm i -D astro-client-pragma # or pnpm add -D astro-client-pragmaAdd the integration to astro.config.mjs:
import { defineConfig } from "astro/config";
import clientPragma from "astro-client-pragma";
export default defineConfig({
integrations: [clientPragma()],
});🔧 Usage
// src/components/Chart.tsx ← hydrates when visible
"client:visible";
export default function Chart() {
return <div id="chart">…</div>;
}---
// No client:* directive needed here 🎉
import Chart from '~/components/Chart';
---
<Chart />Supported directives: load, visible, idle, media, only.
Custom directives are allowed but will trigger a console warning.
⚙️ Configuration
// astro.config.mjs
import { defineConfig } from "astro/config";
import clientPragma from "astro-client-pragma";
export default defineConfig({
integrations: [
clientPragma({
/* ↓ all options are optional ↓ */
allow: /\.(?:jsx?|tsx?|vue|svelte)$/i, // 1️⃣ which files to scan
log: (msg) => {
// 2️⃣ custom logger
if (process.env.DEBUG) console.log(msg);
},
}),
],
});ClientPragmaOptions interface
| Field | Type | Default | Purpose | | |
| ----------- | ----------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------- |
| allow | RegExp | `/.(?:m?[jt]sx? | svelte | vue)$/i` | Limits scanning to files whose names match the regex. Adjust if you use other extensions. |
| log | (msg: string) => void | console.log | Receives informational messages (detections, removals, warnings). Supply () => {} to silence or route to your own logger. | | |
If you pass no options — clientPragma() — the defaults above are used.
🛠 How it works
- Scanner plugin walks your
src/tree (and every file change during dev) looking for the pragma at the top of framework-component files. - Patcher plugin intercepts each
.astrofile before Astro’s compiler and injects the recordedclient:*attribute onto matching component tags. - When a pragma changes, the scanner invalidates all dependent
.astromodules so they’re re-compiled with the new directive—keeping HMR perfectly in sync.
This is done entirely via Vite’s plugin API—no Babel, no heavy AST parsing—so overhead is minimal.
🧩 Minimum requirements
- Node ≥ 18 (matches Astro 5 and Vite 5 support matrix)
❓ Why bother — isn’t this in Astro already?
Astro’s core team knows the client:* ergonomics still have room for polish.
Several roadmap threads explore ideas that would eventually let you skip hand-written directives:
- withastro/roadmap #431 – “Making it possible to set client directives dynamically”
Community members propose everything from a prop-based API (<Comp client={...} />) to pragma strings. - withastro/roadmap #67 – “Require client directive for all framework components”
A discussion on compiler-level enforcement so no one forgets a directive—but it doesn’t solve DX friction. - withastro/roadmap #907 – “Server islands / use:server”
Mentions a potential siblinguse:clientpragma, echoing exactly the top-of-file approach used here.
These ideas are promising but not yet part of Astro’s runtime.
Until an official solution lands, astro-client-pragma fills the gap today:
- ✅ Instant productivity win – Adopt the Next.js-style pragma without waiting on new compiler features.
- ✅ Zero migration cost – Works on an opt-in, file-by-file basis; existing code keeps its
client:*attributes. - ✅ Feedback loop – Real-world usage can inform Astro’s future design; open an issue to share your findings!
By smoothing out the hydration workflow right now, the plugin lets you stay focused on shipping fast, eco-friendly sites—no boilerplate required.
🤖 About the build
This plugin was prototyped and refined with the help of ChatGPT to save countless hours of boilerplate. PRs that fix bugs, improve docs, or even just correct a typo are very appreciated!
📝 License
MIT © 2025 Mohamed Radi
Made with ❤️ by ChatGPT.
